Skip to content

Avoid full article-card refreshes for scheduler clock rechecks - #300

Merged
abhi1693 merged 15 commits into
masterfrom
fix/294-scheduler-clock-refresh
Oct 24, 2026
Merged

abhi1693 merged 15 commits into
masterfrom
fix/294-scheduler-clock-refresh

Conversation

@abhi1693

@abhi1693 abhi1693 commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

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

  • The native ARM64 PostgreSQL 17.11 comparison passed at exact head 1f02ffda with 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.
  • The original results comment updates in place with Before, After, Delta and signed Improvement columns. It includes SQL, buffer, temporary-write and WAL counters; invalid or incomplete runs cannot claim a speedup. Reporting reads artifacts without executing PR code and rejects stale head/base SHAs. Exactly one scheduler results comment remains.
  • CI for 1f02ffda finished 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.
  • CI repair validation passed 1,016 tooling tests (16 skipped; 52 benchmark-runner regressions included), plus 64 report/parity tests, 16 isolated Locust tests and Python lint/format/types/version checks. Actual disposable HTTP/database/pooler probes verified SCRAM authentication, wrong-password rejection, completed warmup/measurement and exclusion of sampler SQL. A final disposable smoke completed 69 HTTP requests without failures. Canonical unsigned 32-bit seeds are validated before creating resources, and the runner writes JSON reports through file descriptors that reject symlinks and enforce owner-only permissions. Node 26 overflow fixtures retain complete 413/deadline assertions. The admin notification fixture waits for readiness, and the Edge touch fixture settles real scroll-history persistence before setup; native pointer, 44px target and actual tap checks remain enforced.
  • API performance uses three paired ARM64 runners, deterministic per-user journeys, completed bootstrap, 15 seconds of warmup and a full 60-second measured window. The strict 20% and 20 ms regression thresholds and existing noise gates are unchanged. All six final samples had zero HTTP failures; the hosted gate passed with INCONCLUSIVE latency due to runner noise. No API latency improvement or unchanged-latency claim is made. CPU, SQL, wait and pool diagnostics remain downloadable.

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

  • The description explains the change, validation and remaining gaps.
  • Relevant documentation and regression tests are updated.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Backend unit coverage

PASS · minimum combined coverage 98.00%.

Tests: 10446 passed, 0 failed, 0 skipped. Source files: 367.

Workspace Lines Branches Combined
All backend code 98.68% 95.66% 98.01%
apps/admin-api 96.65% 89.65% 95.32%
apps/aggregator 97.99% 94.45% 97.18%
apps/api 99.49% 98.88% 99.38%
apps/article-enrichment-worker 80.00% 50.00% 71.43%
apps/cli 99.43% 90.76% 98.13%
apps/images-worker 80.00% 50.00% 71.43%
apps/mcp 99.86% 98.70% 99.65%
apps/notifications 100.00% 100.00% 100.00%
apps/partner-api 99.47% 95.51% 98.83%
apps/search-indexer 85.48% 85.71% 85.53%
apps/source-discovery-worker 80.00% 50.00% 71.43%
apps/user-api 99.88% 98.96% 99.72%
packages/core 99.10% 96.86% 98.55%
packages/http 99.47% 97.49% 99.03%

Unit coverage includes every backend workspace. PostgreSQL/Redis integration tests run separately.

Commit: 1f02ffd · HTML, JSON, XML reports and job logs · attempt 1

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

PR reader API performance

Result: INCONCLUSIVE

5 inconclusive · 3 within threshold. Zero request failures across all six runs.

Base 6da65ecab623444bb1933e59b7d354013726efad → PR 1f02ffda829b939c8b45efc325bd162730f9a0eb

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 comparison

All latency values are in milliseconds; lower is better. Values are medians of three runs, with one-millisecond histogram bins.

Route Base p95 PR p95 Change Result
All requests 108 111 +3 (+2.8%) Within threshold
Latest feed 133 142 +9 (+6.8%) Within threshold
Feed pagination 93 105 +12 (+12.9%) Inconclusive
Article detail 88 80 -8 (-9.1%) Within threshold
Source feed 83 114 +31 (+37.3%) Inconclusive
Topic feed 109 100 -9 (-8.3%) Inconclusive
Feed filters 72 84 +12 (+16.7%) Inconclusive
Sources 40 42 +2 (+5.0%) Within threshold
Topics 47 55 +8 (+17.0%) Inconclusive
Additional latency and throughput metrics

Each cell shows base → PR. Latencies are in milliseconds.

Endpoint p50 p99 Requests/s
Aggregated 35 → 37 156 → 169 28.65 → 28.58
/v1/feed [latest] 50 → 51 174 → 190 8.60 → 8.59
/v1/feed [page] 34 → 35 151 → 173 4.08 → 4.05
/v1/articles/[id] 22 → 23 116 → 133 5.80 → 5.79
/v1/feed [source] 33 → 33 147 → 143 2.02 → 2.00
/v1/feed [topic] 35 → 33 164 → 146 1.60 → 1.60
/v1/feed/options 25 → 25 97 → 139 2.18 → 2.18
/v1/sources 15 → 15 72 → 81 2.18 → 2.18
/v1/topics 15 → 16 123 → 105 2.18 → 2.18
All paired p95 samples and changes

Each 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.

