Repository navigation
Avoid full article-card refreshes for scheduler clock rechecks - #300
Conversation
Backend unit coveragePASS · minimum combined coverage 98.00%. Tests: 10446 passed, 0 failed, 0 skipped. Source files: 367.
Unit coverage includes every backend workspace. PostgreSQL/Redis integration tests run separately. Commit: 1f02ffd · HTML, JSON, XML reports and job logs · attempt 1 |
PR reader API performanceResult: INCONCLUSIVE 5 inconclusive · 3 within threshold. Zero request failures across all six runs. Base Three independent GitHub-hosted ARM64 runners, each measuring base and PR sequentially with alternating order and isolated resources for every sample. 16 users, completed bootstrap and 15 seconds of warmup before each full 60-second measurement, fixed journey seed 294, 1,000 synthetic articles, cache off, five PgBouncer slots. Latency comparisonAll latency values are in milliseconds; lower is better. Values are medians of three runs, with one-millisecond histogram bins.
Additional latency and throughput metricsEach cell shows base → PR. Latencies are in milliseconds.
All paired p95 samples and changesEach pair shares a validated runner. Cells show base → PR p95 (absolute and percentage change), in milliseconds. Slower/faster counts use the same strict 20% and 20 ms thresholds against that pair's own baseline.
Individual runs
How to interpret this reportRegressed / Improved: a p95 regression needs >20% and >20 ms increase in the medians and in at least two same-runner base/PR pairs. Improvements use the inverse threshold. Within threshold means the change did not meet both thresholds. Inconclusive: a within-revision p95 range >35% of its median and >20 ms is too noisy for a confident latency verdict. A material median change without two confirming pairs is also inconclusive; this does not prove unchanged performance. Inconclusive latency comparisons are non-blocking: the check passes without claiming an improvement. Confirmed regressions and test/report errors fail the PR gate. Throughput is descriptive: paced users do not measure maximum capacity. This uncached public API test does not establish production health, browser performance or worker capacity. Base and PR share a runner within each pair; three pairs use independent runners. Alternating order reduces host-assignment bias but cannot eliminate changes in host load over time. Full HTML/CSV reports and logs · attempt 1 |
Scheduler recheck scale resultsPASS · native ARM64 · PostgreSQL 17.11 · 5 × 50 rechecks + 50 concurrent ingests per dataset. Improvement: positive = less work or time; negative = regression. Before and after use identical historical populations. 100,000 articlesValid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.
Before includes the expected clock-only event/hydration amplification. Positive improvement means reduced cost; negative means increased cost. Delta = after - before. Base 150,000 articlesValid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.
Before includes the expected clock-only event/hydration amplification. Positive improvement means reduced cost; negative means increased cost. Delta = after - before. Base Measurements, query plans and job logs · attempt 1 Synthetic warmed scheduler/publisher workload; not production p95. Production reference: 92,581 articles on 2026-10-24. No deployment is performed. |
Lighthouse ·
|
| Page | FCP | LCP | CLS | TBT | JS | Total |
|---|---|---|---|---|---|---|
Latest (/latest) |
1.21 s | 4.20 s | 0.001 | 255 ms | 361 KiB | 663 KiB |
Article preview (/articles/…) |
1.36 s | 3.93 s | 0.005 | 142 ms | 364 KiB | 685 KiB |
Topics (/topics) |
1.22 s | 3.97 s | 0.000 | 162 ms | 319 KiB | 471 KiB |
Sources (/sources) |
1.22 s | 4.07 s | 0.000 | 253 ms | 332 KiB | 488 KiB |
Public profile (/users/…) |
1.21 s | 3.24 s | 0.009 | 88 ms | 280 KiB | 428 KiB |
Leaderboard (/leaderboard) |
1.06 s | 2.37 s | 0.000 | 101 ms | 276 KiB | 383 KiB |
Mobile reader · Three cold loads per page · Median timings · Largest transfer size.
Needs attention
| Page | Finding | Measured | Target / limit |
|---|---|---|---|
Latest (/latest) |
4.20 s | 4.00 s | |
Latest (/latest) |
361 KiB | 330 KiB | |
Latest (/latest) |
4.20 s | 2.50 s | |
Latest (/latest) |
255 ms | 200 ms | |
Article preview (/articles/…) |
364 KiB | 330 KiB | |
Article preview (/articles/…) |
3.93 s | 2.50 s | |
Topics (/topics) |
3.97 s | 2.50 s | |
Sources (/sources) |
4.07 s | 4.00 s | |
Sources (/sources) |
332 KiB | 330 KiB | |
Sources (/sources) |
4.07 s | 2.50 s | |
Sources (/sources) |
253 ms | 200 ms | |
Public profile (/users/…) |
3.24 s | 2.50 s |
Full reports and logs · 1f02ffd · Attempt 1
|



What changes and why?
Scheduler checks that only advanced an article's next-check time queued full pipeline-card refreshes, repeatedly loading retained analysis evidence while jobs were already queued or running.
Migration 0035 separates clock maintenance from semantic invalidation. Clock changes patch only the saved next-check field in serving/building projections by primary key. Article, analysis, approval, source and catalog changes retain their normal refresh path.
The publisher synchronizes detached cards with current clocks under nonblocking article locks. Contention rolls back the whole batch with its events intact, preserving retries and avoiding opposite lock ordering during bulk ingestion. Active-job checks defer large analysis payloads and reuse unchanged prerequisite facts.
Related issues
Related to #294.
Validation
1f02ffdawith matched 100,000- and 150,000-article datasets. Runtime improved 31.8% / 37.2%, application CPU 33.4% / 36.2%, and clock-only events/card hydrations fell 250 → 0 at both sizes. All 50 concurrent ingests projected; clocks, retries and leases remained correct. Shared-block reads at 150k increased 7,013 → 15,916 (+126.9%), retained as a negative improvement in the report. No retention cleanup ran. Actual plans returned 50 due articles through the due index and patched one projection row by primary key.1f02ffdafinished successfully with 72 passed jobs, including CI required, all three CodeQL analyses, Sonar's quality gate and all twelve ARM64 image build/scan/smoke checks. Sonar reports 97.1% new-code coverage, zero bugs, vulnerabilities or code smells, and no open issues. All nine review threads are resolved. Regression coverage includes queued/running checks, retry deadlines, completion/deletion races, policy rebuilds, lock contention, rollback and specialist lease recovery. Local application validation passed 10,370 backend units, 294 projection/migration integrations and 107 scheduler/lifecycle integrations.The production reference is dated 24 October 2026, 09:27–09:28 UTC: 92,581 articles, 156,004 analysis jobs and 7,302 queued analyses. Volume fixtures exceed these recorded populations with retained history and taxonomy. These synthetic warmed measurements do not establish production percentiles or universal I/O savings.
Methodology and reproduction. No user-facing UI changes.
Rollout notes
Pause the previous pipeline publisher before upgrading to schema 0035, then start the candidate publisher. The previous publisher lacks clock synchronization and must not publish detached cards after the trigger changes.
The trigger-only migration preserves queued events and article/job history. To roll back, downgrade to 0034 while keeping the candidate publisher, then roll back the application. Coordinate independently developed migrations to preserve one Alembic head.
No deployment has been made. After deployment, compare matched-workload event lag, scheduler/publisher CPU, WAL/write volume, clock visibility, overdue retries and recovery.
Ready for review