Skip to content

feat(cubejs): refresh-worker liveness endpoint for a stalled scheduler - #94

Merged
acmeguy merged 1 commit into
mainfrom
fix/refresh-scheduler-liveness
Oct 12, 2026
Merged

acmeguy merged 1 commit into
mainfrom
fix/refresh-scheduler-liveness

Conversation

@acmeguy

@acmeguy acmeguy commented Oct 12, 2026

Copy link
Copy Markdown

Why

Cube's refresh scheduler skips a tick while the previous interval is still running, and intervals have no timeout. A hung interval on dev (2026-10-08, root cause fixed in #93) stopped pre-aggregation refresh for every tenant for 4.5 days with no error and no restart. The worker's only liveness check was pgrep.

What

  • scheduledRefreshContexts runs at the start of every interval, so it now records a heartbeat.
  • GET /scheduler-health returns 503 and logs Refresh scheduler stalled: no interval started for Nm once no interval has started for 30 min. Normal dev intervals take 1–5 min; the worst seen in 5 days was 5:18.
  • The route is mounted only where the scheduler runs. API pods set CUBEJS_SCHEDULED_REFRESH=false, so they don't expose it. The path is outside /api, so nginx doesn't proxy it.

Rollout order

Deploy this image first. Then the fraios infra PR switches the refresh-worker livenessProbe from pgrep to httpGet /scheduler-health and adds the Prometheus alerts. Switching the probe before this image is live would 404 and restart-loop the worker.

Test

src/utils/__tests__/scheduledRefreshStall.test.js mocks timers and makes the datasource lookup hang, as it did on dev. It checks that the endpoint stays healthy at 29 min, reports a stall at 31 min, resets when a new interval starts even though that interval then hangs, and stalls again 31 min later. Cubejs suite: 701/703; the 2 failures are the existing runtimeDependencyHardening local-install checks.

🤖 Generated with Claude Code

Cube's scheduler skips a tick while the previous interval is still running
and has no timeout, so a hung interval (dev, 2026-10-08) stopped
pre-aggregation refresh for every tenant for 4.5 days with no error and no
restart. The only liveness check was pgrep.

scheduledRefreshContexts is called at the start of every interval, so it now
records a heartbeat. GET /scheduler-health returns 503 (and logs why) once no
interval has started for 30 minutes; the worker's liveness probe can then
restart it. Mounted only where the scheduler runs, so API pods (scheduled
refresh off) don't expose it. Normal intervals on dev take 1-5 minutes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@acmeguy
acmeguy merged commit 004874c into main Oct 12, 2026
3 checks passed
@acmeguy
acmeguy deleted the fix/refresh-scheduler-liveness branch October 12, 2026 18:02
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.

1 participant