clean up nested workflows and events#204
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@cursor can you write tests for this? |
commit: |
|
I've written tests for the cleanup functionality and also fixed a bug I discovered. Here's what was done: Tests Added (5 new tests in
Bug Fix in if (journalEntry.step.kind === "event") {
await ctx.db.delete(journalEntry.step.eventId!);to: if (journalEntry.step.kind === "event" && journalEntry.step.eventId) {
await ctx.db.delete(journalEntry.step.eventId);This prevents a crash when |
- Test cleanup deletes associated events when cleaning up workflow with event steps - Test cleanup enqueues cleanup for nested workflows - Test cleanup handles workflow step without workflowId - Test cleanup handles event step without eventId - Test cleanup with mixed event and workflow steps Also fix bug where cleanup would crash when eventId is undefined on event steps. Co-authored-by: Ian Macartney <ianmacartney@users.noreply.github.com>
…journal.startSteps startSteps is a regular mutation, not an internal function. Co-authored-by: Ian Macartney <ianmacartney@users.noreply.github.com>
| if (!nestedWorkflowCompleted) { | ||
| await t.mutation(api.workflow.cancel, { workflowId: nestedWorkflowId! }); | ||
| } |
There was a problem hiding this comment.
@cursor this should happen automatically as part of canceling the parent
There was a problem hiding this comment.
Updated the tests to rely on the parent workflow's cancel automatically canceling nested workflows. The tests now:
- Cancel only the parent workflow
- Verify that the nested workflow was automatically canceled (by checking
runResultis defined) - No longer manually cancel nested workflows separately
This better reflects the expected behavior where canceling a parent propagates cancellation to in-progress nested workflows.
…workflows Canceling the parent workflow automatically cancels in-progress nested workflows, so there's no need to manually cancel them separately. Co-authored-by: Ian Macartney <ianmacartney@users.noreply.github.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/component/workflow.ts (1)
362-364: Reuse a single workpool instance during cleanup.At Line 362,
getWorkpool(ctx, {})runs inside the per-entry loop, which repeats config reads and client construction. Collect nested workflow IDs first, then enqueue with one workpool instance (and dedupe IDs).♻️ Suggested refactor
- for (const journalEntry of journalEntries) { + const nestedWorkflowIds = new Set<Id<"workflows">>(); + for (const journalEntry of journalEntries) { logger.debug("Deleting journal entry", journalEntry); await ctx.db.delete(journalEntry._id); if (journalEntry.step.kind === "event" && journalEntry.step.eventId) { await ctx.db.delete(journalEntry.step.eventId); } else if ( journalEntry.step.kind === "workflow" && journalEntry.step.workflowId ) { - const workpool = await getWorkpool(ctx, {}); - await workpool.enqueueMutation(ctx, api.workflow.cleanup, { - workflowId: journalEntry.step.workflowId, - }); + nestedWorkflowIds.add(journalEntry.step.workflowId); } } + if (nestedWorkflowIds.size > 0) { + const workpool = await getWorkpool(ctx, {}); + for (const nestedWorkflowId of nestedWorkflowIds) { + await workpool.enqueueMutation(ctx, api.workflow.cleanup, { + workflowId: nestedWorkflowId, + }); + } + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/component/workflow.ts` around lines 362 - 364, The current code calls getWorkpool(ctx, {}) inside the per-entry loop which rebuilds clients/config repeatedly; instead, first collect all nested workflow IDs from journalEntry.step.workflowId across entries (dedupe them), then call getWorkpool(ctx, {}) once to obtain a single workpool and call workpool.enqueueMutation(ctx, api.workflow.cleanup, { workflowId: id }) for each unique id; update the loop to remove repeated getWorkpool calls and use the single workpool instance for all enqueueMutation calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/component/workflow.ts`:
- Around line 362-364: The current code calls getWorkpool(ctx, {}) inside the
per-entry loop which rebuilds clients/config repeatedly; instead, first collect
all nested workflow IDs from journalEntry.step.workflowId across entries (dedupe
them), then call getWorkpool(ctx, {}) once to obtain a single workpool and call
workpool.enqueueMutation(ctx, api.workflow.cleanup, { workflowId: id }) for each
unique id; update the loop to remove repeated getWorkpool calls and use the
single workpool instance for all enqueueMutation calls.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (2)
src/component/workflow.test.tssrc/component/workflow.ts
sethconvex
left a comment
There was a problem hiding this comment.
If you're not worried about deleting lots of potential steps in one mutation, LGTM.
| logger.debug("Deleting journal entry", journalEntry); | ||
| await ctx.db.delete(journalEntry._id); | ||
| if (journalEntry.step.kind === "event" && journalEntry.step.eventId) { | ||
| await ctx.db.delete(journalEntry.step.eventId); |
There was a problem hiding this comment.
Is this going to be a problem when there are lots of steps with big args?
There was a problem hiding this comment.
We currently limit the journal & size of all steps to be max 8MiB, including events I believe, so deletion should only consume <= 16MiB if we read everything and delete them individually. If they hit the limit on the nose we might be in trouble for the extra workflow metadata, but deleting events take less data b/c we only read as part of the delete, not fetched in addition.
|
Merged into main directly |



TL;DR
Enhanced workflow cleanup to properly delete associated events and nested workflows.
Fixes #186
What changed?
Added logic to the
cleanupmutation to handle additional resource deletion:How to test?
Why make this change?
This change prevents resource leaks by ensuring that when a workflow is cleaned up, all of its associated resources (events and nested workflows) are properly deleted as well. Without this change, orphaned events and nested workflows would remain in the database after the parent workflow is cleaned up.
Summary by CodeRabbit
Bug Fixes
Tests