Skip to content

fix(crew): add missing drain_writes call in akickoff finally block#4932

Closed
wishhyt wants to merge 1 commit intocrewAIInc:mainfrom
wishhyt:fix/crew-akickoff-drain-writes
Closed

fix(crew): add missing drain_writes call in akickoff finally block#4932
wishhyt wants to merge 1 commit intocrewAIInc:mainfrom
wishhyt:fix/crew-akickoff-drain-writes

Conversation

@wishhyt
Copy link
Copy Markdown
Contributor

@wishhyt wishhyt commented Mar 18, 2026

Summary

  • The synchronous kickoff() correctly calls self._memory.drain_writes() in its finally block to ensure all background memory saves complete before returning.
  • The async akickoff() was missing this call, so background memory writes could be silently lost when using the async entry point.

Changes

Added the same drain_writes() call to akickoff()'s finally block.

Test plan

Run a crew with memory enabled via akickoff() and verify memory records are persisted


Note

Low Risk
Low risk: adds a guarded drain_writes() call in an async finally block to prevent losing queued memory writes, with minimal behavioral impact beyond waiting for persistence.

Overview
Native async Crew.akickoff() now mirrors the sync kickoff() cleanup behavior by calling self._memory.drain_writes() (when supported) in its finally block before clear_files()/context detach.

This prevents background memory saves from being dropped when using the native async entrypoint.

Written by Cursor Bugbot for commit be48692. This will update automatically on new commits. Configure here.

The synchronous `kickoff()` correctly calls
`self._memory.drain_writes()` in its finally block to ensure all
background memory saves complete before returning. The async
`akickoff()` was missing this call, so background memory writes
could be silently lost when using the async entry point.

Made-with: Cursor
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

raise
finally:
if self._memory is not None and hasattr(self._memory, "drain_writes"):
self._memory.drain_writes()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking call in async method stalls event loop

Medium Severity

drain_writes() is a synchronous method that calls future.result() on concurrent.futures.Future objects, which blocks the calling thread. Invoking it directly inside the async def akickoff() method blocks the event loop, preventing all other coroutines from making progress until every pending memory save completes. This is particularly impactful when multiple crews run concurrently via asyncio.gather() or similar patterns. The call needs to be offloaded (e.g., via asyncio.to_thread) to avoid starving the event loop.

Fix in Cursor Fix in Web

@greysonlalonde
Copy link
Copy Markdown
Contributor

Duplicate of #4768. Closing.

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.

2 participants