taskito 0.7.0__tar.gz → 0.9.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 (174) hide show
  1. {taskito-0.7.0 → taskito-0.9.0}/Cargo.lock +22 -3
  2. {taskito-0.7.0 → taskito-0.9.0}/PKG-INFO +1 -1
  3. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/Cargo.toml +1 -1
  4. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/maintenance.rs +1 -1
  5. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/mod.rs +15 -6
  6. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/poller.rs +4 -1
  7. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/jobs.rs +27 -5
  8. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/mod.rs +53 -13
  9. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/models.rs +11 -0
  10. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/archival.rs +1 -1
  11. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/dead_letter.rs +2 -1
  12. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/mod.rs +28 -0
  13. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/workers.rs +45 -5
  14. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/dead_letter.rs +5 -1
  15. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/jobs.rs +39 -3
  16. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/workers.rs +74 -14
  17. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/schema.rs +6 -0
  18. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/archival.rs +1 -1
  19. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/dead_letter.rs +2 -1
  20. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/mod.rs +19 -0
  21. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/tests.rs +29 -17
  22. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/workers.rs +45 -5
  23. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/traits.rs +16 -3
  24. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/tests/rust/storage_tests.rs +28 -8
  25. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/Cargo.toml +4 -1
  26. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/lib.rs +1 -0
  27. taskito-0.9.0/crates/taskito-python/src/prefork/child.rs +122 -0
  28. taskito-0.9.0/crates/taskito-python/src/prefork/dispatch.rs +32 -0
  29. taskito-0.9.0/crates/taskito-python/src/prefork/mod.rs +198 -0
  30. taskito-0.9.0/crates/taskito-python/src/prefork/protocol.rs +123 -0
  31. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_job.rs +3 -0
  32. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/inspection.rs +10 -3
  33. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/mod.rs +6 -3
  34. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/worker.rs +51 -17
  35. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/__init__.py +1 -1
  36. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/_taskito.pyi +8 -1
  37. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/app.py +57 -2
  38. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/mixins.py +127 -0
  39. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/context.py +19 -0
  40. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/fastapi.py +36 -4
  41. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/events.py +3 -0
  42. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/mixins.py +19 -2
  43. taskito-0.9.0/py_src/taskito/prefork/__init__.py +20 -0
  44. taskito-0.9.0/py_src/taskito/prefork/__main__.py +6 -0
  45. taskito-0.9.0/py_src/taskito/prefork/child.py +196 -0
  46. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/result.py +95 -0
  47. {taskito-0.7.0 → taskito-0.9.0}/pyproject.toml +1 -1
  48. {taskito-0.7.0 → taskito-0.9.0}/Cargo.toml +0 -0
  49. {taskito-0.7.0 → taskito-0.9.0}/LICENSE +0 -0
  50. {taskito-0.7.0 → taskito-0.9.0}/README.md +0 -0
  51. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/error.rs +0 -0
  52. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/job.rs +0 -0
  53. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/lib.rs +0 -0
  54. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/periodic.rs +0 -0
  55. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/circuit_breaker.rs +0 -0
  56. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/dlq.rs +0 -0
  57. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/mod.rs +0 -0
  58. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/rate_limiter.rs +0 -0
  59. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/retry.rs +0 -0
  60. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/result_handler.rs +0 -0
  61. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/locks.rs +0 -0
  62. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/logs.rs +0 -0
  63. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/metrics.rs +0 -0
  64. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/mod.rs +0 -0
  65. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/circuit_breakers.rs +0 -0
  66. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/jobs.rs +0 -0
  67. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/locks.rs +0 -0
  68. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/logs.rs +0 -0
  69. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/metrics.rs +0 -0
  70. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/periodic.rs +0 -0
  71. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/queue_state.rs +0 -0
  72. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/rate_limits.rs +0 -0
  73. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/trait_impl.rs +0 -0
  74. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/archival.rs +0 -0
  75. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/circuit_breakers.rs +0 -0
  76. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/locks.rs +0 -0
  77. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/logs.rs +0 -0
  78. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/metrics.rs +0 -0
  79. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/mod.rs +0 -0
  80. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/periodic.rs +0 -0
  81. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/queue_state.rs +0 -0
  82. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/rate_limits.rs +0 -0
  83. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/trait_impl.rs +0 -0
  84. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/circuit_breakers.rs +0 -0
  85. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/jobs.rs +0 -0
  86. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/locks.rs +0 -0
  87. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/logs.rs +0 -0
  88. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/metrics.rs +0 -0
  89. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/periodic.rs +0 -0
  90. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/queue_state.rs +0 -0
  91. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/rate_limits.rs +0 -0
  92. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/trait_impl.rs +0 -0
  93. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/src/worker.rs +0 -0
  94. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-core/tests/rust.rs +0 -0
  95. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/async_worker.rs +0 -0
  96. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_config.rs +0 -0
  97. {taskito-0.7.0 → taskito-0.9.0}/crates/taskito-python/src/py_worker.rs +0 -0
  98. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/__init__.py +0 -0
  99. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/context.py +0 -0
  100. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/executor.py +0 -0
  101. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/helpers.py +0 -0
  102. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/locks.py +0 -0
  103. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/async_support/result.py +0 -0
  104. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/canvas.py +0 -0
  105. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/cli.py +0 -0
  106. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/__init__.py +0 -0
  107. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/__init__.py +0 -0
  108. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/admin.py +0 -0
  109. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/apps.py +0 -0
  110. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/__init__.py +0 -0
  111. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/__init__.py +0 -0
  112. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_dashboard.py +0 -0
  113. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_info.py +0 -0
  114. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_worker.py +0 -0
  115. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/django/settings.py +0 -0
  116. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/flask.py +0 -0
  117. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/otel.py +0 -0
  118. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/prometheus.py +0 -0
  119. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/contrib/sentry.py +0 -0
  120. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/dashboard.py +0 -0
  121. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/exceptions.py +0 -0
  122. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/health.py +0 -0
  123. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/inject.py +0 -0
  124. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/__init__.py +0 -0
  125. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/built_in.py +0 -0
  126. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/converters.py +0 -0
  127. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/errors.py +0 -0
  128. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/interceptor.py +0 -0
  129. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/metrics.py +0 -0
  130. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/reconstruct.py +0 -0
  131. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/registry.py +0 -0
  132. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/strategy.py +0 -0
  133. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/interception/walker.py +0 -0
  134. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/locks.py +0 -0
  135. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/middleware.py +0 -0
  136. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/__init__.py +0 -0
  137. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/built_in.py +0 -0
  138. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handler.py +0 -0
  139. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/__init__.py +0 -0
  140. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/boto3_client.py +0 -0
  141. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/file.py +0 -0
  142. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/gcs_client.py +0 -0
  143. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/httpx_client.py +0 -0
  144. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/logger.py +0 -0
  145. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/requests_session.py +0 -0
  146. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/metrics.py +0 -0
  147. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/no_proxy.py +0 -0
  148. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/reconstruct.py +0 -0
  149. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/registry.py +0 -0
  150. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/schema.py +0 -0
  151. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/proxies/signing.py +0 -0
  152. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/py.typed +0 -0
  153. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/__init__.py +0 -0
  154. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/definition.py +0 -0
  155. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/frozen.py +0 -0
  156. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/graph.py +0 -0
  157. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/health.py +0 -0
  158. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/pool.py +0 -0
  159. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/runtime.py +0 -0
  160. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/thread_local.py +0 -0
  161. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/resources/toml_config.py +0 -0
  162. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/scaler.py +0 -0
  163. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/serializers.py +0 -0
  164. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/task.py +0 -0
  165. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/dashboard.css +0 -0
  166. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/dashboard.html +0 -0
  167. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/actions.js +0 -0
  168. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/app.js +0 -0
  169. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/chart.js +0 -0
  170. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/components.js +0 -0
  171. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/utils.js +0 -0
  172. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/templates/js/views.js +0 -0
  173. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/testing.py +0 -0
  174. {taskito-0.7.0 → taskito-0.9.0}/py_src/taskito/webhooks.py +0 -0