Route Pair 1 Pair 2 Pair 3 Slower pairs Faster pairs
All requests 129 → 121 (-8, -6.2%) 99 → 105 (+6, +6.1%) 108 → 111 (+3, +2.8%) 0 0
Latest feed 163 → 145 (-18, -11.0%) 126 → 125 (-1, -0.8%) 133 → 142 (+9, +6.8%) 0 0
Feed pagination 127 → 119 (-8, -6.3%) 84 → 99 (+15, +17.9%) 93 → 105 (+12, +12.9%) 0 0
Article detail 96 → 92 (-4, -4.2%) 82 → 80 (-2, -2.4%) 88 → 77 (-11, -12.5%) 0 0
Source feed 126 → 124 (-2, -1.6%) 83 → 94 (+11, +13.3%) 71 → 114 (+43, +60.6%) 1 0
Topic feed 109 → 113 (+4, +3.7%) 95 → 99 (+4, +4.2%) 141 → 100 (-41, -29.1%) 0 1
Feed filters 78 → 76 (-2, -2.6%) 46 → 84 (+38, +82.6%) 72 → 90 (+18, +25.0%) 1 0
Sources 49 → 40 (-9, -18.4%) 40 → 56 (+16, +40.0%) 38 → 42 (+4, +10.5%) 0 0
Topics 82 → 64 (-18, -22.0%) 42 → 48 (+6, +14.3%) 47 → 55 (+8, +17.0%) 0 0
Individual runs
Run Requests Failures Exit code
Base 1 1706 0 0
Base 2 1726 0 0
Base 3 1719 0 0
PR 1 1711 0 0
PR 2 1725 0 0
PR 3 1714 0 0
How to interpret this report

Regressed / 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

abhi1693 commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner Author

Scheduler recheck scale results

PASS · 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 articles

Valid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.

Metric Before After Delta Improvement (+/-)
Workload runtime (s) 19.513 13.310 -6.203 +31.8%
Application CPU (s) 17.426 11.608 -5.818 +33.4%
Clock-only events 250 0 -250 +100.0%
Cohort card hydrations 250 0 -250 +100.0%
SQL calls 6,890 5,635 -1,255 +18.2%
Shared blocks hit 830,017 493,729 -336,288 +40.5%
Shared blocks read 3,946 541 -3,405 +86.3%
Temporary blocks written 0 0 0 0.0%
WAL records 10,920 8,541 -2,379 +21.8%
WAL full-page images 919 825 -94 +10.2%
WAL bytes 7,442,144 6,379,884 -1,062,260 +14.3%

Before includes the expected clock-only event/hydration amplification.

Positive improvement means reduced cost; negative means increased cost. Delta = after - before.

Base 6da65ecab623444bb1933e59b7d354013726efad → candidate 1f02ffda829b939c8b45efc325bd162730f9a0eb.
Workflow run.

150,000 articles

Valid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.

Metric Before After Delta Improvement (+/-)
Workload runtime (s) 27.966 17.567 -10.399 +37.2%
Application CPU (s) 24.757 15.803 -8.954 +36.2%
Clock-only events 250 0 -250 +100.0%
Cohort card hydrations 250 0 -250 +100.0%
SQL calls 6,891 5,636 -1,255 +18.2%
Shared blocks hit 1,188,807 691,518 -497,289 +41.8%
Shared blocks read 7,013 15,916 +8,903 -126.9%
Temporary blocks written 0 0 0 0.0%
WAL records 10,933 8,397 -2,536 +23.2%
WAL full-page images 954 852 -102 +10.7%
WAL bytes 7,707,037 6,496,957 -1,210,080 +15.7%

Before includes the expected clock-only event/hydration amplification.

Positive improvement means reduced cost; negative means increased cost. Delta = after - before.

Base 6da65ecab623444bb1933e59b7d354013726efad → candidate 1f02ffda829b939c8b45efc325bd162730f9a0eb.
Workflow run.

Head: 1f02ffd · base: 6da65ec

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.

Comment thread .github/workflows/scheduler-recheck-scale.yml Fixed
Comment thread scripts/render_scheduler_recheck_report.cjs Fixed
Comment thread scripts/render_scheduler_recheck_report.cjs Fixed
Comment thread .github/workflows/scheduler-recheck-scale.yml Fixed
Comment thread .github/workflows/scheduler-recheck-scale.yml Fixed
Comment thread .github/workflows/scheduler-recheck-scale.yml Fixed
Comment thread .github/workflows/scheduler-recheck-scale.yml Fixed
Repository owner deleted a comment from github-actions Bot Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Lighthouse · ⚠️ Targets exceeded

⚠️ 12 target warnings · Bold values need attention.

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) ⚠️ Target · LCP 4.20 s 4.00 s
Latest (/latest) ⚠️ Target · JS transfer 361 KiB 330 KiB
Latest (/latest) ⚠️ Target · LCP 4.20 s 2.50 s
Latest (/latest) ⚠️ Target · TBT 255 ms 200 ms
Article preview (/articles/…) ⚠️ Target · JS transfer 364 KiB 330 KiB
Article preview (/articles/…) ⚠️ Target · LCP 3.93 s 2.50 s
Topics (/topics) ⚠️ Target · LCP 3.97 s 2.50 s
Sources (/sources) ⚠️ Target · LCP 4.07 s 4.00 s
Sources (/sources) ⚠️ Target · JS transfer 332 KiB 330 KiB
Sources (/sources) ⚠️ Target · LCP 4.07 s 2.50 s
Sources (/sources) ⚠️ Target · TBT 253 ms 200 ms
Public profile (/users/…) ⚠️ Target · LCP 3.24 s 2.50 s

Full reports and logs · 1f02ffd · Attempt 1

Comment thread scripts/load-test.py Fixed
Comment thread scripts/load-test.py Fixed
@sonarqubecloud

Copy link
Copy Markdown

@abhi1693
abhi1693 merged commit ed21947 into master Oct 24, 2026
92 checks passed
@abhi1693
abhi1693 deleted the fix/294-scheduler-clock-refresh branch October 24, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants