2323from django_tasks .exceptions import InvalidTaskBackendError
2424from django_tasks .signals import task_finished , task_started
2525from django_tasks .task import DEFAULT_QUEUE_NAME
26+ from django_tasks .utils import get_random_id
2627
2728package_logger = logging .getLogger ("django_tasks" )
2829logger = logging .getLogger ("django_tasks.backends.database.db_worker" )
@@ -38,6 +39,7 @@ def __init__(
3839 backend_name : str ,
3940 startup_delay : bool ,
4041 max_tasks : Optional [int ],
42+ worker_id : str ,
4143 ):
4244 self .queue_names = queue_names
4345 self .process_all_queues = "*" in queue_names
@@ -51,6 +53,8 @@ def __init__(
5153 self .running_task = False
5254 self ._run_tasks = 0
5355
56+ self .worker_id = worker_id
57+
5458 def shutdown (self , signum : int , frame : Optional [FrameType ]) -> None :
5559 if not self .running :
5660 logger .warning (
@@ -82,11 +86,17 @@ def reset_signals(self) -> None:
8286 if hasattr (signal , "SIGQUIT" ):
8387 signal .signal (signal .SIGQUIT , signal .SIG_DFL )
8488
85- def start (self ) -> None :
86- logger .info ("Starting worker for queues=%s" , "," .join (self .queue_names ))
89+ def run (self ) -> None :
90+ self .configure_signals ()
91+
92+ logger .info (
93+ "Starting worker worker_id=%s queues=%s" ,
94+ self .worker_id ,
95+ "," .join (self .queue_names ),
96+ )
8797
8898 if self .startup_delay and self .interval :
89- # Add a random small delay before starting the loop to avoid a thundering herd
99+ # Add a random small delay before starting to avoid a thundering herd
90100 time .sleep (random .random ())
91101
92102 while self .running :
@@ -109,19 +119,24 @@ def start(self) -> None:
109119
110120 if task_result is not None :
111121 # "claim" the task, so it isn't run by another worker process
112- task_result .claim ()
122+ task_result .claim (self . worker_id )
113123
114124 if task_result is not None :
115125 self .run_task (task_result )
116126
117127 if self .batch and task_result is None :
118128 # If we're running in "batch" mode, terminate the loop (and thus the worker)
119- logger .info ("No more tasks to run - exiting gracefully." )
129+ logger .info (
130+ "No more tasks to run for worker_id=%s - exiting gracefully." ,
131+ self .worker_id ,
132+ )
120133 return None
121134
122135 if self .max_tasks is not None and self ._run_tasks >= self .max_tasks :
123136 logger .info (
124- "Run maximum tasks (%d) - exiting gracefully." , self ._run_tasks
137+ "Run maximum tasks (%d) on worker=%s - exiting gracefully." ,
138+ self ._run_tasks ,
139+ self .worker_id ,
125140 )
126141 return None
127142
@@ -199,6 +214,14 @@ def valid_max_tasks(val: str) -> int:
199214 return num
200215
201216
217+ def validate_worker_id (val : str ) -> str :
218+ if not val :
219+ raise ArgumentTypeError ("Worker id must not be empty" )
220+ if len (val ) > 64 :
221+ raise ArgumentTypeError ("Worker ids must be shorter than 64 characters" )
222+ return val
223+
224+
202225class Command (BaseCommand ):
203226 help = "Run a database background worker"
204227
@@ -249,6 +272,13 @@ def add_arguments(self, parser: ArgumentParser) -> None:
249272 type = valid_max_tasks ,
250273 help = "If provided, the maximum number of tasks the worker will execute before exiting." ,
251274 )
275+ parser .add_argument (
276+ "--worker-id" ,
277+ nargs = "?" ,
278+ type = validate_worker_id ,
279+ help = "Worker id. MUST be unique across worker pool (default: auto-generate)" ,
280+ default = get_random_id (),
281+ )
252282
253283 def configure_logging (self , verbosity : int ) -> None :
254284 if verbosity == 0 :
@@ -274,6 +304,7 @@ def handle(
274304 startup_delay : bool ,
275305 reload : bool ,
276306 max_tasks : Optional [int ],
307+ worker_id : str ,
277308 ** options : dict ,
278309 ) -> None :
279310 self .configure_logging (verbosity )
@@ -291,14 +322,15 @@ def handle(
291322 backend_name = backend_name ,
292323 startup_delay = startup_delay ,
293324 max_tasks = max_tasks ,
325+ worker_id = worker_id ,
294326 )
295327
296328 if reload :
297329 if os .environ .get (DJANGO_AUTORELOAD_ENV ) == "true" :
298330 # Only the child process should configure its signals
299331 worker .configure_signals ()
300332
301- run_with_reloader (worker .start )
333+ run_with_reloader (worker .run )
302334 else :
303335 worker .configure_signals ()
304- worker .start ()
336+ worker .run ()
0 commit comments