Skip to content

Token tracking race condition in threading-based async_execution #4168

@Devasy

Description

@Devasy

Problem

The per-task token tracking feature has a race condition for tasks using threading-based async_execution (i.e., task.async_execution=True with synchronous crew.kickoff()).

Current Behavior

When multiple tasks with async_execution=True are executed by the same agent:

  1. tokens_before is captured when the task is queued and submitted to the thread pool
  2. Tasks run concurrently in threads
  3. All concurrent tasks capture similar tokens_before values
  4. tokens_after is captured sequentially in _process_async_tasks after calling future.result()
  5. Later tasks get credited with tokens from earlier tasks that ran in parallel

Example

# Agent starts with 100 tokens used
- Task A queued: tokens_before = 100, starts running in thread
- Task B queued: tokens_before = 100, starts running in thread (nearly same time)
- Task A completes using 50 tokens (agent now at 150)
- Task B completes using 30 tokens (agent now at 180)

# Sequential processing in _process_async_tasks:
- Task A: tokens_after = 180, delta = 80 (WRONG - includes Task B's 30 tokens)
- Task B: tokens_after = 180, delta = 80 (WRONG - same as Task A)

Root Cause

The threading-based task.execute_async() uses concurrent.futures.ThreadPoolExecutor, which makes it difficult to wrap the execution to capture tokens immediately after completion within the thread.

Potential Solutions

  1. Wrapper function in thread: Modify execute_async to accept a wrapper function that captures tokens immediately after task completion within the thread
  2. Agent-level locking: Add a lock per agent to ensure only one async task per agent runs at a time (may impact performance)
  3. Documentation: Document the limitation and recommend using akickoff() for accurate async task token tracking
  4. Deprecation path: Consider deprecating threading-based async_execution in favor of native async

Related

Impact

  • Medium: Affects token cost tracking accuracy when using async_execution=True with kickoff()
  • Workaround: Use akickoff() instead, or avoid concurrent tasks from same agent

Additional Context

This issue only affects per-task token metrics. Crew-level and per-agent total metrics are still accurate as they're calculated after all tasks complete.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions