8
8
import anyio
9
9
from taskiq_dependencies import DependencyGraph
10
10
11
- from taskiq .abc .broker import AckableMessage , AsyncBroker
11
+ from taskiq .abc .broker import AsyncBroker
12
12
from taskiq .abc .middleware import TaskiqMiddleware
13
- from taskiq .acks import AcknowledgeType
13
+ from taskiq .acks import AckableMessage , AcknowledgeType , NackableMessage
14
14
from taskiq .context import Context
15
15
from taskiq .exceptions import NoResultError
16
- from taskiq .message import TaskiqMessage
16
+ from taskiq .message import MessageWithMetadata , TaskiqMessage , WrappedMessage
17
17
from taskiq .receiver .params_parser import parse_params
18
18
from taskiq .result import TaskiqResult
19
19
from taskiq .state import TaskiqState
@@ -58,6 +58,7 @@ def __init__(
58
58
on_exit : Optional [Callable [["Receiver" ], None ]] = None ,
59
59
max_tasks_to_execute : Optional [int ] = None ,
60
60
wait_tasks_timeout : Optional [float ] = None ,
61
+ max_attempts_at_message : Optional [int ] = None ,
61
62
) -> None :
62
63
self .broker = broker
63
64
self .executor = executor
@@ -72,6 +73,7 @@ def __init__(
72
73
self .known_tasks : Set [str ] = set ()
73
74
self .max_tasks_to_execute = max_tasks_to_execute
74
75
self .wait_tasks_timeout = wait_tasks_timeout
76
+ self .max_attempts_at_message = max_attempts_at_message
75
77
for task in self .broker .get_all_tasks ().values ():
76
78
self ._prepare_task (task .task_name , task .original_func )
77
79
self .sem : "Optional[asyncio.Semaphore]" = None
@@ -86,7 +88,7 @@ def __init__(
86
88
87
89
async def callback ( # noqa: C901, PLR0912
88
90
self ,
89
- message : Union [bytes , AckableMessage ],
91
+ message : Union [bytes , WrappedMessage ],
90
92
raise_err : bool = False ,
91
93
) -> None :
92
94
"""
@@ -101,7 +103,38 @@ async def callback( # noqa: C901, PLR0912
101
103
:param raise_err: raise an error if cannot save result in
102
104
result_backend.
103
105
"""
104
- message_data = message .data if isinstance (message , AckableMessage ) else message
106
+ message_data = (
107
+ message .message if isinstance (message , WrappedMessage ) else message
108
+ )
109
+ if isinstance (message , MessageWithMetadata ):
110
+ message_metadata = message .metadata
111
+ else :
112
+ message_metadata = None
113
+
114
+ delivery_count = message_metadata .delivery_count if message_metadata else None
115
+ if (
116
+ delivery_count
117
+ and self .max_attempts_at_message
118
+ and delivery_count >= self .max_attempts_at_message
119
+ ):
120
+ logger .error (
121
+ "Permitted number of attempts at processing message %s "
122
+ "has been exhausted after %s attempts." ,
123
+ message_data ,
124
+ self .max_attempts_at_message ,
125
+ )
126
+ if isinstance (
127
+ message ,
128
+ NackableMessage ,
129
+ ):
130
+ await maybe_awaitable (message .nack ())
131
+ elif isinstance (
132
+ message ,
133
+ AckableMessage ,
134
+ ):
135
+ await maybe_awaitable (message .ack ())
136
+ return
137
+
105
138
try :
106
139
taskiq_msg = self .broker .formatter .loads (message = message_data )
107
140
taskiq_msg .parse_labels ()
@@ -331,7 +364,7 @@ async def listen(self, finish_event: asyncio.Event) -> None: # pragma: no cover
331
364
if self .run_startup :
332
365
await self .broker .startup ()
333
366
logger .info ("Listening started." )
334
- queue : "asyncio.Queue[Union[bytes, AckableMessage ]]" = asyncio .Queue ()
367
+ queue : "asyncio.Queue[Union[bytes, WrappedMessage ]]" = asyncio .Queue ()
335
368
336
369
async with anyio .create_task_group () as gr :
337
370
gr .start_soon (self .prefetcher , queue , finish_event )
@@ -342,7 +375,7 @@ async def listen(self, finish_event: asyncio.Event) -> None: # pragma: no cover
342
375
343
376
async def prefetcher (
344
377
self ,
345
- queue : "asyncio.Queue[Union[bytes, AckableMessage ]]" ,
378
+ queue : "asyncio.Queue[Union[bytes, WrappedMessage ]]" ,
346
379
finish_event : asyncio .Event ,
347
380
) -> None :
348
381
"""
@@ -354,7 +387,7 @@ async def prefetcher(
354
387
fetched_tasks : int = 0
355
388
iterator = self .broker .listen ()
356
389
current_message : asyncio .Task [
357
- Union [bytes , AckableMessage ]
390
+ Union [bytes , WrappedMessage ]
358
391
] = asyncio .create_task (
359
392
iterator .__anext__ (), # type: ignore
360
393
)
@@ -394,7 +427,7 @@ async def prefetcher(
394
427
395
428
async def runner (
396
429
self ,
397
- queue : "asyncio.Queue[Union[bytes, AckableMessage ]]" ,
430
+ queue : "asyncio.Queue[Union[bytes, WrappedMessage ]]" ,
398
431
) -> None :
399
432
"""
400
433
Run tasks.
0 commit comments