make `--upstream_sync` also sync the gap analysis graph progressively
#534 opened on Jul 21, 2024
Repository metrics
- Stars
- (167 stars)
- PR merge metrics
- (PR metrics pending)
Description
Status
Maintainer-approved design — opportunistic gap-analysis (GA) fetch from production on access, replacing the prior idea of bulk-downloading the full ~9 GB GA graph via --upstream_sync. Implementation spec will land in a follow-up PR; this issue tracks the feature and acceptance criteria.
Supersedes bulk GA download as the primary local-dev path. Prateek's JIT Neo4j compute path remains an advanced fallback documented separately (not the default UI/REST path).
Problem
The gap-analysis cache is very large (~9 GB). Downloading it wholesale during --upstream_sync is unreliable and unnecessary for most local development: contributors typically need only the GA pairs they actually view.
Production (opencre.org) already serves precomputed GA rows from Postgres (cache-only; cache miss → 404). Local instances should reuse that upstream cache opportunistically instead of requiring a full bulk sync.
Proposed solution
When a user requests a GA pair (via UI or local REST GA API — same backend code path):
- If the pair exists in the local GA store, serve it.
- If not, and auto-fetch is enabled, fetch the full material row from prod (read-only HTTP client), upsert into the local GA store, then serve it.
- While a fetch is in flight for a pair, return a "download in progress" state; concurrent requests for the same pair share a single in-flight fetch (frontend polls/waits).
- On prod 404 (pair not in prod cache): show documented instructions for local backfill (links to opencre.org and/or GitHub docs — to be written as part of this work). Do not compute GA in the request path from the UI.
- On prod unreachable or fetch failure: fall through to local cached row if present; otherwise show Try again (not local compute in UI).
GA auto-fetch is independent of --upstream_sync CRE graph sync. Locally cached pairs are preserved and not overwritten by a failed fetch.
Design decisions
- Trigger: Both UI and local REST GA API use the same backend code path.
- Prod URL: Configurable env var (default
https://opencre.org). Prod down / miss behavior:- Prod unreachable (timeout, network error, exhausted retries): serve local cached row if it exists.
- Not in local cache: show link to compute/backfill instructions (no UI compute).
- Do not silently compute on prod-down in the UI/request path. Local compute remains CI/docs-only (advanced JIT Neo4j fallback), not a hidden fallback when prod is down.
- Persist: Fetch the full material row from prod; upsert into the local GA store (
gap_analysis_results/ equivalent). - Concurrency: Single fetch per pair; backend returns "download in progress" while in-flight; frontend polls/waits.
- 404 miss: Exact UX copy plus links to local backfill documentation (opencre.org and/or GitHub). Block local compute from UI for now.
- Instructions: Link to docs to be written as part of this work — do not prescribe specific Makefile targets in this ticket.
- Soft message: When both constituent standards exist locally and prod confirms they are valid GA participants, but the specific pair is missing on prod, show a soft CTA to file a ticket after the backfill instructions. Detection logic (all must hold):
- Both standards exist locally in the CRE graph (nodes present for the pair's two standard names).
- Both are valid GA participants — either:
- the standards list endpoint includes both standards as GA-eligible, or
- individual GET per standard succeeds against prod (or local graph metadata when prod standards list is unavailable).
- GA request for that specific pair returns 404 or an error from prod (after retries exhausted).
- When all three conditions hold, append the soft "file a ticket" CTA; otherwise show only the standard backfill instructions.
- Refresh: Backend owns fetch lifecycle; frontend refresh sees the same state. Log when a local instance pulls a pair from prod.
- Env disable:
CRE_GA_NO_UPSTREAM=1(or similar name) documented in.env.example— disables auto-fetch. On fetch failure: Try again button (not local calc in UI). - Independence: GA auto-fetch is independent of
--upstream_syncCRE graph sync. Locally cached pairs are preserved (not overwritten by failed fetch). - Security: No auth on prod fetch; read-only HTTP client to prod GA endpoints; no writes to prod. State explicitly in implementation spec.
- Configurable prod fetch (env vars): GA upstream HTTP client uses
CRE_GA_UPSTREAM_*env vars, scoped parallel to the existingCRE_UPSTREAM_*pattern from upstream CRE graph sync (#951):CRE_GA_UPSTREAM_TIMEOUT_SECONDS— default 30 (Heroku-typical; mirrorsCRE_UPSTREAM_TIMEOUT_SECONDS)CRE_GA_UPSTREAM_MAX_ATTEMPTS— default 4 (mirrorsCRE_UPSTREAM_MAX_ATTEMPTS)CRE_GA_UPSTREAM_RETRY_BACKOFF_SECONDS— default 2 (mirrorsCRE_UPSTREAM_RETRY_BACKOFF_SECONDS; optional but recommended for parity)- Exhaust retries before surfacing Try again in UI.
Cache policy
- V1: Once cached locally, always serve from local cache — no automatic re-fetch from prod on subsequent requests.
- V2 (future): Add TTL-based re-fetch from prod (e.g. env-controlled staleness window). Document as Version 2; out of scope for v1 implementation.
Open items (TBD — do not block implementation)
| Item | Notes |
|---|---|
| V2 TTL / force-refresh | Deferred to Version 2 (see Cache policy) |
Out of scope
- Bulk download of the full GA graph via
--upstream_syncas the primary path (superseded by this design). - Computing GA on production (prod remains cache-only).
- Computing GA in the UI/request path on cache miss (blocked; backfill via docs/CLI only).
- Prescribing exact Makefile targets in this ticket (docs PR will cover operational steps).
- JIT Neo4j compute as the default path (advanced fallback in docs only).
- V2: TTL-based automatic re-fetch from prod for locally cached pairs (see Cache policy).
Acceptance criteria
- UI and local REST GA API share one backend fetch/cache code path.
- Configurable prod base URL (default opencre.org); read-only prod HTTP client (no auth, no writes).
- On cache miss with auto-fetch enabled: fetch full material row from prod and upsert locally.
- V1 cache policy: once a pair is cached locally, subsequent requests serve from local cache without automatic prod re-fetch.
- On prod unreachable (after
CRE_GA_UPSTREAM_MAX_ATTEMPTSretries): serve local cached row if present; otherwise Try again with compute/backfill instructions link (no UI-triggered compute). - On prod 404 for a pair not in local cache: documented backfill instructions (opencre.org + GitHub links); no local compute from UI.
- Single in-flight fetch per pair; concurrent requests get "download in progress"; frontend polls/waits.
- Soft CTA to file a ticket when soft-message detection (#7) conditions are met (both standards local + valid GA participants + prod pair 404/error).
-
CRE_GA_NO_UPSTREAM=1(or agreed name) disables auto-fetch; documented in.env.example. -
CRE_GA_UPSTREAM_TIMEOUT_SECONDSdefault 30;CRE_GA_UPSTREAM_MAX_ATTEMPTSdefault 4; documented in.env.example(and implementation spec). - Failed fetch does not overwrite existing local cached row.
- Logging when local instance pulls a pair from prod.
- Tests: mocked prod HTTP, cache upsert, in-progress lock, 404 UX copy, env disable flag, read-only prod client behavior, logging, env defaults (
CRE_GA_UPSTREAM_TIMEOUT_SECONDS,CRE_GA_UPSTREAM_MAX_ATTEMPTS), soft-message detection logic (positive/negative cases), V1 no re-fetch (cached pair served without second prod call).
Dependencies
- Production GA REST API serving precomputed material rows (existing on opencre.org).
- Local GA store schema (
gap_analysis_results/ equivalent) supporting upsert of material rows. - Documentation PR: local backfill instructions, env vars, advanced JIT Neo4j fallback (not default).
- Detailed implementation spec PR (referenced from this issue).
Note
A detailed implementation spec will land in a follow-up PR linked from this issue. Volunteers should read this body (and the spec PR when available) before claiming the issue.