Fix run_recipe endpoint to use content-addressable run_id
The run_recipe endpoint was still using uuid.uuid4() instead of compute_run_id(). Now it: - Computes deterministic run_id from inputs + recipe - Checks L1 cache before running - Checks L2 and pulls from IPFS if needed - Only runs Celery if output not found Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
65
server.py
65
server.py
@@ -1534,8 +1534,6 @@ async def run_recipe(recipe_id: str, request: RecipeRunRequest, ctx: UserContext
|
||||
# Build DAG from recipe
|
||||
dag = build_dag_from_recipe(yaml_config, request.inputs, recipe)
|
||||
|
||||
# Create run
|
||||
run_id = str(uuid.uuid4())
|
||||
actor_id = ctx.actor_id
|
||||
|
||||
# Collect all input hashes
|
||||
@@ -1544,12 +1542,71 @@ async def run_recipe(recipe_id: str, request: RecipeRunRequest, ctx: UserContext
|
||||
if fixed.content_hash:
|
||||
all_inputs.append(fixed.content_hash)
|
||||
|
||||
# Compute content-addressable run_id
|
||||
run_id = compute_run_id(all_inputs, f"recipe:{recipe.name}")
|
||||
output_name = f"{recipe.name}-{run_id[:8]}"
|
||||
|
||||
# Check L1 cache first
|
||||
cached_run = await database.get_run_cache(run_id)
|
||||
if cached_run:
|
||||
output_hash = cached_run["output_hash"]
|
||||
if cache_manager.has_content(output_hash):
|
||||
logger.info(f"run_recipe: Cache hit for run_id={run_id[:16]}...")
|
||||
return RunStatus(
|
||||
run_id=run_id,
|
||||
status="completed",
|
||||
recipe=f"recipe:{recipe.name}",
|
||||
inputs=all_inputs,
|
||||
output_name=output_name,
|
||||
created_at=cached_run.get("created_at", datetime.now(timezone.utc).isoformat()),
|
||||
completed_at=cached_run.get("created_at", datetime.now(timezone.utc).isoformat()),
|
||||
output_hash=output_hash,
|
||||
username=actor_id,
|
||||
provenance_cid=cached_run.get("provenance_cid"),
|
||||
)
|
||||
|
||||
# Check L2 if not in L1
|
||||
l2_server = ctx.l2_server
|
||||
try:
|
||||
l2_resp = http_requests.get(f"{l2_server}/assets/by-run-id/{run_id}", timeout=10)
|
||||
if l2_resp.status_code == 200:
|
||||
l2_data = l2_resp.json()
|
||||
output_hash = l2_data.get("output_hash")
|
||||
ipfs_cid = l2_data.get("ipfs_cid")
|
||||
if output_hash and ipfs_cid:
|
||||
logger.info(f"run_recipe: Found on L2, pulling from IPFS")
|
||||
import ipfs_client
|
||||
legacy_dir = CACHE_DIR / "legacy"
|
||||
legacy_dir.mkdir(parents=True, exist_ok=True)
|
||||
recovery_path = legacy_dir / output_hash
|
||||
if ipfs_client.get_file(ipfs_cid, str(recovery_path)):
|
||||
cache_manager._set_content_index(output_hash, output_hash)
|
||||
cache_manager._set_ipfs_index(output_hash, ipfs_cid)
|
||||
await database.save_run_cache(
|
||||
run_id=run_id, output_hash=output_hash,
|
||||
recipe=f"recipe:{recipe.name}", inputs=all_inputs,
|
||||
ipfs_cid=ipfs_cid, provenance_cid=l2_data.get("provenance_cid"),
|
||||
actor_id=actor_id,
|
||||
)
|
||||
return RunStatus(
|
||||
run_id=run_id, status="completed",
|
||||
recipe=f"recipe:{recipe.name}", inputs=all_inputs,
|
||||
output_name=output_name,
|
||||
created_at=datetime.now(timezone.utc).isoformat(),
|
||||
completed_at=datetime.now(timezone.utc).isoformat(),
|
||||
output_hash=output_hash, username=actor_id,
|
||||
provenance_cid=l2_data.get("provenance_cid"),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"run_recipe: L2 lookup failed: {e}")
|
||||
|
||||
# Not cached - run Celery
|
||||
run = RunStatus(
|
||||
run_id=run_id,
|
||||
status="pending",
|
||||
recipe=f"recipe:{recipe.name}",
|
||||
inputs=all_inputs,
|
||||
output_name=f"{recipe.name}-{run_id[:8]}",
|
||||
output_name=output_name,
|
||||
created_at=datetime.now(timezone.utc).isoformat(),
|
||||
username=actor_id
|
||||
)
|
||||
@@ -3652,6 +3709,7 @@ def render_page(title: str, content: str, actor_id: Optional[str] = None, active
|
||||
<a href="/runs" class="pb-3 px-1 font-medium transition-colors {runs_active}">Runs</a>
|
||||
<a href="/recipes" class="pb-3 px-1 font-medium transition-colors {recipes_active}">Recipes</a>
|
||||
<a href="/media" class="pb-3 px-1 font-medium transition-colors {media_active}">Media</a>
|
||||
<a href="/download/client" class="pb-3 px-1 font-medium transition-colors text-gray-400 hover:text-white ml-auto" title="Download CLI client">Download Client</a>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
@@ -3720,6 +3778,7 @@ def render_ui_html(actor_id: Optional[str] = None, tab: str = "runs") -> str:
|
||||
<a href="/runs" class="pb-3 px-1 font-medium transition-colors {runs_active}">Runs</a>
|
||||
<a href="/recipes" class="pb-3 px-1 font-medium transition-colors {recipes_active}">Recipes</a>
|
||||
<a href="/media" class="pb-3 px-1 font-medium transition-colors {media_active}">Media</a>
|
||||
<a href="/download/client" class="pb-3 px-1 font-medium transition-colors text-gray-400 hover:text-white ml-auto" title="Download CLI client">Download Client</a>
|
||||
</nav>
|
||||
|
||||
<div id="content" hx-get="{content_url}" hx-trigger="load" hx-swap="innerHTML">
|
||||
|
||||
Reference in New Issue
Block a user