Skip to content

Commit 5b60bc8

Browse files
dmartinsteinitzu
authored andcommitted
Permit empty unique_on kwarg to lock on name only
1 parent b334529 commit 5b60bc8

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ task2 = do_something.delay(username='bob', otherarg=100) # this is a duplicate
138138
assert task1 == task2
139139
```
140140

141+
Specify an empty list to consider the task name only.
142+
141143
### raise\_on\_duplicate
142144

143145
When this option is enabled the task's `delay` and `apply_async` method will raise a `DuplicateTaskError` exception when attempting to spawn a duplicate task instead of returning the existing task's `AsyncResult`

celery_singleton/singleton.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,16 @@ def generate_lock(self, task_name, task_args=None, task_kwargs=None):
5757
unique_on = self.unique_on
5858
task_args = task_args or []
5959
task_kwargs = task_kwargs or {}
60-
if unique_on:
60+
if unique_on is not None:
6161
if isinstance(unique_on, str):
6262
unique_on = [unique_on]
63-
sig = inspect.signature(self.run)
64-
bound = sig.bind(*task_args, **task_kwargs).arguments
65-
63+
if not any(unique_on):
64+
unique_kwargs = {}
65+
else:
66+
sig = inspect.signature(self.run)
67+
bound = sig.bind(*task_args, **task_kwargs).arguments
68+
unique_kwargs = {key: bound[key] for key in unique_on}
6669
unique_args = []
67-
unique_kwargs = {key: bound[key] for key in unique_on}
6870
else:
6971
unique_args = task_args
7072
unique_kwargs = task_kwargs

tests/test_singleton.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,34 @@ def unique_on_kwargs_task(a, b=2, c=3, d=4):
232232
assert mock_gen.call_count == 2
233233
assert [list(a) for a in mock_gen.call_args_list] == expected_args
234234

235+
@mock.patch.object(
236+
util, "generate_lock", autospec=True, side_effect=util.generate_lock
237+
)
238+
def test__unique_on_empty__lock_on_task_name_only(
239+
self, mock_gen, scoped_app, celery_session_worker
240+
):
241+
with scoped_app as app:
242+
243+
@celery_session_worker.app.task(base=Singleton, unique_on=[])
244+
def unique_on_empty_task(a, b=2, c=3, d=4):
245+
return a * b * c * d
246+
247+
celery_session_worker.reload() # So task is registered
248+
249+
result = unique_on_empty_task.delay(2, b=3, c=4, d=5)
250+
251+
result.get()
252+
time.sleep(0.05) # Small delay for on_success
253+
254+
expected_args = [
255+
[
256+
(unique_on_empty_task.name, [], {}),
257+
{"key_prefix": unique_on_empty_task.singleton_config.key_prefix},
258+
]
259+
] * 2
260+
assert mock_gen.call_count == 2
261+
assert [list(a) for a in mock_gen.call_args_list] == expected_args
262+
235263
@mock.patch.object(
236264
util, "generate_lock", autospec=True, side_effect=util.generate_lock
237265
)

0 commit comments

Comments
 (0)