feat: L1 server URL sent with publish request (many-to-many support)
- Add l1_server field to RecordRunRequest - L2 fetches run data from the specified L1 URL instead of hardcoded config - Store l1_server in provenance and metadata - Remove ARTDAG_L1 config requirement from L2 - Update docker-stack.yml comments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,7 @@ ARTDAG_DOMAIN=artdag.rose-ash.com
|
|||||||
# Default username (for actor endpoints)
|
# Default username (for actor endpoints)
|
||||||
ARTDAG_USER=giles
|
ARTDAG_USER=giles
|
||||||
|
|
||||||
# L1 server URL (for fetching run data)
|
|
||||||
ARTDAG_L1=https://l1.artdag.rose-ash.com
|
|
||||||
|
|
||||||
# JWT secret for token signing (generate with: openssl rand -hex 32)
|
# JWT secret for token signing (generate with: openssl rand -hex 32)
|
||||||
JWT_SECRET=your-secret-here-generate-with-openssl-rand-hex-32
|
JWT_SECRET=your-secret-here-generate-with-openssl-rand-hex-32
|
||||||
|
|
||||||
|
# Note: ARTDAG_L1 is no longer needed - L1 server URL is sent with each request
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
- REDIS_URL=redis://redis:6379/5
|
- REDIS_URL=redis://redis:6379/5
|
||||||
- CACHE_DIR=/data/cache
|
- CACHE_DIR=/data/cache
|
||||||
# L2_SERVER and L2_DOMAIN from .env file
|
# L1_PUBLIC_URL, L2_SERVER, L2_DOMAIN from .env file
|
||||||
volumes:
|
volumes:
|
||||||
- l1_cache:/data/cache
|
- l1_cache:/data/cache
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -69,7 +69,7 @@ services:
|
|||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
- ARTDAG_DATA=/data/l2
|
- ARTDAG_DATA=/data/l2
|
||||||
# ARTDAG_DOMAIN, ARTDAG_USER, ARTDAG_L1, JWT_SECRET from .env file
|
# ARTDAG_DOMAIN, ARTDAG_USER, JWT_SECRET from .env file
|
||||||
volumes:
|
volumes:
|
||||||
- l2_data:/data/l2
|
- l2_data:/data/l2
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
11
server.py
11
server.py
@@ -93,6 +93,7 @@ class RecordRunRequest(BaseModel):
|
|||||||
"""Request to record an L1 run."""
|
"""Request to record an L1 run."""
|
||||||
run_id: str
|
run_id: str
|
||||||
output_name: str
|
output_name: str
|
||||||
|
l1_server: str # URL of the L1 server that has this run
|
||||||
|
|
||||||
|
|
||||||
class PublishCacheRequest(BaseModel):
|
class PublishCacheRequest(BaseModel):
|
||||||
@@ -1034,13 +1035,14 @@ async def register_asset(req: RegisterRequest, user: User = Depends(get_required
|
|||||||
@app.post("/registry/record-run")
|
@app.post("/registry/record-run")
|
||||||
async def record_run(req: RecordRunRequest, user: User = Depends(get_required_user)):
|
async def record_run(req: RecordRunRequest, user: User = Depends(get_required_user)):
|
||||||
"""Record an L1 run and register the output. Requires authentication."""
|
"""Record an L1 run and register the output. Requires authentication."""
|
||||||
# Fetch run from L1 server
|
# Fetch run from the specified L1 server
|
||||||
|
l1_url = req.l1_server.rstrip('/')
|
||||||
try:
|
try:
|
||||||
resp = requests.get(f"{L1_SERVER}/runs/{req.run_id}")
|
resp = requests.get(f"{l1_url}/runs/{req.run_id}")
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
run = resp.json()
|
run = resp.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(400, f"Failed to fetch run from L1: {e}")
|
raise HTTPException(400, f"Failed to fetch run from L1 ({l1_url}): {e}")
|
||||||
|
|
||||||
if run.get("status") != "completed":
|
if run.get("status") != "completed":
|
||||||
raise HTTPException(400, f"Run not completed: {run.get('status')}")
|
raise HTTPException(400, f"Run not completed: {run.get('status')}")
|
||||||
@@ -1053,6 +1055,7 @@ async def record_run(req: RecordRunRequest, user: User = Depends(get_required_us
|
|||||||
provenance = {
|
provenance = {
|
||||||
"inputs": [{"content_hash": h} for h in run.get("inputs", [])],
|
"inputs": [{"content_hash": h} for h in run.get("inputs", [])],
|
||||||
"recipe": run.get("recipe"),
|
"recipe": run.get("recipe"),
|
||||||
|
"l1_server": l1_url,
|
||||||
"l1_run_id": req.run_id,
|
"l1_run_id": req.run_id,
|
||||||
"rendered_at": run.get("completed_at")
|
"rendered_at": run.get("completed_at")
|
||||||
}
|
}
|
||||||
@@ -1063,7 +1066,7 @@ async def record_run(req: RecordRunRequest, user: User = Depends(get_required_us
|
|||||||
content_hash=output_hash,
|
content_hash=output_hash,
|
||||||
asset_type="video", # Could be smarter about this
|
asset_type="video", # Could be smarter about this
|
||||||
tags=["rendered", "l1"],
|
tags=["rendered", "l1"],
|
||||||
metadata={"l1_run_id": req.run_id},
|
metadata={"l1_server": l1_url, "l1_run_id": req.run_id},
|
||||||
provenance=provenance
|
provenance=provenance
|
||||||
), user.username)
|
), user.username)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user