feat: warn when deduplication_key_fields are missing from task kwargs (#68)

This commit is contained in:
d3vyce
2026-06-27 14:19:42 +02:00
committed by GitHub
parent 764288c924
commit 7326f4693f
3 changed files with 44 additions and 5 deletions
+4
View File
@@ -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 ## Opting out per task
```python ```python
+13 -5
View File
@@ -144,11 +144,19 @@ class RedisDeduplicationMiddleware(TaskiqMiddleware):
key_fields = parse_list_label( key_fields = parse_list_label(
message.labels.get(DEDUP_KEY_FIELDS_LABEL), DEDUP_KEY_FIELDS_LABEL message.labels.get(DEDUP_KEY_FIELDS_LABEL), DEDUP_KEY_FIELDS_LABEL
) )
kwargs = ( if key_fields is not None:
{k: v for k, v in message.kwargs.items() if k in key_fields} missing = [field for field in key_fields if field not in message.kwargs]
if key_fields is not None if missing:
else message.kwargs 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: try:
payload = json.dumps( payload = json.dumps(
{"task": message.task_name, "kwargs": kwargs}, {"task": message.task_name, "kwargs": kwargs},
+27
View File
@@ -605,6 +605,33 @@ class TestLabelTypeParsing:
assert any("{'a': 1}" in r.message for r in caplog.records) assert any("{'a': 1}" in r.message for r in caplog.records)
assert key is not None 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): def test_stringified_key_fields_parsed_correctly(self, middleware, make_message):
# taskiq's prepare_label() stringifies ["a", "b"] → "['a', 'b']" before pre_send # taskiq's prepare_label() stringifies ["a", "b"] → "['a', 'b']" before pre_send
m1 = make_message( m1 = make_message(