What
durableChannelSurface runs a turn by holding a fetch to the DO's /turn under the EDGE worker's ctx.waitUntil, and /turn responds only when the turn completes. The edge's post-response waitUntil window is finite — a long turn (multi-round tool use) gets the fetch cancelled, which kills the DO request and the turn mid-flight.
Impact
Observed in production (kaik-crisp-agent, 2026-07-15): turns running 24–38s intermittently died with waitUntil() tasks did not complete within the allowed time + POST https://do/turn - Canceled. For observe/shadow channels (mode: "observe") the edge never uses the reply — holding the edge open for the whole turn buys nothing and bounds turn duration by edge lifetime instead of DO lifetime.
Suggested fix
An async turn mode (e.g. POST /turn?detach=1 or a detached: true option on the channel surface): the DO accepts, responds 202 immediately, and runs the turn under its own lifetime (DOs stay alive while they have work). Channels in observe mode should default to it — they drop the reply anyway. Respond-mode channels keep the current await-reply path.
Versions: @junejs/server 0.1.2-dev.4, @junejs/core 0.1.1-dev.9.
What
durableChannelSurfaceruns a turn by holding a fetch to the DO's/turnunder the EDGE worker'sctx.waitUntil, and/turnresponds only when the turn completes. The edge's post-response waitUntil window is finite — a long turn (multi-round tool use) gets the fetch cancelled, which kills the DO request and the turn mid-flight.Impact
Observed in production (kaik-crisp-agent, 2026-07-15): turns running 24–38s intermittently died with
waitUntil() tasks did not complete within the allowed time+POST https://do/turn - Canceled. For observe/shadow channels (mode: "observe") the edge never uses the reply — holding the edge open for the whole turn buys nothing and bounds turn duration by edge lifetime instead of DO lifetime.Suggested fix
An async turn mode (e.g.
POST /turn?detach=1or adetached: trueoption on the channel surface): the DO accepts, responds 202 immediately, and runs the turn under its own lifetime (DOs stay alive while they have work). Channels in observe mode should default to it — they drop the reply anyway. Respond-mode channels keep the current await-reply path.Versions: @junejs/server 0.1.2-dev.4, @junejs/core 0.1.1-dev.9.