-
Notifications
You must be signed in to change notification settings - Fork 295
Schedule fixes #653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schedule fixes #653
Conversation
🦋 Changeset detectedLatest commit: 8dffadb The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Claude Code ReviewIssues found:
Suggested fix for #1: // After line 1275, add early return:
if (result && Array.isArray(result)) {
for (const row of result) {
if (this._destroyed) return; // Check at loop start
const callback = this[row.callback as keyof Agent<Env>];
// ... rest of loop
// Remove the three other _destroyed checks since we check at loop startOtherwise the approach is sound and properly addresses the reported issues. |
commit: |
Add a destroyed flag and yield context abort functionality.
Updates documentation to reflect that destroy() can now be safely called within scheduled task callbacks. The Agent properly handles cleanup by: - Setting an internal flag to skip remaining database updates - Yielding ctx.abort() to the event loop for clean alarm handler completion This addresses the fix in cloudflare/agents#653 where calling destroy() inside a schedule previously caused errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
📚 Documentation has been updated to reflect these changes. Documentation PR: cloudflare/cloudflare-docs#26558 The following documentation pages have been updated:
The documentation now explains that when
|
Updates documentation to reflect that destroy() can now be safely called from within scheduled task callbacks. The Agent SDK now: - Sets an internal flag to prevent database updates after destruction - Defers ctx.abort() to the event loop to allow handlers to complete Related to cloudflare/agents#653 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
Documentation has been updated to reflect this change in cloudflare-docs#26558. |
Updates schedule-tasks.mdx to reflect changes from cloudflare/agents#653: - Add example showing immediate task scheduling (delay = 0) - Document safe usage of destroy() within scheduled callbacks - Explain that Agent SDK defers destruction to ensure scheduled tasks complete Addresses the fix for issue #616 where calling destroy() inside a schedule would cause errors and retry loops. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
📚 Documentation UpdatedThe documentation has been updated to reflect the changes in this PR. Updated documentation:
Cloudflare Docs PR: cloudflare/cloudflare-docs#26558 Changes include:
This comment was automatically generated by the documentation sync workflow. |
Documentation Sync📚 Documentation has been synced to cloudflare-docs Docs PR: cloudflare/cloudflare-docs#26558 Changes synced:
The documentation now reflects the fixes for calling |
|
Documentation for this PR has been updated in cloudflare/cloudflare-docs#26558 |
|
📚 Documentation update: cloudflare/cloudflare-docs#26558 This PR documents the schedule bug fixes, including:
|
mattzcarey
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good. I was seeing this all the time for the playground :))
threepointone
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some notes, will stamp after clarification.
.changeset/neat-beds-cheat.md
Outdated
| "agents": patch | ||
| --- | ||
|
|
||
| add destroyed flag and yield ctx.abort |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't clear, can you make it just a bit clearer what it does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
| } | ||
|
|
||
| export class TestCaseSensitiveAgent extends Agent<Env> { | ||
| observability = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why removing observability on all these agents?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They flood stdout with logs about schedules, connections etc. I've never found them particularly useful (at least in the test runs).
There's still a lot of workerd internal logs but I appreciate less noise unless others find them useful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fair. tbh I'm very unhappy with our observability stuff anyway, I want to rip it all out.
| `; | ||
|
|
||
| // execute any pending alarms and schedule the next alarm | ||
| await this.alarm(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really wish I could remember why we did this. but I'll keep an.eye out for it.
this.destroy()in handlersCurrently, calling
this.destroyinside a schedule won't clean up the Agent properly. There are 2 issues at play:this.destroydeletes all tables from SQLITE (and all other storage). This causes an error in the alarm handler since theAgentalarm tries to update thecf_agent_schedulestable after the schedule callback is run.this.ctx.abortthrows an uncatchable error to force DO eviction. When this happens inside the alarm handler the runtime attempts a re-try.To address both, this PR:
this.destroyed = truefrom withinthis.destroyto skip SQLITE updates in the alarm handler whenever it's set.this.ctx.abortto the event loop so we don't throw the error in the alarm handler's context. Since we're always in a single-threaded runtime we ensure that the handler completes before thethis.ctx.aborttask in the event loop is executed.(IO ops after
this.destroycould seethis.ctx.abortbeing called before completion but adding anything afterthis.destroyis an anti-pattern anyway so I think it's fine)Fixes #616.
this.ctx.blockConcurrencyWhile(...)in constructorInside the
Agentthere's a manual call toawait this.alarm()(for which we use the bCW) to run due schedules. Since we're usingthis.ctx.storage.setAlarminternally, the alarm method is called by the runtime after the constructor anyway, so we can get rid of our manual call.So basically:
BEFORE:
constructor()->await this.alarm()(called manually) ->alarm()(called by the runtime)NOW:
constructor()->alarm()(called by the runtime)Fixes #600
PS: There are 2 seemingly unrelated changes included:
this._scheduleNextAlarmwasn't taking into account schedules for now (e.g.this.schedule(0, "destroy")).observability = undefinedin the test DOs to reduce stdout noise.