Skip to content

feat: add per-team concurrency guard to TaskClaimer.advance_dag#294

Merged
mvillmow merged 1 commit into
mainfrom
131-auto-impl
Apr 23, 2026
Merged

feat: add per-team concurrency guard to TaskClaimer.advance_dag#294
mvillmow merged 1 commit into
mainfrom
131-auto-impl

Conversation

@mvillmow

Copy link
Copy Markdown
Collaborator

Summary

  • Adds TaskClaimer class at src/keystone/task_claimer.py with a two-layer per-team concurrency guard
  • _advancing: set[str] provides an O(1) coalesce/skip check: concurrent calls for the same team return [] immediately with a log message instead of queuing
  • _team_locks: dict[str, asyncio.Lock] provides mutual exclusion over the full fetch→find→claim cycle
  • async with + finally guarantee the lock and _advancing entry are always released, even when get_tasks or claim_task raises

Test plan

  • test_advance_dag_claims_ready_tasks — basic happy path, all tasks claimed
  • test_advance_dag_empty_team_returns_empty — no tasks, no claim attempts
  • test_advance_dag_partial_claim_failures — failed claims excluded from result
  • test_concurrent_advance_dag_coalesced — second same-team call skipped while first is in-flight; get_tasks called exactly once
  • test_concurrent_advance_dag_different_teams_parallel — different teams proceed independently
  • test_advance_dag_lock_released_on_error — exception in get_tasks does not deadlock subsequent calls
  • test_sequential_calls_same_team_both_execute — sequential (non-concurrent) same-team calls both execute normally

All 7 tests pass: python3 -m pytest tests/test_task_claimer.py -v

Closes #131

🤖 Generated with Claude Code

Add TaskClaimer class in src/keystone/task_claimer.py with a per-team
asyncio.Lock and coalesce/skip mechanism to prevent concurrent advance_dag
calls for the same team from racing each other.

- Two-layer guard: _advancing set for O(1) coalesce check + per-team
  asyncio.Lock for mutual exclusion over the full fetch->find->claim cycle
- Concurrent calls for the same team are skipped (not queued) with a log
  message, since the in-flight call already sees the latest state
- async with + finally ensure lock and set are always released on exceptions
- 7 unit tests covering basic claiming, coalescing, parallelism across teams,
  error recovery, and sequential reuse

Closes #131

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread tests/test_task_claimer.py
@github-actions

Copy link
Copy Markdown

Security Scan Results

  • ⚠️ Secret Scanning: No results available
  • ✅ SAST: Completed (check Security tab for details)
  • ✅ Dependency Scanning: Completed
  • ✅ C++ Static Analysis: Completed
  • ✅ Docker Image Scanning: 0 high, 21 medium vulnerabilities (acceptable)

Recommendations

  • Review findings in the GitHub Security tab
  • Check artifact uploads for detailed reports
  • Address critical Docker vulnerabilities immediately

Workflow: Security Scanning

@github-actions

Copy link
Copy Markdown

CI Summary

Check Status
Code Quality ✅ success
Sanitizers (ASan, UBSan, TSan, LSan, MSan) ✅ success
Benchmarks ✅ success
Coverage ✅ success

View full run

@mvillmow
mvillmow enabled auto-merge (rebase) April 23, 2026 14:16
@mvillmow
mvillmow merged commit d92c9dc into main Apr 23, 2026
20 checks passed
@mvillmow
mvillmow deleted the 131-auto-impl branch April 23, 2026 14:23
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.

[Improvement] Add concurrency guard to prevent parallel advance_dag for same team

1 participant