threadmill 0.8.2__tar.gz → 0.8.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {threadmill-0.8.2 → threadmill-0.8.3}/PKG-INFO +1 -1
  2. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/_version.py +3 -3
  3. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/executor.py +22 -10
  4. {threadmill-0.8.2 → threadmill-0.8.3}/LICENSE +0 -0
  5. {threadmill-0.8.2 → threadmill-0.8.3}/README.md +0 -0
  6. {threadmill-0.8.2 → threadmill-0.8.3}/pyproject.toml +0 -0
  7. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/__init__.py +0 -0
  8. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/apps.py +0 -0
  9. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/__init__.py +0 -0
  10. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/base.py +0 -0
  11. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/lua/acknowledge.lua +0 -0
  12. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/lua/acquire.lua +0 -0
  13. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/lua/mover.lua +0 -0
  14. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/lua/reaper.lua +0 -0
  15. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/backends/redis.py +0 -0
  16. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/exceptions.py +0 -0
  17. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/inspector/__init__.py +0 -0
  18. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/inspector/app.py +0 -0
  19. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/inspector/inspector.scss +0 -0
  20. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/inspector/screens.py +0 -0
  21. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/inspector/telemetry.py +0 -0
  22. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/management/__init__.py +0 -0
  23. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/management/commands/__init__.py +0 -0
  24. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/management/commands/threadmill.py +0 -0
  25. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/retry.py +0 -0
  26. {threadmill-0.8.2 → threadmill-0.8.3}/threadmill/signals.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: threadmill
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: The most reliable backend for Django's task framework.
5
5
  Keywords: Django,tasks,worker
6
6
  Author-email: Johannes Maron <johannes@maron.family>
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.8.2'
22
- __version_tuple__ = version_tuple = (0, 8, 2)
21
+ __version__ = version = '0.8.3'
22
+ __version_tuple__ = version_tuple = (0, 8, 3)
23
23
 
24
- __commit_id__ = commit_id = 'gdff213884'
24
+ __commit_id__ = commit_id = 'g0ef712225'
@@ -12,7 +12,6 @@ import socket
12
12
  import sys
13
13
  import sysconfig
14
14
  import threading
15
- import time
16
15
  import typing
17
16
  from concurrent.futures import Future, ThreadPoolExecutor
18
17
  from inspect import iscoroutinefunction
@@ -129,7 +128,12 @@ class TaskExecutor:
129
128
  prefetch_count: int | None = None
130
129
  poll_interval: datetime.timedelta = datetime.timedelta(seconds=0.01)
131
130
  poll_max_interval: datetime.timedelta = datetime.timedelta(seconds=1)
132
- is_publishing: bool = dataclasses.field(default=True, init=False)
131
+ shutdown_requested: threading.Event = dataclasses.field(
132
+ default_factory=threading.Event, init=False
133
+ )
134
+ pool_maintainer: threading.Thread | None = dataclasses.field(
135
+ default=None, init=False
136
+ )
133
137
  worker_processes: list[WorkerProcess] = dataclasses.field(
134
138
  default_factory=list, init=False
135
139
  )
@@ -176,9 +180,10 @@ class TaskExecutor:
176
180
  self.worker_processes = [
177
181
  self.create_worker_process() for _ in range(self.process_count)
178
182
  ]
179
- threads = [
180
- threading.Thread(target=self.maintain_worker_pool, daemon=True),
181
- ]
183
+ self.pool_maintainer = threading.Thread(
184
+ target=self.maintain_worker_pool, daemon=True
185
+ )
186
+ threads = [self.pool_maintainer]
182
187
  if self.backend.broker_class:
183
188
  self.broker = self.backend.broker_class(self.backend)
184
189
  threads.append(self.broker)
@@ -189,17 +194,24 @@ class TaskExecutor:
189
194
  thread.join()
190
195
 
191
196
  def shutdown(self) -> None:
192
- """Stop queue consumption and terminate all worker processes."""
197
+ """Stop pool maintenance first, then queue consumption and all workers."""
193
198
  logger.info("Shutting down task executor")
199
+ self.shutdown_requested.set()
200
+ if (
201
+ self.pool_maintainer is not None
202
+ and self.pool_maintainer.is_alive()
203
+ # The maintainer calls shutdown() itself on exit_empty.
204
+ and self.pool_maintainer is not threading.current_thread()
205
+ ):
206
+ self.pool_maintainer.join()
194
207
  if self.broker is not None:
195
208
  self.broker.shutdown()
196
209
  with ThreadPoolExecutor(max_workers=self.process_count) as executor:
197
210
  executor.map(lambda worker: worker.shutdown(), self.worker_processes)
198
- self.is_publishing = False
199
211
 
200
212
  def maintain_worker_pool(self) -> None:
201
- """Restart worker processes that have exited."""
202
- while self.is_publishing:
213
+ """Restart worker processes that have exited, until shutdown is requested."""
214
+ while not self.shutdown_requested.is_set():
203
215
  all_dead = True
204
216
  for index, worker in enumerate(self.worker_processes):
205
217
  if worker.is_alive():
@@ -218,7 +230,7 @@ class TaskExecutor:
218
230
  if all_dead and self.exit_empty:
219
231
  self.shutdown()
220
232
  return
221
- time.sleep(1)
233
+ self.shutdown_requested.wait(1)
222
234
 
223
235
 
224
236
  class WorkerProcess(multiprocessing.Process):
File without changes
File without changes
File without changes