Skip to content

Fix/part49 leader elected scheduling - #565

Merged
Wilfred007 merged 3 commits into
Protocol-Guild:mainfrom
Lets-work-0012:fix/part49-leader-elected-scheduling
Aug 19, 2026
Merged

Fix/part49 leader elected scheduling#565
Wilfred007 merged 3 commits into
Protocol-Guild:mainfrom
Lets-work-0012:fix/part49-leader-elected-scheduling

Conversation

@Akatenvictor

Copy link
Copy Markdown

All 26 tests pass (16 existing + 10 new). Here's a summary of the implementation:

Changes Made

Branch: fix/part49-leader-elected-scheduling (3 commits, spread across 20h)

1. backend/src/jobs/part49Jobs.ts — Core rewrite

  • Replaced setInterval(fn, 24h) with node-cron scheduled at 0 0 * * * (midnight UTC)
  • Added pg_try_advisory_lock so only one pod per replica set executes each job — the lock is non-blocking and session-scoped (auto-releases when the client returns to the pool)
  • Kept immediate startup run for catch-up after deploys (safe, idempotent)
  • Returns a ScheduledJob handle with stop() for graceful shutdown

2. backend/src/index.ts — Integration

  • Captures ScheduledJob handles from both scheduler functions
  • Adds stop() calls to the SIGTERM/SIGINT shutdown handler

3. backend/src/jobs/__tests__/part49Jobs.test.ts — 10 tests

  • Cron expression is 0 0 * * * with timezone: 'UTC'
  • Advisory lock acquired → job executes; not acquired → skipped
  • Startup catch-up runs immediately without lock contention
  • stop() halts the cron task
  • DB client released even on job failure

How it works with 2+ replicas

Each pod runs node-cron at midnight UTC. When the cron ticks, every pod attempts pg_try_advisory_lock(84901001) / pg_try_advisory_lock(84901002). Only the first pod to acquire the lock executes; others get acquired: false and skip silently. The lock auto-releases when the DB client is returned to the pool.

Closes #450

Akatenvictor added 3 commits August 19, 2026 02:30
…49 jobs

The previous setInterval-based scheduling ran on every pod at
boot-relative times, causing redundant execution across replicas and
drift from the intended midnight UTC schedule.

- Use node-cron (already a dependency) to schedule at 0 0 * * *
  (midnight UTC) instead of a 24h interval from pod boot time
- Add pg_try_advisory_lock so only one pod in the replica set
  executes each job per cron tick
- Keep immediate startup run for catch-up after deploys
- Return a ScheduledJob handle for graceful shutdown
- Capture ScheduledJob handles from scheduleDailyUsageSnapshots and
  scheduleNightlyIntegrityCheck
- Add stop() calls to the shutdown handler so cron tasks are cleaned
  up on SIGTERM/SIGINT
10 tests covering:
- node-cron scheduled at midnight UTC (0 0 * * *)
- Advisory lock acquired → job executes; lock not acquired → skipped
- Startup catch-up runs fire immediately without lock contention
- stop() halts the cron task
- Database client released even when job throws
@Wilfred007
Wilfred007 merged commit 2f3b902 into Protocol-Guild:main Aug 19, 2026
1 check passed
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.

Scheduled background jobs use per-pod setInterval with no leader election — redundant, non-deterministic execution

2 participants