Recent searches now discovers directly-submitted /v1/jobs jobs across clusters¶
Motivation¶
A BLAST job submitted directly through the elb-openapi sibling service
(POST /v1/jobs) did not appear on the Recent searches page. The history
view lists jobs subscription-scoped only (no cluster_name) so it can show
jobs across every cluster, but the external-job discovery in
blast_jobs_list called _openapi_client_kwargs_from_cluster(subscription_id,
"", ""), which requires the full (subscription, resource_group, cluster)
triple and therefore resolved to {}. With empty kwargs the OpenAPI /v1/jobs
listing could only be reached through the fragile ELB_OPENAPI_BASE_URL env /
runtime-cache fallback — never reliably populated (public-TLS deployments never
call save_openapi_base_url, a fresh worker/api process has an empty runtime
cache, and a single global cache key only remembers one cluster). So
directly-submitted jobs stayed invisible until a per-cluster card view happened
to discover and sync them.
User-facing change¶
Opening Recent searches now lists jobs submitted directly via the OpenAPI
/v1/jobs endpoint, on any ElasticBLAST cluster in the subscription, without
having to first visit a per-cluster card. A single Stopped/unreachable cluster
no longer hides jobs that ran on the other reachable clusters; the list is only
flagged external_degraded when every discovered cluster is unreachable.
API / IaC diff summary¶
api/services/blast/external_jobs.py- New
_discover_subscription_clusters(subscription_id)— one cached (60 s TTL) ARMmanagedClusters.listround trip returning(resource_group, cluster_name)pairs for ElasticBLAST clusters. Never raises; discovery failures return[]so the caller degrades to the env / runtime-cache fallback. Stopped clusters are excluded (via_cluster_power_state_allows_openapi) so the ~14 s-polled Recent searches endpoint never burns a 10 sk8s_get_service_iptimeout per Stopped cluster — a Stopped cluster cannot serve/v1/jobsanyway, and anything it ran while Running is already a local Table row. _reset_external_jobs_cache()now also clears the new cluster cache.api/routes/blast/jobs.py- New
_resolve_external_list_targets(...)resolves a list of OpenAPI endpoints to query: a single target for acluster_name-scoped request (unchanged), one target per discovered cluster for a subscription-only request, or the legacy{}env / runtime-cache fallback when nothing resolves. blast_jobs_listnow loops over the resolved targets, de-duplicates jobs byjob_id, applies the per-target scope to each external row, syncs the union into Table Storage, and surfacesexternal_degradedonly when no target was reachable (partial success is not flagged).- No IaC change.
Validation evidence¶
uv run pytest -q api/tests→ 3199 passed, 3 skipped.- New tests in
api/tests/test_external_blast_api.py: test_canonical_jobs_list_subscription_scope_discovers_clusterstest_canonical_jobs_list_subscription_scope_partial_cluster_failuretest_canonical_jobs_list_subscription_scope_all_clusters_downtest_discover_subscription_clusters_skips_stoppeduv run ruff check api/routes/blast/jobs.py api/services/blast/external_jobs.py→ clean.