Service Bus completion events carry result-file download URLs¶
Date: 2026-06-17
Area: Service Bus integration (api/tasks/servicebus), examples (example/servicebus)
Motivation¶
An external consumer of the optional elastic-blast-completions topic could see
that a job succeeded but had to enumerate the result files itself (parse
result_ref.api, call the job detail, read result.files, then build each file
URL) before it could download anything. The request was for the completion
message to carry a ready-to-use download_url per result file so a consumer can
fetch results directly.
User-facing change¶
A succeeded blast.transition event now includes a result_files array:
"result_files": [
{
"file_id": "merged_results.out.gz",
"name": "merged_results.out.gz",
"format": "blast_tabular",
"size": 12345,
"download_url": "https://<dashboard-host>/api/v1/elastic-blast/jobs/{job_id}/files/merged_results.out.gz"
}
]
download_url points at the dashboard's authenticated file-streaming gateway
(GET /api/v1/elastic-blast/jobs/{job_id}/files/{file_id}), which the api
sidecar proxies to the sibling OpenAPI plane. A consumer downloads by calling it
with a bearer token. It is never a Storage SAS URL or a direct blob URL
(charter §9). When the dashboard public base cannot be resolved, the file
metadata is still emitted but download_url is omitted, so a subscriber can fall
back to result_ref.
The field is present only on succeeded events when the optional completion
topic is configured; queued / running / failed events are unchanged. The
addition does not alter the event_id dedup digest.
API / IaC diff summary¶
api/tasks/servicebus/tasks.py- new
_result_files_for_event(job, openapi_job_id)— builds the per-file metadata +download_urlfrom the sibling job detail (_external_result_files) and the resolved dashboard public base (resolve_control_plane_url). Capped at_MAX_RESULT_FILES(25). _transition_event(...)gains an optionalresult_filesparameter, emitted only when supplied._publish_one_bridge(...)attachesresult_fileson thesucceededtransition (best-effort: a build failure logs and emits an empty list).- No IaC change. No new env var. Uses the existing
CONTAINER_APP_NAME+CONTAINER_APP_ENV_DNS_SUFFIX(orDASHBOARD_PUBLIC_URL/ operator setting) thatresolve_control_plane_urlalready reads. example/servicebus/consume.py—--source completions --downloadnow readsresult_files, acquires a bearer token (ELB_BEARER_TOKENoraz account get-access-token --resource $ELB_API_CLIENT_ID), and downloads eachdownload_urlto--download-dir.
Validation¶
uv run pytest -q api/tests/test_servicebus_tasks.py— 35 passed (includes the newtest_result_files_for_event_*,test_transition_event_includes_result_files_*, andtest_publish_transitions_succeeded_attaches_download_urls).uv run ruff check api/tasks/servicebus/tasks.py api/tests/test_servicebus_tasks.py example/servicebus— clean.example/servicebus/consume.py --self-test— green (assertsplan_downloadsturns the event'sresult_filesinto download targets and that the URL is the dashboard gateway, not a SAS URL).- Live end-to-end against
ca-elb-dashboard+elb-cluster-01: send a real Service Bus request → drain → OpenAPI submit → BLAST run → succeeded completion event carryingdownload_url→ consumer downloads the result file.