Skip to content

fix(token_usage): replace threading.Lock with asyncio.Lock in record()#1893

Merged
zhijianma merged 1 commit intoagentscope-ai:mainfrom
mvanhorn:osc/1834-fix-token-usage-async-lock
Mar 20, 2026
Merged

fix(token_usage): replace threading.Lock with asyncio.Lock in record()#1893
zhijianma merged 1 commit intoagentscope-ai:mainfrom
mvanhorn:osc/1834-fix-token-usage-async-lock

Conversation

@mvanhorn
Copy link
Copy Markdown
Contributor

Summary

TokenUsageManager.record() is an async method that uses self._file_lock = threading.Lock() to serialize file I/O. threading.Lock is a blocking primitive - when acquired inside an async method on the event loop thread, it blocks the entire event loop until released. Under concurrent calls this produces the deadlock captured in the py-spy stack dump in #1834.

Fix: Replace threading.Lock() with asyncio.Lock() for _file_lock and change with self._file_lock: to async with self._file_lock:. This is the same pattern already used in app/runner/manager.py, app/crons/manager.py, and app/mcp/manager.py.

The class-level threading.Lock in get_instance() is kept unchanged since that classmethod is synchronous and never awaits.

Changes

  • src/copaw/token_usage/manager.py: Add import asyncio, change _file_lock from threading.Lock() to asyncio.Lock(), change with to async with in record()

Test plan

  • ruff check passes
  • Concurrent record() calls from multiple coroutines no longer deadlock

Closes #1834

This contribution was developed with AI assistance (Claude Code + Codex).

TokenUsageManager.record() is an async method but used threading.Lock
for _file_lock, which blocks the entire event loop under concurrent
calls. Replace with asyncio.Lock and change `with` to `async with`.

The class-level threading.Lock in get_instance() is kept as-is since
that classmethod is synchronous and never awaits.

Closes agentscope-ai#1834

This contribution was developed with AI assistance (Claude Code + Codex).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@zhijianma zhijianma merged commit 2cd5466 into agentscope-ai:main Mar 20, 2026
38 checks passed
@mvanhorn
Copy link
Copy Markdown
Contributor Author

Thanks for the review.

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.

[Bug]: TokenUsageManager.record uses threading.Lock in async context, causing event loop lockup / deadlock under load

2 participants