@@ -60,6 +60,10 @@ class BaseWorker(RedisMixin):
60
60
health_check_interval = 60
61
61
health_check_key = b'arq:health-check'
62
62
63
+ #: Mostly used in tests; if true actors and the redis pool will not be closed at the end of run()
64
+ # allowing reuse of the worker, eg. ``worker.run()`` can be called multiple times.
65
+ reusable = False
66
+
63
67
def __init__ (self , * ,
64
68
burst : bool = False ,
65
69
shadows : list = None ,
@@ -92,7 +96,7 @@ def __init__(self, *,
92
96
signal .signal (signal .SIGTERM , self .handle_sig )
93
97
signal .signal (SIG_PROXY , self .handle_proxy_signal )
94
98
super ().__init__ (** kwargs ) # type: ignore # TODO
95
- self ._closing_lock = asyncio .Lock (loop = self .loop )
99
+ self ._shutdown_lock = asyncio .Lock (loop = self .loop )
96
100
97
101
async def shadow_factory (self ) -> list :
98
102
"""
@@ -142,6 +146,7 @@ async def run(self):
142
146
Main entry point for the the worker which initialises shadows, checks they look ok then runs ``work`` to
143
147
perform jobs.
144
148
"""
149
+ self ._stopped = False
145
150
work_logger .info ('Initialising work manager, burst mode: %s' , self ._burst_mode )
146
151
147
152
shadows = await self .shadow_factory ()
@@ -170,7 +175,7 @@ async def run(self):
170
175
try :
171
176
await self .work ()
172
177
finally :
173
- await self .close ()
178
+ await self .shutdown ()
174
179
if self ._task_exception :
175
180
work_logger .error ('Found task exception "%s"' , self ._task_exception )
176
181
raise self ._task_exception
@@ -241,6 +246,7 @@ async def _check_health(self):
241
246
def check_health (cls , ** kwargs ):
242
247
"""
243
248
Run a health check on the worker return the appropriate exit code.
249
+
244
250
:return: 0 if successful, 1 if not
245
251
"""
246
252
self = cls (** kwargs )
@@ -333,17 +339,19 @@ def handle_execute_exc(cls, started_at, exc, j):
333
339
exc_type = exc .__class__ .__name__
334
340
jobs_logger .exception ('%-4s ran in%7.3fs ! %s: %s' , j .queue , timestamp () - started_at , j , exc_type )
335
341
336
- async def close (self ):
337
- with await self ._closing_lock :
338
- if self ._closed :
339
- return
342
+ async def shutdown (self ):
343
+ with await self ._shutdown_lock :
340
344
if self ._pending_tasks :
341
345
work_logger .info ('shutting down worker, waiting for %d jobs to finish' , len (self ._pending_tasks ))
342
346
await asyncio .wait (self ._pending_tasks , loop = self .loop )
343
347
t = (timestamp () - self .start ) if self .start else 0
344
348
work_logger .info ('shutting down worker after %0.3fs ◆ %d jobs done ◆ %d failed ◆ %d timed out' ,
345
349
t , self .jobs_complete , self .jobs_failed , self .jobs_timed_out )
350
+ if not self .reusable :
351
+ await self .close ()
346
352
353
+ async def close (self ):
354
+ if not self ._closed :
347
355
if self ._shadow_lookup :
348
356
await asyncio .gather (* [s .close (True ) for s in self ._shadow_lookup .values ()], loop = self .loop )
349
357
await super ().close ()
0 commit comments