Skip to content

Commit c0b04f1

Browse files
docs(cems): evidence-based refresh/polling strategy to minimise HTTP calls
Probed the API to design incremental polling instead of re-fetching every activation detail: - One list call (?limit=300) = full corpus (224 items, ~72 KB) carrying the change signals lastUpdate/closed/n_products/n_aois. - No HTTP caching (no ETag/Last-Modified) and server-side "updated since" filters are ignored, so change detection is application-side via a per-code watermark. - ?closed=false works and returns only live activations (currently 3); closed activations are immutable. Strategy: backfill once; steady-state poll ?closed=false and fetch detail only when (lastUpdate, n_products, n_aois) advance; final fetch on close; slow full-list reconcile for new/closed. Turns ~224 detail fetches/cycle into one 72 KB list call plus a handful of details. RSS (portal, redirected) is the WP2 push alternative. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4a1f343 commit c0b04f1

1 file changed

Lines changed: 35 additions & 5 deletions

File tree

docs/model/sources/CEMS/README.md

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,41 @@ class **per iteration**, chained by `rel: prev`. The aggregated activation `stat
258258
snapshot with **no history** — use it only as a current-total cross-check or when per-product
259259
stats are absent (never in addition, to avoid double counting).
260260

261-
**The join & refresh:** every item across both axes shares `monty:corr_id` — query by it and
262-
order by `datetime` / `monitoring_number` to reconstruct the timeline. Detect change by
263-
polling the **list endpoint's `lastUpdate`** per activation (the detail payload omits it) and
264-
refetching detail when it advances; **`closed=true` ⇒ final** (stop polling), `closed=false`
265-
live. (WP2 RSS feeds provide the same trigger event-driven.)
261+
**The join:** every item across both axes shares `monty:corr_id` — query by it and order by
262+
`datetime` / `monitoring_number` to reconstruct the timeline.
263+
264+
### Refresh & polling strategy (minimise HTTP calls)
265+
266+
The **detail** endpoint is expensive (EMSR847 ≈ 413 KB); the **list** endpoint is one cheap
267+
call that already exposes the change signals. Probed API behaviour:
268+
269+
- **One list call returns the full corpus**: `?limit=300` → all 224 activations, ~72 KB, ~0.7 s,
270+
each item carrying `lastUpdate`, `closed`, `n_products`, `n_aois`.
271+
- **No HTTP caching** — no `ETag` / `Last-Modified` on either endpoint, so conditional
272+
`304` requests are unavailable; change detection must be **application-side**.
273+
- **No server-side "updated since" filter**`lastUpdate__gte` / `updated_after` /
274+
`activationTime` are **ignored** (still return all 224).
275+
- **But `?closed=false` works** — returns only the live activations (currently **3**).
276+
- `ordering` is ignored; default order is **code-descending** (newest activation first).
277+
278+
Given that, only **open** activations change, and each closed activation is immutable once
279+
closed. The minimal-calls loop:
280+
281+
1. **Backfill once**: page the full list (1 call) → fetch detail for each activation (224
282+
one-time). Persist a watermark per `code`: `(lastUpdate, n_products, n_aois, closed)`.
283+
2. **Steady state — cheap poll**: `GET ?closed=false` (1 tiny call). For each open activation,
284+
fetch **detail only if** `lastUpdate` advanced **or** `n_products` / `n_aois` grew vs the
285+
watermark. Typically 0–few detail calls per cycle instead of 224.
286+
3. **Close-out**: when an activation leaves the `closed=false` set (or flips `closed=true`),
287+
fetch its detail **one final time**, then never again.
288+
4. **Reconcile**: run the full `?limit=300` list on a slow cadence (e.g. daily) to catch brand-new
289+
codes and any activation that opened *and* closed between polls; diff against watermarks.
290+
291+
This turns a naive per-cycle cost of **224 detail fetches (~tens of MB)** into **one ~72 KB list
292+
call + a handful of detail fetches**. The composite `(lastUpdate, n_products, n_aois)` is the
293+
dirty check (there is no per-product timestamp in the list). A legacy RSS feed exists on the
294+
portal (`emergency.copernicus.eu/mapping/…/feed`, redirected) and is the intended **push**
295+
trigger under WP2 — it can replace the frequent `?closed=false` poll entirely.
266296

267297
## Cross-source linkage
268298

0 commit comments

Comments
 (0)