Skip to content

Commit 6871ea4

Browse files
authored
Split execution limit in concurrency and throttle parameters (#6013)
* Split execution limit in concurrency and throttle parameters Currently the execution limit combines two ortogonal features: Limit concurrency and throttle execution. This change separates the two features, allowing for more flexible configuration of job execution. Ultimately I want to get rid of the old limit parameter. But for ease of review and migration, I'd like to do this in two steps: First introduce the new parameters, and map the old limit parameters to the new parameters. Then, in a second step, remove the old limit parameter and migrate all users to the new concurrency and throttle parameters as needed. * Introduce common lock release method * Fix THROTTLE_WAIT behavior The concurrency QUEUE does not really QUEUE throttle limits. * Add documentation for new concurrency/throttle Job options * Handle group options for concurrency and throttle separately * Fix GROUP_THROTTLE_WAIT concurrency setting We need to use the QUEUE concurrency setting instead of GROUP_QUEUE for the GROUP_THROTTLE_WAIT execution limit. Otherwise the test_jobs_decorator.py::test_execution_limit_group_throttle_wait test deadlocks. The reason this deadlocks is because GROUP_QUEUE concurrency doesn't really work because we only can release a group lock if the job is actually running. Or put differently, throttling isn't supported with GROUP_* concurrency options. * Prevent using any throttling with group concurrency The group concurrency modes (reject and queue) are not compatible with any throttling, since we currently can't unlock the group lock when a job doesn't get started (which is the case when throttling is applied). * Fix commit in group rate limit * Explain the deadlock issue with group locks in code * Handle locking correctly on throttle limit exceptions * Introduce pytest for new job decorator combinations
1 parent cf77ab2 commit 6871ea4

File tree

3 files changed

+324
-130
lines changed

3 files changed

+324
-130
lines changed

supervisor/jobs/const.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,60 @@ class JobCondition(StrEnum):
3434
SUPERVISOR_UPDATED = "supervisor_updated"
3535

3636

37+
class JobConcurrency(StrEnum):
38+
"""Job concurrency control.
39+
40+
Controls how many instances of a job can run simultaneously.
41+
42+
Individual Concurrency (applies to each method separately):
43+
- REJECT: Fail immediately if another instance is already running
44+
- QUEUE: Wait for the current instance to finish, then run
45+
46+
Group Concurrency (applies across all methods on a JobGroup):
47+
- GROUP_REJECT: Fail if ANY job is running on the JobGroup
48+
- GROUP_QUEUE: Wait for ANY running job on the JobGroup to finish
49+
50+
JobGroup Behavior:
51+
- All methods on the same JobGroup instance share a single lock
52+
- Methods can call other methods on the same group without deadlock
53+
- Uses the JobGroup.group_name for coordination
54+
- Requires the class to inherit from JobGroup
55+
"""
56+
57+
REJECT = "reject" # Fail if already running (was ONCE)
58+
QUEUE = "queue" # Wait if already running (was SINGLE_WAIT)
59+
GROUP_REJECT = "group_reject" # Was GROUP_ONCE
60+
GROUP_QUEUE = "group_queue" # Was GROUP_WAIT
61+
62+
63+
class JobThrottle(StrEnum):
64+
"""Job throttling control.
65+
66+
Controls how frequently jobs can be executed.
67+
68+
Individual Throttling (each method has its own throttle state):
69+
- THROTTLE: Skip execution if called within throttle_period
70+
- RATE_LIMIT: Allow up to throttle_max_calls within throttle_period, then fail
71+
72+
Group Throttling (all methods on a JobGroup share throttle state):
73+
- GROUP_THROTTLE: Skip if ANY method was called within throttle_period
74+
- GROUP_RATE_LIMIT: Allow up to throttle_max_calls total across ALL methods
75+
76+
JobGroup Behavior:
77+
- All methods on the same JobGroup instance share throttle counters/timers
78+
- Uses the JobGroup.group_name as the key for tracking state
79+
- If one method is throttled, other methods may also be throttled
80+
- Requires the class to inherit from JobGroup
81+
"""
82+
83+
THROTTLE = "throttle" # Skip if called too frequently
84+
RATE_LIMIT = "rate_limit" # Rate limiting with max calls per period
85+
GROUP_THROTTLE = "group_throttle" # Group version of THROTTLE
86+
GROUP_RATE_LIMIT = "group_rate_limit" # Group version of RATE_LIMIT
87+
88+
3789
class JobExecutionLimit(StrEnum):
38-
"""Job Execution limits."""
90+
"""Job Execution limits - DEPRECATED: Use JobConcurrency and JobThrottle instead."""
3991

4092
ONCE = "once"
4193
SINGLE_WAIT = "single_wait"

0 commit comments

Comments
 (0)