Skip to content

fix(scheduled-task): wait for session startup before giving up#165

Merged
grinev merged 1 commit into
grinev:mainfrom
xodmd45-ctrl:fix/scheduled-task-startup-race
Jun 20, 2026
Merged

fix(scheduled-task): wait for session startup before giving up#165
grinev merged 1 commit into
grinev:mainfrom
xodmd45-ctrl:fix/scheduled-task-startup-race

Conversation

@xodmd45-ctrl

Copy link
Copy Markdown
Contributor

Fixes #164.

Problem

waitForScheduledTaskResult treated a session that is not yet in the status map (server has not started processing the prompt) the same as a session that has gone idle:

const sessionStatus = statuses[sessionId];
if (!sessionStatus || sessionStatus.type === "idle") {
  ...
  idlePollsWithoutResult += 1;
  if (idlePollsWithoutResult >= MAX_IDLE_POLLS_WITHOUT_RESULT) {
    throw new Error("Scheduled task finished without a completed assistant response");
  }
}

With MAX_IDLE_POLLS_WITHOUT_RESULT = 3 × EXECUTION_POLL_INTERVAL_MS = 2000, the executor gives up after only ~6s. After promptAsync, OpenCode does not register the session in session.status until it begins processing, which on a cold project instance routinely takes longer than 6s (measured: ~6.3s warm, ~23s cold first-of-day).

When the executor gives up, the finally block deletes the temporary session while the server is still inserting the first user message, producing a server-side FOREIGN KEY constraint failed (message.session_id → session.id). This made scheduled tasks fail every day.

Fix

Track whether the session has been observed active (hasObservedActivity). Only apply the short MAX_IDLE_POLLS_WITHOUT_RESULT deadline after activity has been seen; before that, wait through a dedicated startup grace (MAX_STARTUP_POLLS_WITHOUT_ACTIVITY). A session that legitimately goes idle after working still fails fast as before.

Tests

  • New test: the executor keeps polling past MAX_IDLE_POLLS_WITHOUT_RESULT while the session is absent from the status map, then succeeds once it becomes active.
  • npm run build, npm run lint, and vitest run all pass (14/14 in this suite).

Verified end-to-end against a live bot (0.21.2 + opencode 1.17.8, zai-coding-plan/glm-5.2): the scheduled task now reaches model streaming instead of failing with the FK error at ~6s.

The executor treated a session missing from the status map (server has
not started it yet) the same as an idle session, so it gave up after
~6s (MAX_IDLE_POLLS_WITHOUT_RESULT * EXECUTION_POLL_INTERVAL_MS). The
finally block then deleted the temporary session while the server was
still inserting the first user message, which failed server-side with
"FOREIGN KEY constraint failed" and surfaced as a daily scheduled-task
failure ("finished without a completed assistant response").

Track whether the session has been observed active; only apply the
short idle deadline after activity is seen, and use a separate startup
grace before the server registers the session.

Fixes grinev#164
@grinev

grinev commented Jun 20, 2026

Copy link
Copy Markdown
Owner

@xodmd45-ctrl thanks for contribution!

@grinev grinev merged commit b3d1eb8 into grinev:main Jun 20, 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 tasks fail daily: premature giveup during session startup deletes the session (FOREIGN KEY constraint failed)

3 participants