@@ -43,6 +43,12 @@ version = "1.5.0"
43
43
  source = "registry+https://github.com/rust-lang/crates.io-index"
44
44
  checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
45
45
 
46
+ [[package]]
47
+ name = "base64"
48
+ version = "0.22.1"
49
+ source = "registry+https://github.com/rust-lang/crates.io-index"
50
+ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
51
+
46
52
  [[package]]
47
53
  name = "bitflags"
48
54
  version = "2.11.0"
@@ -324,6 +330,16 @@ dependencies = [
324
330
  "percent-encoding",
325
331
  ]
326
332
 
333
+ [[package]]
334
+ name = "gethostname"
335
+ version = "1.1.0"
336
+ source = "registry+https://github.com/rust-lang/crates.io-index"
337
+ checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
338
+ dependencies = [
339
+ "rustix",
340
+ "windows-link",
341
+ ]
342
+
327
343
  [[package]]
328
344
  name = "getrandom"
329
345
  version = "0.2.17"
@@ -1201,7 +1217,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
1201
1217
 
1202
1218
  [[package]]
1203
1219
  name = "taskito-async"
1204
- version = "0.7.0"
1220
+ version = "0.9.0"
1205
1221
  dependencies = [
1206
1222
  "async-trait",
1207
1223
  "crossbeam-channel",
@@ -1213,7 +1229,7 @@ dependencies = [
1213
1229
 
1214
1230
  [[package]]
1215
1231
  name = "taskito-core"
1216
- version = "0.7.0"
1232
+ version = "0.9.0"
1217
1233
  dependencies = [
1218
1234
  "async-trait",
1219
1235
  "chrono",
@@ -1237,12 +1253,15 @@ dependencies = [
1237
1253
 
1238
1254
  [[package]]
1239
1255
  name = "taskito-python"
1240
- version = "0.7.0"
1256
+ version = "0.9.0"
1241
1257
  dependencies = [
1242
1258
  "async-trait",
1259
+ "base64",
1243
1260
  "crossbeam-channel",
1261
+ "gethostname",
1244
1262
  "log",
1245
1263
  "pyo3",
1264
+ "serde",
1246
1265
  "serde_json",
1247
1266
  "taskito-async",
1248
1267
  "taskito-core",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskito
3
- Version: 0.7.0
3
+ Version: 0.9.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "taskito-core"
3
- version = "0.7.0"
3
+ version = "0.9.0"
4
4
  edition = "2021"
5
5
 
6
6
  [features]
@@ -99,7 +99,7 @@ impl Scheduler {
99
99
  depends_on: vec![],
100
100
  expires_at: None,
101
101
  result_ttl_ms: None,
102
- namespace: None,
102
+ namespace: self.namespace.clone(),
103
103
  };
104
104
 
105
105
  if let Err(e) = self.storage.enqueue_unique(new_job) {
@@ -128,6 +128,7 @@ pub struct Scheduler {
128
128
  config: SchedulerConfig,
129
129
  shutdown: Arc<Notify>,
130
130
  paused_cache: Mutex<(HashSet<String>, Instant)>,
131
+ namespace: Option<String>,
131
132
  }
132
133
 
133
134
  /// Counters for tick-based scheduling of periodic maintenance tasks.
@@ -139,7 +140,12 @@ struct TickCounters {
139
140
  }
140
141
 
141
142
  impl Scheduler {
142
- pub fn new(storage: StorageBackend, queues: Vec<String>, config: SchedulerConfig) -> Self {
143
+ pub fn new(
144
+ storage: StorageBackend,
145
+ queues: Vec<String>,
146
+ config: SchedulerConfig,
147
+ namespace: Option<String>,
148
+ ) -> Self {
143
149
  let rate_limiter = RateLimiter::new(storage.clone());
144
150
  let dlq = DeadLetterQueue::new(storage.clone());
145
151
  let circuit_breaker = CircuitBreaker::new(storage.clone());
@@ -155,6 +161,7 @@ impl Scheduler {
155
161
  config,
156
162
  shutdown: Arc::new(Notify::new()),
157
163
  paused_cache: Mutex::new((HashSet::new(), Instant::now())),
164
+ namespace,
158
165
  }
159
166
  }
160
167
 
@@ -249,6 +256,7 @@ mod tests {
249
256
  storage,
250
257
  vec!["default".to_string()],
251
258
  SchedulerConfig::default(),
259
+ None,
252
260
  )
253
261
  }
254
262
 
@@ -445,7 +453,7 @@ mod tests {
445
453
  // The second job should be back in pending with a future scheduled_at
446
454
  let jobs = scheduler
447
455
  .storage
448
- .list_jobs(Some(JobStatus::Pending as i32), None, None, 10, 0)
456
+ .list_jobs(Some(JobStatus::Pending as i32), None, None, 10, 0, None)
449
457
  .unwrap();
450
458
  assert_eq!(jobs.len(), 1);
451
459
  assert!(jobs[0].scheduled_at > now_millis());
@@ -486,7 +494,7 @@ mod tests {
486
494
  // Job should be rescheduled
487
495
  let jobs = scheduler
488
496
  .storage
489
- .list_jobs(Some(JobStatus::Pending as i32), None, None, 10, 0)
497
+ .list_jobs(Some(JobStatus::Pending as i32), None, None, 10, 0, None)
490
498
  .unwrap();
491
499
  assert_eq!(jobs.len(), 1);
492
500
  assert!(jobs[0].scheduled_at > now_millis());
@@ -562,6 +570,7 @@ mod tests {
562
570
  Some("periodic_task"),
563
571
  10,
564
572
  0,
573
+ None,
565
574
  )
566
575
  .unwrap();
567
576
  assert_eq!(jobs.len(), 1);
@@ -575,13 +584,13 @@ mod tests {
575
584
  result_ttl_ms: Some(1), // 1ms TTL
576
585
  ..SchedulerConfig::default()
577
586
  };
578
- let scheduler = Scheduler::new(storage, vec!["default".to_string()], config);
587
+ let scheduler = Scheduler::new(storage, vec!["default".to_string()], config, None);
579
588
 
580
589
  // Enqueue, dequeue, and complete a job
581
590
  let job = scheduler.storage.enqueue(make_job("cleanup_task")).unwrap();
582
591
  scheduler
583
592
  .storage
584
- .dequeue("default", now_millis() + 1000)
593
+ .dequeue("default", now_millis() + 1000, None)
585
594
  .unwrap();
586
595
  scheduler.storage.complete(&job.id, Some(vec![1])).unwrap();
587
596
 
@@ -605,7 +614,7 @@ mod tests {
605
614
  cleanup_interval: 1,
606
615
  ..SchedulerConfig::default()
607
616
  };
608
- let scheduler = Scheduler::new(storage, vec!["default".to_string()], config);
617
+ let scheduler = Scheduler::new(storage, vec!["default".to_string()], config, None);
609
618
 
610
619
  scheduler.storage.enqueue(make_job("tick_task")).unwrap();
611
620
 
@@ -51,7 +51,10 @@ impl Scheduler {
51
51
  return Ok(false);
52
52
  }
53
53
 
54
- let job = match self.storage.dequeue_from(&active_queues, now)? {
54
+ let job = match self
55
+ .storage
56
+ .dequeue_from(&active_queues, now, self.namespace.as_deref())?
57
+ {
55
58
  Some(j) => j,
56
59
  None => return Ok(false),
57
60
  };
@@ -270,17 +270,27 @@ macro_rules! impl_diesel_job_ops {
270
270
  }
271
271
 
272
272
  /// Atomically dequeue the highest-priority ready job from the given queue.
273
- /// Skips expired jobs.
274
- pub fn dequeue(&self, queue_name: &str, now: i64) -> Result<Option<Job>> {
273
+ /// Skips expired jobs. When `namespace` is `Some`, only jobs in that
274
+ /// namespace are considered; when `None`, only jobs with no namespace.
275
+ pub fn dequeue(&self, queue_name: &str, now: i64, namespace: Option<&str>) -> Result<Option<Job>> {
275
276
  let mut conn = self.conn()?;
276
277
 
277
278
  conn.transaction(|conn| {
278
- let candidates: Vec<JobRow> = jobs::table
279
+ let mut query = jobs::table
279
280
  .filter(jobs::queue.eq(queue_name))
280
281
  .filter(jobs::status.eq(JobStatus::Pending as i32))
281
282
  .filter(jobs::scheduled_at.le(now))
282
283
  .order((jobs::priority.desc(), jobs::scheduled_at.asc()))
283
284
  .limit(100)
285
+ .into_boxed();
286
+
287
+ if let Some(ns) = namespace {
288
+ query = query.filter(jobs::namespace.eq(ns));
289
+ } else {
290
+ query = query.filter(jobs::namespace.is_null());
291
+ }
292
+
293
+ let candidates: Vec<JobRow> = query
284
294
  .select(JobRow::as_select())
285
295
  .load(conn)?;
286
296
 
@@ -327,9 +337,9 @@ macro_rules! impl_diesel_job_ops {
327
337
  }
328
338
 
329
339
  /// Dequeue from multiple queues, checking each in order.
330
- pub fn dequeue_from(&self, queues: &[String], now: i64) -> Result<Option<Job>> {
340
+ pub fn dequeue_from(&self, queues: &[String], now: i64, namespace: Option<&str>) -> Result<Option<Job>> {
331
341
  for queue_name in queues {
332
- if let Some(job) = self.dequeue(queue_name, now)? {
342
+ if let Some(job) = self.dequeue(queue_name, now, namespace)? {
333
343
  return Ok(Some(job));
334
344
  }
335
345
  }
@@ -554,6 +564,8 @@ macro_rules! impl_diesel_job_ops {
554
564
  }
555
565
 
556
566
  /// List jobs with optional filters and pagination.
567
+ /// When `namespace` is `Some`, only jobs in that namespace are returned.
568
+ /// When `None`, all jobs are returned regardless of namespace.
557
569
  pub fn list_jobs(
558
570
  &self,
559
571
  status: Option<i32>,
@@ -561,6 +573,7 @@ macro_rules! impl_diesel_job_ops {
561
573
  task_name: Option<&str>,
562
574
  limit: i64,
563
575
  offset: i64,
576
+ namespace: Option<&str>,
564
577
  ) -> Result<Vec<Job>> {
565
578
  let mut conn = self.conn()?;
566
579
 
@@ -575,6 +588,9 @@ macro_rules! impl_diesel_job_ops {
575
588
  if let Some(t) = task_name {
576
589
  query = query.filter(jobs::task_name.eq(t));
577
590
  }
591
+ if let Some(ns) = namespace {
592
+ query = query.filter(jobs::namespace.eq(ns));
593
+ }
578
594
 
579
595
  let rows: Vec<JobRow> = query
580
596
  .limit(limit)
@@ -678,6 +694,8 @@ macro_rules! impl_diesel_job_ops {
678
694
  }
679
695
 
680
696
  /// List jobs with extended filters.
697
+ /// When `namespace` is `Some`, only jobs in that namespace are returned.
698
+ /// When `None`, all jobs are returned regardless of namespace.
681
699
  #[allow(clippy::too_many_arguments)]
682
700
  pub fn list_jobs_filtered(
683
701
  &self,
@@ -690,6 +708,7 @@ macro_rules! impl_diesel_job_ops {
690
708
  created_before: Option<i64>,
691
709
  limit: i64,
692
710
  offset: i64,
711
+ namespace: Option<&str>,
693
712
  ) -> Result<Vec<Job>> {
694
713
  let mut conn = self.conn()?;
695
714
 
@@ -716,6 +735,9 @@ macro_rules! impl_diesel_job_ops {
716
735
  if let Some(before) = created_before {
717
736
  query = query.filter(jobs::created_at.le(before));
718
737
  }
738
+ if let Some(ns) = namespace {
739
+ query = query.filter(jobs::namespace.eq(ns));
740
+ }
719
741
 
720
742
  let rows: Vec<JobRow> = query
721
743
  .limit(limit)
@@ -40,6 +40,7 @@ pub struct DeadJob {
40
40
  pub max_retries: i32,
41
41
  pub timeout_ms: i64,
42
42
  pub result_ttl_ms: Option<i64>,
43
+ pub namespace: Option<String>,
43
44
  }
44
45
 
45
46
  impl From<models::DeadLetterRow> for DeadJob {
@@ -58,6 +59,7 @@ impl From<models::DeadLetterRow> for DeadJob {
58
59
  max_retries: row.max_retries,
59
60
  timeout_ms: row.timeout_ms,
60
61
  result_ttl_ms: row.result_ttl_ms,
62
+ namespace: row.namespace,
61
63
  }
62
64
  }
63
65
  }
@@ -93,15 +95,17 @@ macro_rules! impl_storage {
93
95
  &self,
94
96
  queue_name: &str,
95
97
  now: i64,
98
+ namespace: Option<&str>,
96
99
  ) -> $crate::error::Result<Option<$crate::job::Job>> {
97
- self.dequeue(queue_name, now)
100
+ self.dequeue(queue_name, now, namespace)
98
101
  }
99
102
  fn dequeue_from(
100
103
  &self,
101
104
  queues: &[String],
102
105
  now: i64,
106
+ namespace: Option<&str>,
103
107
  ) -> $crate::error::Result<Option<$crate::job::Job>> {
104
- self.dequeue_from(queues, now)
108
+ self.dequeue_from(queues, now, namespace)
105
109
  }
106
110
  fn complete(
107
111
  &self,
@@ -151,8 +155,9 @@ macro_rules! impl_storage {
151
155
  task_name: Option<&str>,
152
156
  limit: i64,
153
157
  offset: i64,
158
+ namespace: Option<&str>,
154
159
  ) -> $crate::error::Result<Vec<$crate::job::Job>> {
155
- self.list_jobs(status, queue_name, task_name, limit, offset)
160
+ self.list_jobs(status, queue_name, task_name, limit, offset, namespace)
156
161
  }
157
162
  fn get_job(&self, id: &str) -> $crate::error::Result<Option<$crate::job::Job>> {
158
163
  self.get_job(id)
@@ -347,8 +352,11 @@ macro_rules! impl_storage {
347
352
  resources: Option<&str>,
348
353
  resource_health: Option<&str>,
349
354
  threads: i32,
355
+ hostname: Option<&str>,
356
+ pid: Option<i32>,
357
+ pool_type: Option<&str>,
350
358
  ) -> $crate::error::Result<()> {
351
- self.register_worker(worker_id, queues, tags, resources, resource_health, threads)
359
+ self.register_worker(worker_id, queues, tags, resources, resource_health, threads, hostname, pid, pool_type)
352
360
  }
353
361
  fn heartbeat(
354
362
  &self,
@@ -357,17 +365,27 @@ macro_rules! impl_storage {
357
365
  ) -> $crate::error::Result<()> {
358
366
  self.heartbeat(worker_id, resource_health)
359
367
  }
368
+ fn update_worker_status(
369
+ &self,
370
+ worker_id: &str,
371
+ status: &str,
372
+ ) -> $crate::error::Result<()> {
373
+ self.update_worker_status(worker_id, status)
374
+ }
360
375
  fn list_workers(
361
376
  &self,
362
377
  ) -> $crate::error::Result<Vec<$crate::storage::models::WorkerRow>> {
363
378
  self.list_workers()
364
379
  }
365
- fn reap_dead_workers(&self) -> $crate::error::Result<u64> {
380
+ fn reap_dead_workers(&self) -> $crate::error::Result<Vec<String>> {
366
381
  self.reap_dead_workers()
367
382
  }
368
383
  fn unregister_worker(&self, worker_id: &str) -> $crate::error::Result<()> {
369
384
  self.unregister_worker(worker_id)
370
385
  }
386
+ fn list_claims_by_worker(&self, worker_id: &str) -> $crate::error::Result<Vec<String>> {
387
+ self.list_claims_by_worker(worker_id)
388
+ }
371
389
  fn pause_queue(&self, queue_name: &str) -> $crate::error::Result<()> {
372
390
  self.pause_queue(queue_name)
373
391
  }
@@ -473,6 +491,7 @@ macro_rules! impl_storage {
473
491
  created_before: Option<i64>,
474
492
  limit: i64,
475
493
  offset: i64,
494
+ namespace: Option<&str>,
476
495
  ) -> $crate::error::Result<Vec<$crate::job::Job>> {
477
496
  self.list_jobs_filtered(
478
497
  status,
@@ -484,6 +503,7 @@ macro_rules! impl_storage {
484
503
  created_before,
485
504
  limit,
486
505
  offset,
506
+ namespace,
487
507
  )
488
508
  }
489
509
  }
@@ -526,11 +546,16 @@ impl Storage for StorageBackend {
526
546
  fn enqueue_unique(&self, new_job: NewJob) -> Result<Job> {
527
547
  delegate!(self, enqueue_unique, new_job)
528
548
  }
529
- fn dequeue(&self, queue_name: &str, now: i64) -> Result<Option<Job>> {
530
- delegate!(self, dequeue, queue_name, now)
549
+ fn dequeue(&self, queue_name: &str, now: i64, namespace: Option<&str>) -> Result<Option<Job>> {
550
+ delegate!(self, dequeue, queue_name, now, namespace)
531
551
  }
532
- fn dequeue_from(&self, queues: &[String], now: i64) -> Result<Option<Job>> {
533
- delegate!(self, dequeue_from, queues, now)
552
+ fn dequeue_from(
553
+ &self,
554
+ queues: &[String],
555
+ now: i64,
556
+ namespace: Option<&str>,
557
+ ) -> Result<Option<Job>> {
558
+ delegate!(self, dequeue_from, queues, now, namespace)
534
559
  }
535
560
  fn complete(&self, id: &str, result_bytes: Option<Vec<u8>>) -> Result<()> {
536
561
  delegate!(self, complete, id, result_bytes)
@@ -572,8 +597,9 @@ impl Storage for StorageBackend {
572
597
  task_name: Option<&str>,
573
598
  limit: i64,
574
599
  offset: i64,
600
+ namespace: Option<&str>,
575
601
  ) -> Result<Vec<Job>> {
576
- delegate!(self, list_jobs, status, queue_name, task_name, limit, offset)
602
+ delegate!(self, list_jobs, status, queue_name, task_name, limit, offset, namespace)
577
603
  }
578
604
  fn get_job(&self, id: &str) -> Result<Option<Job>> {
579
605
  delegate!(self, get_job, id)
@@ -726,6 +752,9 @@ impl Storage for StorageBackend {
726
752
  resources: Option<&str>,
727
753
  resource_health: Option<&str>,
728
754
  threads: i32,
755
+ hostname: Option<&str>,
756
+ pid: Option<i32>,
757
+ pool_type: Option<&str>,
729
758
  ) -> Result<()> {
730
759
  delegate!(
731
760
  self,
@@ -735,21 +764,30 @@ impl Storage for StorageBackend {
735
764
  tags,
736
765
  resources,
737
766
  resource_health,
738
- threads
767
+ threads,
768
+ hostname,
769
+ pid,
770
+ pool_type
739
771
  )
740
772
  }
741
773
  fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
742
774
  delegate!(self, heartbeat, worker_id, resource_health)
743
775
  }
776
+ fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()> {
777
+ delegate!(self, update_worker_status, worker_id, status)
778
+ }
744
779
  fn list_workers(&self) -> Result<Vec<models::WorkerRow>> {
745
780
  delegate!(self, list_workers)
746
781
  }
747
- fn reap_dead_workers(&self) -> Result<u64> {
782
+ fn reap_dead_workers(&self) -> Result<Vec<String>> {
748
783
  delegate!(self, reap_dead_workers)
749
784
  }
750
785
  fn unregister_worker(&self, worker_id: &str) -> Result<()> {
751
786
  delegate!(self, unregister_worker, worker_id)
752
787
  }
788
+ fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>> {
789
+ delegate!(self, list_claims_by_worker, worker_id)
790
+ }
753
791
  fn pause_queue(&self, queue_name: &str) -> Result<()> {
754
792
  delegate!(self, pause_queue, queue_name)
755
793
  }
@@ -818,6 +856,7 @@ impl Storage for StorageBackend {
818
856
  created_before: Option<i64>,
819
857
  limit: i64,
820
858
  offset: i64,
859
+ namespace: Option<&str>,
821
860
  ) -> Result<Vec<Job>> {
822
861
  delegate!(
823
862
  self,
@@ -830,7 +869,8 @@ impl Storage for StorageBackend {
830
869
  created_after,
831
870
  created_before,
832
871
  limit,
833
- offset
872
+ offset,
873
+ namespace
834
874
  )
835
875
  }
836
876
  }
@@ -75,6 +75,7 @@ pub struct DeadLetterRow {
75
75
  pub max_retries: i32,
76
76
  pub timeout_ms: i64,
77
77
  pub result_ttl_ms: Option<i64>,
78
+ pub namespace: Option<String>,
78
79
  }
79
80
 
80
81
  /// Insertable struct for dead letter entries.
@@ -94,6 +95,7 @@ pub struct NewDeadLetterRow<'a> {
94
95
  pub max_retries: i32,
95
96
  pub timeout_ms: i64,
96
97
  pub result_ttl_ms: Option<i64>,
98
+ pub namespace: Option<&'a str>,
97
99
  }
98
100
 
99
101
  /// A row in the `rate_limits` table.
@@ -305,6 +307,10 @@ pub struct WorkerRow {
305
307
  pub resources: Option<String>,
306
308
  pub resource_health: Option<String>,
307
309
  pub threads: i32,
310
+ pub started_at: Option<i64>,
311
+ pub hostname: Option<String>,
312
+ pub pid: Option<i32>,
313
+ pub pool_type: Option<String>,
308
314
  }
309
315
 
310
316
  #[derive(Insertable, AsChangeset, Debug)]
@@ -318,6 +324,10 @@ pub struct NewWorkerRow<'a> {
318
324
  pub resources: Option<&'a str>,
319
325
  pub resource_health: Option<&'a str>,
320
326
  pub threads: i32,
327
+ pub started_at: Option<i64>,
328
+ pub hostname: Option<&'a str>,
329
+ pub pid: Option<i32>,
330
+ pub pool_type: Option<&'a str>,
321
331
  }
322
332
 
323
333
  // ── Queue State ─────────────────────────────────────────────────
@@ -394,4 +404,5 @@ pub struct ArchivedJobRow {
394
404
  pub cancel_requested: i32,
395
405
  pub expires_at: Option<i64>,
396
406
  pub result_ttl_ms: Option<i64>,
407
+ pub namespace: Option<String>,
397
408
  }
@@ -70,7 +70,7 @@ impl PostgresStorage {
70
70
  cancel_requested: row.cancel_requested != 0,
71
71
  expires_at: row.expires_at,
72
72
  result_ttl_ms: row.result_ttl_ms,
73
- namespace: None,
73
+ namespace: row.namespace,
74
74
  })
75
75
  .collect())
76
76
  }
@@ -30,6 +30,7 @@ impl PostgresStorage {
30
30
  max_retries: job.max_retries,
31
31
  timeout_ms: job.timeout_ms,
32
32
  result_ttl_ms: job.result_ttl_ms,
33
+ namespace: job.namespace.as_deref(),
33
34
  };
34
35
 
35
36
  diesel::insert_into(dead_letter::table)
@@ -94,7 +95,7 @@ impl PostgresStorage {
94
95
  depends_on: vec![],
95
96
  expires_at: None,
96
97
  result_ttl_ms: dead_row.result_ttl_ms,
97
- namespace: None,
98
+ namespace: dead_row.namespace,
98
99
  };
99
100
 
100
101
  let job = new_job.into_job();
@@ -359,6 +359,24 @@ impl PostgresStorage {
359
359
  "ALTER TABLE workers ADD COLUMN IF NOT EXISTS threads INTEGER NOT NULL DEFAULT 0",
360
360
  );
361
361
 
362
+ // Migration: add worker discovery metadata columns
363
+ migration_alter(
364
+ &mut conn,
365
+ "ALTER TABLE workers ADD COLUMN IF NOT EXISTS started_at BIGINT",
366
+ );
367
+ migration_alter(
368
+ &mut conn,
369
+ "ALTER TABLE workers ADD COLUMN IF NOT EXISTS hostname TEXT",
370
+ );
371
+ migration_alter(
372
+ &mut conn,
373
+ "ALTER TABLE workers ADD COLUMN IF NOT EXISTS pid INTEGER",
374
+ );
375
+ migration_alter(
376
+ &mut conn,
377
+ "ALTER TABLE workers ADD COLUMN IF NOT EXISTS pool_type TEXT",
378
+ );
379
+
362
380
  diesel::sql_query(
363
381
  "CREATE TABLE IF NOT EXISTS queue_state (
364
382
  queue_name TEXT PRIMARY KEY,
@@ -434,6 +452,16 @@ impl PostgresStorage {
434
452
  "ALTER TABLE circuit_breakers ADD COLUMN IF NOT EXISTS half_open_failure_count INTEGER NOT NULL DEFAULT 0",
435
453
  );
436
454
 
455
+ // Migration: add namespace column to dead_letter and archived_jobs
456
+ migration_alter(
457
+ &mut conn,
458
+ "ALTER TABLE dead_letter ADD COLUMN IF NOT EXISTS namespace TEXT",
459
+ );
460
+ migration_alter(
461
+ &mut conn,
462
+ "ALTER TABLE archived_jobs ADD COLUMN IF NOT EXISTS namespace TEXT",
463
+ );
464
+
437
465
  // ── Distributed Locks ─────────────────────────────
438
466
  diesel::sql_query(
439
467
  "CREATE TABLE IF NOT EXISTS distributed_locks (