- Remove trailing whitespace from docstring in utils.py (W293)
- Fix test mocking to use class-level patches instead of instance-level
patches so they work with crew.copy() in kickoff_for_each()
- Adjust timing thresholds slightly to account for CI variance
Co-Authored-By: João <joao@crewai.com>
This commit fixes the threading issue where kickoff_for_each() would hang
indefinitely after successful completion. The root cause was that event
handlers scheduled in the ThreadPoolExecutor were not being awaited,
leaving non-daemon worker threads active and preventing process exit.
Changes:
1. Added _wait_for_event_handlers() helper method to safely wait on event
bus futures with timeout (30s default) and proper error handling
2. Modified kickoff() to wait on all three lifecycle event emissions:
- CrewKickoffStartedEvent
- CrewKickoffCompletedEvent
- CrewKickoffFailedEvent
3. Added is_tracing_disabled() helper to respect CREWAI_DISABLE_TRACING,
CREWAI_DISABLE_TRACKING, and OTEL_SDK_DISABLED environment variables
4. Updated tracing enable logic to check disable flags first, preventing
tracing setup when explicitly disabled
5. Added comprehensive tests covering:
- kickoff_for_each() waiting for event handlers
- kickoff() waiting for event handlers on error
- Tracing disable flags being respected
This ensures that each kickoff() call fully processes its event handlers
before returning, preventing the accumulation of pending executor tasks
that would block process exit in kickoff_for_each().
Fixes#3871
Co-Authored-By: João <joao@crewai.com>