docs: define analytics job execution limits

This commit is contained in:
2026-08-20 16:34:10 +03:30
parent be3cb9f36b
commit ae551c02c1
4 changed files with 17 additions and 14 deletions

View File

@@ -148,13 +148,13 @@ This contract applies only to the one-time challenge-data bootstrap and explicit
- ZarinPal is the authoritative writer of future production payment sessions/attempts in the normalized PostgreSQL schema.
- This project owns the normalized schema contract, migrations, read models, and analytics; it does not recreate ZarinPal's payment-write workflow.
- Payment facts are append-only in the MVP. Existing session/attempt updates and hard deletion are out of scope; a future mutation requirement needs a new invalidation contract.
- The first relevant dashboard access starts all approved analytics-section jobs. A bounded on-demand worker pool calculates independent sections in parallel rather than running a scheduled refresh.
- Each completed section is serialized through its approved typed contract and cached in Redis under a key containing merchant id, merchant source revision, relevant cohort revision, metric-definition version, and section id. Cache entries use a configurable high TTL.
- The authenticated SSE stream emits section progress and makes each successful section available immediately; the dashboard does not wait for every job to finish.
- An idempotent authenticated `POST` starts or returns the current analytics run for the merchant/revision. It enqueues the four MVP sections—`overview`, `payment_performance`, `fees`, and `peer_comparison`—for bounded parallel calculation by a separate Go worker service.
- Each completed section is serialized through its approved typed contract and cached in Redis under a key containing merchant id, merchant source revision, relevant cohort revision, metric-definition version, and section id. Cache entries have a 30-day TTL.
- A separate authenticated `GET` SSE stream for that run emits section progress and makes each successful section available immediately; the dashboard does not wait for every job to finish.
- Redis-backed idempotency/single-flight coordination prevents equivalent concurrent requests from duplicating the same section calculation. Parallelism is bounded globally and per merchant.
- Every inserted related payment fact atomically advances the affected PostgreSQL merchant analytics revision. It also advances the relevant cohort/category revision when peer metrics can change. Database-managed revision changes cover direct ZarinPal inserts that bypass Go request handlers.
- Revision changes invalidate logically by producing new cache keys; old values are not trusted and expire through TTL without requiring a Redis key scan.
- Failed sections emit a typed failure event and remain retryable without marking the section ready. Other successful sections remain available.
- Each section attempt has a 60-second timeout. Transient failures receive at most two automatic retries (three total attempts) with exponential backoff and jitter; deterministic validation/authorization failures are not retried. Exhausted sections emit a typed failure event without marking the section ready. Other successful sections remain available.
- Redis is cache/coordination only. PostgreSQL normalized facts and revision rows remain authoritative; loss or flush of Redis causes safe lazy recomputation.
- Redis and the on-demand job worker are private services, never exposed through Nginx. Cache values exclude payer-card keys, credentials, raw payment rows, and cross-tenant details.
@@ -179,11 +179,12 @@ This contract applies only to the one-time challenge-data bootstrap and explicit
- Daily, weekly, Jalali-month, and Persian-season analytics reconcile to deterministic source queries for additive metrics.
- Rates are recomputed from their numerator and denominator over the requested period rather than averaged from daily percentages.
- Non-additive metrics such as unique payer-token counts are never produced by summing daily distinct counts.
- First access starts every core analytics section; each section is delivered through authenticated SSE as soon as it is ready.
- A second equivalent request reads current high-TTL Redis entries without repeating source-fact aggregation.
- First access idempotently creates/returns one run, starts all four core analytics sections in bounded parallel, and delivers each through authenticated SSE as soon as it is ready.
- A second equivalent request reads current 30-day Redis entries without repeating source-fact aggregation.
- Inserting a related payment fact advances only the affected merchant revision and any affected cohort revision; the next relevant request recomputes once and publishes atomically.
- Concurrent equivalent requests do not duplicate section jobs; configured global/per-merchant limits prevent unbounded query fan-out.
- One failed section does not hide ready sections and does not create a ready cache entry.
- A transient section failure performs no more than two retries with exponential backoff/jitter; each attempt ends within 60 seconds, while non-retryable failures fail immediately.
- Redis loss produces a cold-cache calculation rather than loss of source data.
- Reporting-date rows covering the dataset range reconcile deterministically between Gregorian and Jalali day, week, month, and season attributes.
- Every reporting week starts Saturday at `00:00:00` and ends Friday at `23:59:59.999…` in `Asia/Tehran`; API ranges use an equivalent half-open `[start, next_start)` interval.
@@ -204,7 +205,7 @@ Resolved: peer benchmarks exclude the active merchant and require at least 10 ot
Resolved: use normalized PostgreSQL source-of-truth entities plus a reporting-date dimension, then compute versioned analytics sections lazily into Redis. Daily, weekly, Jalali-month, and Persian-season results use explicit date boundaries. Keep fact tables unpartitioned initially and introduce partitioning only from measured need. See ADR 0007.
Resolved: ZarinPal writes future append-only production rows directly to normalized tables. First dashboard access starts all section jobs in bounded parallel, Redis caches each typed result with a high TTL, and authenticated SSE reveals sections as they become ready. PostgreSQL merchant/cohort revisions advanced on insert provide logical invalidation. See ADR 0011.
Resolved: ZarinPal writes future append-only production rows directly to normalized tables. An idempotent `POST` starts four parallel sections in a separate Go worker; Redis caches each typed result for 30 days; an authenticated `GET` SSE stream reveals sections as ready. Each section has a 60-second attempt timeout and at most two transient retries using exponential backoff/jitter. PostgreSQL merchant/cohort revisions provide logical invalidation. See ADR 0011.
Resolved: holiday and named-event reporting are removed from scope. MVP reporting periods are limited to daily, weekly, Jalali-month, and Persian-season views. See ADR 0010.
@@ -212,4 +213,4 @@ Resolved: reporting weeks follow the Iranian week: Saturday through Friday in `A
Resolved: only source session status `Verified` is a definitely successful payment. Keep `Paid` separate until an authoritative ZarinPal definition changes the metric catalogue. See `METRIC-CATALOGUE.md`.
No broad architecture approval gates remain for this capability. Physical columns, indexes, constraints, Redis TTL/limits, SSE delivery details, analytics-section contracts, and migration details still require acceptance in the implementation-ready specs.
No broad architecture approval gates remain for this capability. Physical columns, indexes, exact SSE schemas/reconnect retention, worker concurrency, retry classification, analytics-section response contracts, and migration details still require acceptance in the implementation-ready specs.