mirror of
https://github.com/d3vyce/taskiq-deduplication.git
synced 2026-08-04 19:14:07 +00:00
feat: warn when deduplication_key_fields are missing from task kwargs (#68)
This commit is contained in:
@@ -178,6 +178,10 @@ async def send_welcome_email(user_id: int, locale: str) -> None:
|
||||
...
|
||||
```
|
||||
|
||||
If a listed field is absent from a task's kwargs, it is dropped from the
|
||||
fingerprint and a warning is logged, since this can make genuinely different
|
||||
calls collide on the same lock.
|
||||
|
||||
## Opting out per task
|
||||
|
||||
```python
|
||||
|
||||
@@ -144,11 +144,19 @@ class RedisDeduplicationMiddleware(TaskiqMiddleware):
|
||||
key_fields = parse_list_label(
|
||||
message.labels.get(DEDUP_KEY_FIELDS_LABEL), DEDUP_KEY_FIELDS_LABEL
|
||||
)
|
||||
kwargs = (
|
||||
{k: v for k, v in message.kwargs.items() if k in key_fields}
|
||||
if key_fields is not None
|
||||
else message.kwargs
|
||||
if key_fields is not None:
|
||||
missing = [field for field in key_fields if field not in message.kwargs]
|
||||
if missing:
|
||||
logger.warning(
|
||||
"Task %s requested deduplication_key_fields %r but they are "
|
||||
"absent from kwargs; they are dropped from the fingerprint, which "
|
||||
"may cause distinct calls to collide.",
|
||||
message.task_name,
|
||||
missing,
|
||||
)
|
||||
kwargs = {k: v for k, v in message.kwargs.items() if k in key_fields}
|
||||
else:
|
||||
kwargs = message.kwargs
|
||||
try:
|
||||
payload = json.dumps(
|
||||
{"task": message.task_name, "kwargs": kwargs},
|
||||
|
||||
@@ -605,6 +605,33 @@ class TestLabelTypeParsing:
|
||||
assert any("{'a': 1}" in r.message for r in caplog.records)
|
||||
assert key is not None
|
||||
|
||||
async def test_missing_key_fields_warns(self, middleware, make_message, caplog):
|
||||
import logging
|
||||
|
||||
msg = make_message(
|
||||
kwargs={"order_id": 1},
|
||||
labels={DEDUP_KEY_FIELDS_LABEL: ["user_id", "order_id"]},
|
||||
)
|
||||
with caplog.at_level(logging.WARNING, logger="taskiq_deduplication.middleware"):
|
||||
key = middleware._build_deduplication_key(msg)
|
||||
assert any("user_id" in r.message for r in caplog.records)
|
||||
# the field that is present must not be reported as missing
|
||||
assert not any("order_id" in r.message for r in caplog.records)
|
||||
assert key is not None
|
||||
|
||||
async def test_present_key_fields_do_not_warn(
|
||||
self, middleware, make_message, caplog
|
||||
):
|
||||
import logging
|
||||
|
||||
msg = make_message(
|
||||
kwargs={"user_id": 1, "order_id": 2},
|
||||
labels={DEDUP_KEY_FIELDS_LABEL: ["user_id"]},
|
||||
)
|
||||
with caplog.at_level(logging.WARNING, logger="taskiq_deduplication.middleware"):
|
||||
middleware._build_deduplication_key(msg)
|
||||
assert not any("absent from kwargs" in r.message for r in caplog.records)
|
||||
|
||||
def test_stringified_key_fields_parsed_correctly(self, middleware, make_message):
|
||||
# taskiq's prepare_label() stringifies ["a", "b"] → "['a', 'b']" before pre_send
|
||||
m1 = make_message(
|
||||
|
||||
Reference in New Issue
Block a user