tasktiger 0.26.3__tar.gz → 0.27.0__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 (55) hide show
  1. {tasktiger-0.26.3/tasktiger.egg-info → tasktiger-0.27.0}/PKG-INFO +13 -1
  2. {tasktiger-0.26.3 → tasktiger-0.27.0}/README.rst +12 -0
  3. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/__init__.py +1 -1
  4. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/stats.py +12 -0
  5. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/worker.py +9 -3
  6. {tasktiger-0.26.3 → tasktiger-0.27.0/tasktiger.egg-info}/PKG-INFO +13 -1
  7. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_workers.py +37 -0
  8. {tasktiger-0.26.3 → tasktiger-0.27.0}/LICENSE +0 -0
  9. {tasktiger-0.26.3 → tasktiger-0.27.0}/MANIFEST.in +0 -0
  10. {tasktiger-0.26.3 → tasktiger-0.27.0}/pyproject.toml +0 -0
  11. {tasktiger-0.26.3 → tasktiger-0.27.0}/setup.cfg +0 -0
  12. {tasktiger-0.26.3 → tasktiger-0.27.0}/setup.py +0 -0
  13. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/_internal.py +0 -0
  14. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/exceptions.py +0 -0
  15. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/executor.py +0 -0
  16. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/flask_script.py +0 -0
  17. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/logging.py +0 -0
  18. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/lua/move_task.lua +0 -0
  19. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/lua/semaphore.lua +0 -0
  20. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/migrations.py +0 -0
  21. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/redis_scripts.py +0 -0
  22. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/redis_semaphore.py +0 -0
  23. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/retry.py +0 -0
  24. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/rollbar.py +0 -0
  25. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/runner.py +0 -0
  26. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/schedule.py +0 -0
  27. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/task.py +0 -0
  28. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/tasktiger.py +0 -0
  29. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/test_helpers.py +0 -0
  30. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/timeouts.py +0 -0
  31. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/types.py +0 -0
  32. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger/utils.py +0 -0
  33. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger.egg-info/SOURCES.txt +0 -0
  34. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger.egg-info/dependency_links.txt +0 -0
  35. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger.egg-info/entry_points.txt +0 -0
  36. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger.egg-info/requires.txt +0 -0
  37. {tasktiger-0.26.3 → tasktiger-0.27.0}/tasktiger.egg-info/top_level.txt +0 -0
  38. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/__init__.py +0 -0
  39. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/config.py +0 -0
  40. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/conftest.py +0 -0
  41. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/tasks.py +0 -0
  42. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/tasks_periodic.py +0 -0
  43. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_base.py +0 -0
  44. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_context_manager.py +0 -0
  45. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_lazy_init.py +0 -0
  46. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_logging.py +0 -0
  47. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_migrations.py +0 -0
  48. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_periodic.py +0 -0
  49. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_queue_size.py +0 -0
  50. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_redis_scripts.py +0 -0
  51. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_semaphore.py +0 -0
  52. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_stats.py +0 -0
  53. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/test_task.py +0 -0
  54. {tasktiger-0.26.3 → tasktiger-0.27.0}/tests/utils.py +0 -0
  55. {tasktiger-0.26.3 → tasktiger-0.27.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tasktiger
3
- Version: 0.26.3
3
+ Version: 0.27.0
4
4
  Summary: Python task queue
5
5
  Home-page: http://github.com/closeio/tasktiger
6
6
  License: MIT
@@ -212,6 +212,18 @@ decorate and queue tasks. The constructor takes the following arguments:
212
212
  given queues (and their subqueues), unless explicit queues are passed to
213
213
  the command line.
214
214
 
215
+ - ``STATS_INTERVAL``
216
+
217
+ Interval in seconds between worker task runtime statistics (default: 60).
218
+ Set to 0 to disable the stats thread and its callbacks. Queue maintenance
219
+ can occupy a worker outside task-execution statistics. When enabled,
220
+ ``StatsThread.report_maintenance_start()`` and ``report_maintenance_end()``
221
+ bracket the combined scheduled-task promotion and expired-task recovery
222
+ pass, with the end callback called even if either operation raises.
223
+ The hooks allow custom instrumentation; their defaults are no-ops and do
224
+ not change task runtime or utilization statistics. No maintenance callbacks
225
+ run when maintenance is not due or the worker is stopping.
226
+
215
227
  - ``setup_structlog``
216
228
 
217
229
  If set to True, sets up structured logging using ``structlog`` when
@@ -182,6 +182,18 @@ decorate and queue tasks. The constructor takes the following arguments:
182
182
  given queues (and their subqueues), unless explicit queues are passed to
183
183
  the command line.
184
184
 
185
+ - ``STATS_INTERVAL``
186
+
187
+ Interval in seconds between worker task runtime statistics (default: 60).
188
+ Set to 0 to disable the stats thread and its callbacks. Queue maintenance
189
+ can occupy a worker outside task-execution statistics. When enabled,
190
+ ``StatsThread.report_maintenance_start()`` and ``report_maintenance_end()``
191
+ bracket the combined scheduled-task promotion and expired-task recovery
192
+ pass, with the end callback called even if either operation raises.
193
+ The hooks allow custom instrumentation; their defaults are no-ops and do
194
+ not change task runtime or utilization statistics. No maintenance callbacks
195
+ run when maintenance is not due or the worker is stopping.
196
+
185
197
  - ``setup_structlog``
186
198
 
187
199
  If set to True, sets up structured logging using ``structlog`` when
@@ -12,7 +12,7 @@ from .task import Task
12
12
  from .tasktiger import TaskTiger, run_worker
13
13
  from .worker import Worker
14
14
 
15
- __version__ = "0.26.3"
15
+ __version__ = "0.27.0"
16
16
  __all__ = [
17
17
  "TaskTiger",
18
18
  "Worker",
@@ -39,6 +39,18 @@ class StatsThread(threading.Thread):
39
39
  self._task_running = False
40
40
  self._task_start_time = None
41
41
 
42
+ def report_maintenance_start(self) -> None:
43
+ """Signal the start of scheduled-task promotion and expired-task recovery.
44
+
45
+ The default is a no-op and does not alter task statistics.
46
+ """
47
+
48
+ def report_maintenance_end(self) -> None:
49
+ """Signal the end of scheduled-task promotion and expired-task recovery.
50
+
51
+ The default is a no-op and does not alter task statistics.
52
+ """
53
+
42
54
  def compute_stats(self) -> None:
43
55
  now = time.monotonic()
44
56
 
@@ -867,9 +867,15 @@ class Worker:
867
867
  time.time() - self._last_task_check > self.config["SELECT_TIMEOUT"]
868
868
  and not self._stop_requested
869
869
  ):
870
- self._worker_queue_scheduled_tasks()
871
- self._worker_queue_expired_tasks()
872
- self._last_task_check = time.time()
870
+ if self.stats_thread:
871
+ self.stats_thread.report_maintenance_start()
872
+ try:
873
+ self._worker_queue_scheduled_tasks()
874
+ self._worker_queue_expired_tasks()
875
+ self._last_task_check = time.time()
876
+ finally:
877
+ if self.stats_thread:
878
+ self.stats_thread.report_maintenance_end()
873
879
 
874
880
  def _queue_periodic_tasks(self) -> None:
875
881
  # Only queue periodic tasks for queues this worker is responsible
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tasktiger
3
- Version: 0.26.3
3
+ Version: 0.27.0
4
4
  Summary: Python task queue
5
5
  Home-page: http://github.com/closeio/tasktiger
6
6
  License: MIT
@@ -212,6 +212,18 @@ decorate and queue tasks. The constructor takes the following arguments:
212
212
  given queues (and their subqueues), unless explicit queues are passed to
213
213
  the command line.
214
214
 
215
+ - ``STATS_INTERVAL``
216
+
217
+ Interval in seconds between worker task runtime statistics (default: 60).
218
+ Set to 0 to disable the stats thread and its callbacks. Queue maintenance
219
+ can occupy a worker outside task-execution statistics. When enabled,
220
+ ``StatsThread.report_maintenance_start()`` and ``report_maintenance_end()``
221
+ bracket the combined scheduled-task promotion and expired-task recovery
222
+ pass, with the end callback called even if either operation raises.
223
+ The hooks allow custom instrumentation; their defaults are no-ops and do
224
+ not change task runtime or utilization statistics. No maintenance callbacks
225
+ run when maintenance is not due or the worker is stopping.
226
+
215
227
  - ``setup_structlog``
216
228
 
217
229
  If set to True, sets up structured logging using ``structlog`` when
@@ -3,12 +3,15 @@
3
3
  import datetime
4
4
  import time
5
5
  from multiprocessing import Process
6
+ from unittest import mock
6
7
 
8
+ import pytest
7
9
  from freezefrog import FreezeTime
8
10
 
9
11
  from tasktiger import Task, Worker
10
12
  from tasktiger._internal import ACTIVE
11
13
  from tasktiger.executor import SyncExecutor
14
+ from tasktiger.stats import StatsThread
12
15
  from tasktiger.worker import LOCK_REDIS_KEY
13
16
 
14
17
  from .config import DELAY
@@ -265,3 +268,37 @@ class TestSyncExecutorWorker:
265
268
  # handled by the executor, the task is still active until it times out
266
269
  # and gets requeued by another worker.
267
270
  ensure_queues(active={"default": 1})
271
+
272
+
273
+ @pytest.mark.parametrize("failing_operation", [None, "scheduled", "expired"])
274
+ def test_maintenance_stats_callbacks(tiger, monkeypatch, failing_operation):
275
+ worker = Worker(tiger)
276
+ worker._queue_set = set()
277
+ calls = mock.Mock()
278
+ calls.stats = mock.Mock(spec=StatsThread)
279
+ worker.stats_thread = calls.stats
280
+ monkeypatch.setattr(worker, "_worker_queue_scheduled_tasks", calls.scheduled)
281
+ monkeypatch.setattr(worker, "_worker_queue_expired_tasks", calls.expired)
282
+
283
+ if failing_operation:
284
+ getattr(calls, failing_operation).side_effect = RuntimeError("maintenance")
285
+ with pytest.raises(RuntimeError, match="maintenance"):
286
+ worker._worker_run()
287
+ else:
288
+ worker._worker_run()
289
+
290
+ expected = [mock.call.stats.report_maintenance_start(), mock.call.scheduled()]
291
+ if failing_operation != "scheduled":
292
+ expected.append(mock.call.expired())
293
+ expected.append(mock.call.stats.report_maintenance_end())
294
+ assert calls.mock_calls == expected
295
+
296
+
297
+ def test_maintenance_without_stats(tiger, monkeypatch):
298
+ worker = Worker(tiger)
299
+ worker._queue_set = set()
300
+ calls = mock.Mock()
301
+ monkeypatch.setattr(worker, "_worker_queue_scheduled_tasks", calls.scheduled)
302
+ monkeypatch.setattr(worker, "_worker_queue_expired_tasks", calls.expired)
303
+ worker._worker_run()
304
+ assert calls.mock_calls == [mock.call.scheduled(), mock.call.expired()]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes