feat: advisory cache default (CM-1328)#4391
Conversation
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
PR SummaryMedium Risk Overview Advisory cache: Before creating a row or starting New routes: Batch submit behavior: Each job is processed independently; DAL: Bulk read helpers for analyses, verdicts, and excluded-dependent counts support efficient batch polling. Reviewed by Cursor Bugbot for commit bfd8a2b. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
Adds batch blast-radius submission/polling and reuses recent completed analyses to reduce duplicate Temporal workflows.
Changes:
- Adds batch submit and polling APIs with validation and partial-failure handling.
- Adds advisory-level cache lookup with force bypass.
- Updates routing, rate limits, tests, and OpenAPI documentation.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
services/libs/data-access-layer/src/packages/blastRadius.ts |
Adds cache and batch queries. |
backend/src/api/public/v1/packages/submitBlastRadiusJobBatch.ts |
Implements batch submission. |
backend/src/api/public/v1/packages/submitBlastRadiusJobBatch.test.ts |
Tests batch submission behavior. |
backend/src/api/public/v1/packages/submitBlastRadiusJob.ts |
Adds cache reuse to single submissions. |
backend/src/api/public/v1/packages/submitBlastRadiusJob.test.ts |
Tests single-job caching. |
backend/src/api/public/v1/packages/getBlastRadiusJobBatch.ts |
Implements batch polling. |
backend/src/api/public/v1/packages/getBlastRadiusJobBatch.test.ts |
Tests batch polling. |
backend/src/api/public/v1/packages/blastRadiusBatch.ts |
Defines batch schemas and pagination. |
backend/src/api/public/v1/packages/blastRadiusBatch.test.ts |
Tests schemas and pagination. |
backend/src/api/public/v1/packages/blastRadius.ts |
Defines cache configuration and helper. |
backend/src/api/public/v1/akrites-external/openapi.yaml |
Documents caching and batch APIs. |
backend/src/api/public/v1/akrites-external/index.ts |
Registers routes and adjusts rate limiting. |
Comments suppressed due to low confidence (2)
backend/src/api/public/v1/akrites-external/openapi.yaml:460
- Cache-hit entries do not start workflows, so this cost explanation is inaccurate. Qualify the statement as applying to cache misses.
Capped much lower than the 100-item read batches — each entry
starts its own Temporal workflow, so the batch multiplies
workflow starts (and reachability-analysis cost) per request.
backend/src/api/public/v1/akrites-external/openapi.yaml:1137
- The batch shares the single-submit cache semantics, so only cache misses start workflows. The current absolute wording contradicts the implementation.
single package. Each entry starts its own Temporal workflow, so the
batch is capped at 20 jobs (10 recommended as the default batch
size), much lower than the 100-item read batches, and stays behind
the same strict rate limiter as the single-job route.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| candidates_considered, started_at, completed_at | ||
| FROM blast_radius_analyses | ||
| WHERE advisory_osv_id = $(advisoryOsvId) | ||
| AND package_name IS NOT DISTINCT FROM $(packageName) |
| WHERE advisory_osv_id = $(advisoryOsvId) | ||
| AND package_name IS NOT DISTINCT FROM $(packageName) | ||
| AND ecosystem = $(ecosystem) | ||
| AND status = 'done' | ||
| AND completed_at >= NOW() - make_interval(days => $(maxAgeDays)) |
| status and, once done, results. Bulk submit (jobs:batch) is capped at | ||
| 20 jobs per request (10 recommended as the default batch size) — each | ||
| entry starts its own workflow — and stays behind the same strict rate | ||
| limiter as the single-job route; bulk poll | ||
| (jobs:batch/poll) is read-only and capped at 100 like the other batch | ||
| endpoints. Same interim scope note as Advisories applies (read:packages, | ||
| pending a dedicated read:advisories scope). | ||
| limiter as the single-job route, defaulting to 50 requests/hour | ||
| (configurable via AKRITES_BLAST_RADIUS_RATE_LIMIT_MAX / _WINDOW_MS); |
Summary
Adds bulk/batch endpoints for blast-radius analysis (
submitBlastRadiusJobBatch,getBlastRadiusJobBatch) alongside the existing single-job endpoints, and adds an advisory-level cache so a submit can reuse a recent'done'analysis for the same(advisoryId, package, ecosystem)instead of always starting a new Temporal workflow. Submitting many advisories at once (e.g. a batch of 20) no longer means 20 unconditional workflow starts — repeated/overlapping submissions within a configurable cache window (BLAST_RADIUS_CACHE_MAX_AGE_DAYS, default 1 day) short-circuit to the cached result.Changes
submitBlastRadiusJobBatch/getBlastRadiusJobBatch: new bulk endpoints mirroring the single-job ones. Batch size is capped lower than the other read-only batch endpoints (packages/advisories/contacts) and stays behind the strictblastRadiusRateLimiter, since each job can trigger a real Temporal workflow start, not just a read.workflow.start(or cache-lookup) failure insidesubmitBlastRadiusJobBatchreturns that entry asstatus: 'failed'without failing the rest of the batch — the cache lookup was moved inside the per-jobtry/catch(it was originally outside, which would have rejected the wholePromise.alland 500'd the entire batch on a transient DB error during the cache check).getRecentDoneAnalysis(new DAL function inservices/libs/data-access-layer/src/packages/blastRadius.ts): finds the most recent'done'analysis for the same(advisoryOsvId, packageName, ecosystem)within the cache window. UsesIS NOT DISTINCT FROMforpackageNamesince it's nullable (advisory-wide analyses have no package) and plain=never matchesNULL.getCachedJobEntry(new shared helper inblastRadius.ts): extracted so the cache-check-and-build-entry logic isn't duplicated betweensubmitBlastRadiusJobandsubmitBlastRadiusJobBatch's per-job handler — both now call the same function instead of maintaining two copies of the same lookup.force: trueon a request bypasses the cache entirely, same as before for the single-job endpoint.blastRadius.ts's row types to@crowd/types(per ADR-0006) or adding DAL integration tests/factories (per ADR-0007) in this PR — scoped decision to keep this change focused on the batch API + cache behavior.Type of change
JIRA ticket
CM-1328