taskito 0.8.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.8.0 → taskito-0.9.0}/Cargo.lock +22 -3
  2. {taskito-0.8.0 → taskito-0.9.0}/PKG-INFO +1 -1
  3. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/Cargo.toml +1 -1
  4. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/mod.rs +29 -4
  5. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/models.rs +8 -0
  6. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/mod.rs +18 -0
  7. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/workers.rs +45 -5
  8. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/workers.rs +74 -14
  9. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/schema.rs +4 -0
  10. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/mod.rs +9 -0
  11. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/workers.rs +45 -5
  12. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/traits.rs +7 -1
  13. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/tests/rust/storage_tests.rs +22 -2
  14. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/Cargo.toml +4 -1
  15. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/lib.rs +1 -0
  16. taskito-0.9.0/crates/taskito-python/src/prefork/child.rs +122 -0
  17. taskito-0.9.0/crates/taskito-python/src/prefork/dispatch.rs +32 -0
  18. taskito-0.9.0/crates/taskito-python/src/prefork/mod.rs +198 -0
  19. taskito-0.9.0/crates/taskito-python/src/prefork/protocol.rs +123 -0
  20. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/inspection.rs +4 -0
  21. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/worker.rs +45 -16
  22. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/__init__.py +1 -1
  23. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/_taskito.pyi +4 -1
  24. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/app.py +54 -2
  25. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/mixins.py +127 -0
  26. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/context.py +19 -0
  27. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/fastapi.py +36 -4
  28. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/events.py +3 -0
  29. taskito-0.9.0/py_src/taskito/prefork/__init__.py +20 -0
  30. taskito-0.9.0/py_src/taskito/prefork/__main__.py +6 -0
  31. taskito-0.9.0/py_src/taskito/prefork/child.py +196 -0
  32. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/result.py +95 -0
  33. {taskito-0.8.0 → taskito-0.9.0}/pyproject.toml +1 -1
  34. {taskito-0.8.0 → taskito-0.9.0}/Cargo.toml +0 -0
  35. {taskito-0.8.0 → taskito-0.9.0}/LICENSE +0 -0
  36. {taskito-0.8.0 → taskito-0.9.0}/README.md +0 -0
  37. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/error.rs +0 -0
  38. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/job.rs +0 -0
  39. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/lib.rs +0 -0
  40. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/periodic.rs +0 -0
  41. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/circuit_breaker.rs +0 -0
  42. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/dlq.rs +0 -0
  43. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/mod.rs +0 -0
  44. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/rate_limiter.rs +0 -0
  45. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/resilience/retry.rs +0 -0
  46. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/maintenance.rs +0 -0
  47. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/mod.rs +0 -0
  48. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/poller.rs +0 -0
  49. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/scheduler/result_handler.rs +0 -0
  50. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/jobs.rs +0 -0
  51. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/locks.rs +0 -0
  52. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/logs.rs +0 -0
  53. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/metrics.rs +0 -0
  54. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/diesel_common/mod.rs +0 -0
  55. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/archival.rs +0 -0
  56. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/circuit_breakers.rs +0 -0
  57. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/dead_letter.rs +0 -0
  58. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/jobs.rs +0 -0
  59. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/locks.rs +0 -0
  60. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/logs.rs +0 -0
  61. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/metrics.rs +0 -0
  62. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/periodic.rs +0 -0
  63. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/queue_state.rs +0 -0
  64. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/rate_limits.rs +0 -0
  65. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/postgres/trait_impl.rs +0 -0
  66. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/archival.rs +0 -0
  67. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/circuit_breakers.rs +0 -0
  68. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/dead_letter.rs +0 -0
  69. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/jobs.rs +0 -0
  70. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/locks.rs +0 -0
  71. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/logs.rs +0 -0
  72. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/metrics.rs +0 -0
  73. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/mod.rs +0 -0
  74. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/periodic.rs +0 -0
  75. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/queue_state.rs +0 -0
  76. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/rate_limits.rs +0 -0
  77. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/redis_backend/trait_impl.rs +0 -0
  78. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/archival.rs +0 -0
  79. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/circuit_breakers.rs +0 -0
  80. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/dead_letter.rs +0 -0
  81. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/jobs.rs +0 -0
  82. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/locks.rs +0 -0
  83. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/logs.rs +0 -0
  84. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/metrics.rs +0 -0
  85. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/periodic.rs +0 -0
  86. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/queue_state.rs +0 -0
  87. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/rate_limits.rs +0 -0
  88. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/tests.rs +0 -0
  89. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/storage/sqlite/trait_impl.rs +0 -0
  90. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/src/worker.rs +0 -0
  91. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-core/tests/rust.rs +0 -0
  92. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/async_worker.rs +0 -0
  93. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_config.rs +0 -0
  94. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_job.rs +0 -0
  95. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_queue/mod.rs +0 -0
  96. {taskito-0.8.0 → taskito-0.9.0}/crates/taskito-python/src/py_worker.rs +0 -0
  97. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/__init__.py +0 -0
  98. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/context.py +0 -0
  99. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/executor.py +0 -0
  100. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/helpers.py +0 -0
  101. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/locks.py +0 -0
  102. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/async_support/result.py +0 -0
  103. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/canvas.py +0 -0
  104. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/cli.py +0 -0
  105. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/__init__.py +0 -0
  106. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/__init__.py +0 -0
  107. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/admin.py +0 -0
  108. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/apps.py +0 -0
  109. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/__init__.py +0 -0
  110. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/__init__.py +0 -0
  111. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_dashboard.py +0 -0
  112. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_info.py +0 -0
  113. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/management/commands/taskito_worker.py +0 -0
  114. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/django/settings.py +0 -0
  115. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/flask.py +0 -0
  116. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/otel.py +0 -0
  117. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/prometheus.py +0 -0
  118. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/contrib/sentry.py +0 -0
  119. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/dashboard.py +0 -0
  120. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/exceptions.py +0 -0
  121. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/health.py +0 -0
  122. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/inject.py +0 -0
  123. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/__init__.py +0 -0
  124. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/built_in.py +0 -0
  125. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/converters.py +0 -0
  126. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/errors.py +0 -0
  127. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/interceptor.py +0 -0
  128. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/metrics.py +0 -0
  129. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/reconstruct.py +0 -0
  130. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/registry.py +0 -0
  131. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/strategy.py +0 -0
  132. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/interception/walker.py +0 -0
  133. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/locks.py +0 -0
  134. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/middleware.py +0 -0
  135. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/mixins.py +0 -0
  136. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/__init__.py +0 -0
  137. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/built_in.py +0 -0
  138. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handler.py +0 -0
  139. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/__init__.py +0 -0
  140. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/boto3_client.py +0 -0
  141. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/file.py +0 -0
  142. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/gcs_client.py +0 -0
  143. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/httpx_client.py +0 -0
  144. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/logger.py +0 -0
  145. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/handlers/requests_session.py +0 -0
  146. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/metrics.py +0 -0
  147. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/no_proxy.py +0 -0
  148. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/reconstruct.py +0 -0
  149. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/registry.py +0 -0
  150. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/schema.py +0 -0
  151. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/proxies/signing.py +0 -0
  152. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/py.typed +0 -0
  153. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/__init__.py +0 -0
  154. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/definition.py +0 -0
  155. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/frozen.py +0 -0
  156. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/graph.py +0 -0
  157. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/health.py +0 -0
  158. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/pool.py +0 -0
  159. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/runtime.py +0 -0
  160. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/thread_local.py +0 -0
  161. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/resources/toml_config.py +0 -0
  162. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/scaler.py +0 -0
  163. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/serializers.py +0 -0
  164. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/task.py +0 -0
  165. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/dashboard.css +0 -0
  166. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/dashboard.html +0 -0
  167. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/actions.js +0 -0
  168. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/app.js +0 -0
  169. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/chart.js +0 -0
  170. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/components.js +0 -0
  171. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/utils.js +0 -0
  172. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/templates/js/views.js +0 -0
  173. {taskito-0.8.0 → taskito-0.9.0}/py_src/taskito/testing.py +0 -0
  174. {taskito-0.8.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.8.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.8.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.8.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.8.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.8.0"
3
+ version = "0.9.0"
4
4
  edition = "2021"
5
5
 
6
6
  [features]
@@ -352,8 +352,11 @@ macro_rules! impl_storage {
352
352
  resources: Option<&str>,
353
353
  resource_health: Option<&str>,
354
354
  threads: i32,
355
+ hostname: Option<&str>,
356
+ pid: Option<i32>,
357
+ pool_type: Option<&str>,
355
358
  ) -> $crate::error::Result<()> {
356
- 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)
357
360
  }
358
361
  fn heartbeat(
359
362
  &self,
@@ -362,17 +365,27 @@ macro_rules! impl_storage {
362
365
  ) -> $crate::error::Result<()> {
363
366
  self.heartbeat(worker_id, resource_health)
364
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
+ }
365
375
  fn list_workers(
366
376
  &self,
367
377
  ) -> $crate::error::Result<Vec<$crate::storage::models::WorkerRow>> {
368
378
  self.list_workers()
369
379
  }
370
- fn reap_dead_workers(&self) -> $crate::error::Result<u64> {
380
+ fn reap_dead_workers(&self) -> $crate::error::Result<Vec<String>> {
371
381
  self.reap_dead_workers()
372
382
  }
373
383
  fn unregister_worker(&self, worker_id: &str) -> $crate::error::Result<()> {
374
384
  self.unregister_worker(worker_id)
375
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
+ }
376
389
  fn pause_queue(&self, queue_name: &str) -> $crate::error::Result<()> {
377
390
  self.pause_queue(queue_name)
378
391
  }
@@ -739,6 +752,9 @@ impl Storage for StorageBackend {
739
752
  resources: Option<&str>,
740
753
  resource_health: Option<&str>,
741
754
  threads: i32,
755
+ hostname: Option<&str>,
756
+ pid: Option<i32>,
757
+ pool_type: Option<&str>,
742
758
  ) -> Result<()> {
743
759
  delegate!(
744
760
  self,
@@ -748,21 +764,30 @@ impl Storage for StorageBackend {
748
764
  tags,
749
765
  resources,
750
766
  resource_health,
751
- threads
767
+ threads,
768
+ hostname,
769
+ pid,
770
+ pool_type
752
771
  )
753
772
  }
754
773
  fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
755
774
  delegate!(self, heartbeat, worker_id, resource_health)
756
775
  }
776
+ fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()> {
777
+ delegate!(self, update_worker_status, worker_id, status)
778
+ }
757
779
  fn list_workers(&self) -> Result<Vec<models::WorkerRow>> {
758
780
  delegate!(self, list_workers)
759
781
  }
760
- fn reap_dead_workers(&self) -> Result<u64> {
782
+ fn reap_dead_workers(&self) -> Result<Vec<String>> {
761
783
  delegate!(self, reap_dead_workers)
762
784
  }
763
785
  fn unregister_worker(&self, worker_id: &str) -> Result<()> {
764
786
  delegate!(self, unregister_worker, worker_id)
765
787
  }
788
+ fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>> {
789
+ delegate!(self, list_claims_by_worker, worker_id)
790
+ }
766
791
  fn pause_queue(&self, queue_name: &str) -> Result<()> {
767
792
  delegate!(self, pause_queue, queue_name)
768
793
  }
@@ -307,6 +307,10 @@ pub struct WorkerRow {
307
307
  pub resources: Option<String>,
308
308
  pub resource_health: Option<String>,
309
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>,
310
314
  }
311
315
 
312
316
  #[derive(Insertable, AsChangeset, Debug)]
@@ -320,6 +324,10 @@ pub struct NewWorkerRow<'a> {
320
324
  pub resources: Option<&'a str>,
321
325
  pub resource_health: Option<&'a str>,
322
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>,
323
331
  }
324
332
 
325
333
  // ── Queue State ─────────────────────────────────────────────────
@@ -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,
@@ -1,7 +1,7 @@
1
1
  use diesel::prelude::*;
2
2
 
3
3
  use super::super::models::*;
4
- use super::super::schema::workers;
4
+ use super::super::schema::{execution_claims, workers};
5
5
  use super::PostgresStorage;
6
6
  use crate::error::Result;
7
7
  use crate::job::now_millis;
@@ -11,6 +11,7 @@ const DEAD_WORKER_THRESHOLD_MS: i64 = 30_000;
11
11
 
12
12
  impl PostgresStorage {
13
13
  /// Register a new worker or update an existing one.
14
+ #[allow(clippy::too_many_arguments)]
14
15
  pub fn register_worker(
15
16
  &self,
16
17
  worker_id: &str,
@@ -19,6 +20,9 @@ impl PostgresStorage {
19
20
  resources: Option<&str>,
20
21
  resource_health: Option<&str>,
21
22
  threads: i32,
23
+ hostname: Option<&str>,
24
+ pid: Option<i32>,
25
+ pool_type: Option<&str>,
22
26
  ) -> Result<()> {
23
27
  let mut conn = self.conn()?;
24
28
  let now = now_millis();
@@ -32,6 +36,10 @@ impl PostgresStorage {
32
36
  resources,
33
37
  resource_health,
34
38
  threads,
39
+ started_at: Some(now),
40
+ hostname,
41
+ pid,
42
+ pool_type,
35
43
  };
36
44
 
37
45
  diesel::insert_into(workers::table)
@@ -60,6 +68,18 @@ impl PostgresStorage {
60
68
  Ok(())
61
69
  }
62
70
 
71
+ /// Update the status of a worker.
72
+ pub fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()> {
73
+ let mut conn = self.conn()?;
74
+
75
+ diesel::update(workers::table)
76
+ .filter(workers::worker_id.eq(worker_id))
77
+ .set(workers::status.eq(status))
78
+ .execute(&mut conn)?;
79
+
80
+ Ok(())
81
+ }
82
+
63
83
  /// List all workers with their heartbeat status.
64
84
  pub fn list_workers(&self) -> Result<Vec<WorkerRow>> {
65
85
  let mut conn = self.conn()?;
@@ -72,14 +92,22 @@ impl PostgresStorage {
72
92
  }
73
93
 
74
94
  /// Remove workers that haven't sent a heartbeat within the threshold.
75
- pub fn reap_dead_workers(&self) -> Result<u64> {
95
+ /// Returns the IDs of the reaped workers.
96
+ pub fn reap_dead_workers(&self) -> Result<Vec<String>> {
76
97
  let mut conn = self.conn()?;
77
98
  let cutoff = now_millis().saturating_sub(DEAD_WORKER_THRESHOLD_MS);
78
99
 
79
- let affected = diesel::delete(workers::table.filter(workers::last_heartbeat.lt(cutoff)))
80
- .execute(&mut conn)?;
100
+ let dead_ids: Vec<String> = workers::table
101
+ .filter(workers::last_heartbeat.lt(cutoff))
102
+ .select(workers::worker_id)
103
+ .load(&mut conn)?;
104
+
105
+ if !dead_ids.is_empty() {
106
+ diesel::delete(workers::table.filter(workers::worker_id.eq_any(&dead_ids)))
107
+ .execute(&mut conn)?;
108
+ }
81
109
 
82
- Ok(affected as u64)
110
+ Ok(dead_ids)
83
111
  }
84
112
 
85
113
  /// Unregister a worker (called on shutdown).
@@ -91,4 +119,16 @@ impl PostgresStorage {
91
119
 
92
120
  Ok(())
93
121
  }
122
+
123
+ /// List all job IDs currently claimed by a worker.
124
+ pub fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>> {
125
+ let mut conn = self.conn()?;
126
+
127
+ let job_ids: Vec<String> = execution_claims::table
128
+ .filter(execution_claims::worker_id.eq(worker_id))
129
+ .select(execution_claims::job_id)
130
+ .load(&mut conn)?;
131
+
132
+ Ok(job_ids)
133
+ }
94
134
  }
@@ -8,6 +8,7 @@ use crate::storage::models::WorkerRow;
8
8
  const DEAD_WORKER_THRESHOLD_MS: i64 = 30_000;
9
9
 
10
10
  impl RedisStorage {
11
+ #[allow(clippy::too_many_arguments)]
11
12
  pub fn register_worker(
12
13
  &self,
13
14
  worker_id: &str,
@@ -16,6 +17,9 @@ impl RedisStorage {
16
17
  resources: Option<&str>,
17
18
  resource_health: Option<&str>,
18
19
  threads: i32,
20
+ hostname: Option<&str>,
21
+ pid: Option<i32>,
22
+ pool_type: Option<&str>,
19
23
  ) -> Result<()> {
20
24
  let mut conn = self.conn()?;
21
25
  let now = now_millis();
@@ -30,6 +34,10 @@ impl RedisStorage {
30
34
  pipe.hset(&wkey, "resources", resources.unwrap_or(""));
31
35
  pipe.hset(&wkey, "resource_health", resource_health.unwrap_or(""));
32
36
  pipe.hset(&wkey, "threads", threads);
37
+ pipe.hset(&wkey, "started_at", now);
38
+ pipe.hset(&wkey, "hostname", hostname.unwrap_or(""));
39
+ pipe.hset(&wkey, "pid", pid.unwrap_or(0));
40
+ pipe.hset(&wkey, "pool_type", pool_type.unwrap_or(""));
33
41
  pipe.sadd(&wall, worker_id);
34
42
  pipe.query::<()>(&mut conn).map_err(map_err)?;
35
43
 
@@ -49,6 +57,16 @@ impl RedisStorage {
49
57
  Ok(())
50
58
  }
51
59
 
60
+ pub fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()> {
61
+ let mut conn = self.conn()?;
62
+ let wkey = self.key(&["worker", worker_id]);
63
+
64
+ conn.hset::<_, _, _, ()>(&wkey, "status", status)
65
+ .map_err(map_err)?;
66
+
67
+ Ok(())
68
+ }
69
+
52
70
  pub fn list_workers(&self) -> Result<Vec<WorkerRow>> {
53
71
  let mut conn = self.conn()?;
54
72
  let wall = self.key(&["workers", "all"]);
@@ -89,43 +107,46 @@ impl RedisStorage {
89
107
  .get("threads")
90
108
  .and_then(|s| s.parse().ok())
91
109
  .unwrap_or(0),
110
+ started_at: data.get("started_at").and_then(|s| s.parse().ok()),
111
+ hostname: to_opt("hostname"),
112
+ pid: data
113
+ .get("pid")
114
+ .and_then(|s| s.parse().ok())
115
+ .filter(|&v: &i32| v != 0),
116
+ pool_type: to_opt("pool_type"),
92
117
  });
93
118
  }
94
119
 
95
120
  Ok(rows)
96
121
  }
97
122
 
98
- pub fn reap_dead_workers(&self) -> Result<u64> {
123
+ pub fn reap_dead_workers(&self) -> Result<Vec<String>> {
99
124
  let mut conn = self.conn()?;
100
125
  let cutoff = now_millis().saturating_sub(DEAD_WORKER_THRESHOLD_MS);
101
126
  let wall = self.key(&["workers", "all"]);
102
127
 
103
128
  let worker_ids: Vec<String> = conn.smembers(&wall).map_err(map_err)?;
104
129
 
105
- let mut count = 0u64;
130
+ let mut reaped = Vec::new();
106
131
  for wid in worker_ids {
107
132
  let wkey = self.key(&["worker", &wid]);
108
133
  let hb: Option<i64> = conn.hget(&wkey, "last_heartbeat").map_err(map_err)?;
109
134
 
110
- if let Some(last_hb) = hb {
111
- if last_hb < cutoff {
112
- let pipe = &mut redis::pipe();
113
- pipe.del(&wkey);
114
- pipe.srem(&wall, &wid);
115
- pipe.query::<()>(&mut conn).map_err(map_err)?;
116
- count += 1;
117
- }
118
- } else {
119
- // No heartbeat data — remove
135
+ let is_dead = match hb {
136
+ Some(last_hb) => last_hb < cutoff,
137
+ None => true,
138
+ };
139
+
140
+ if is_dead {
120
141
  let pipe = &mut redis::pipe();
121
142
  pipe.del(&wkey);
122
143
  pipe.srem(&wall, &wid);
123
144
  pipe.query::<()>(&mut conn).map_err(map_err)?;
124
- count += 1;
145
+ reaped.push(wid);
125
146
  }
126
147
  }
127
148
 
128
- Ok(count)
149
+ Ok(reaped)
129
150
  }
130
151
 
131
152
  pub fn unregister_worker(&self, worker_id: &str) -> Result<()> {
@@ -140,4 +161,43 @@ impl RedisStorage {
140
161
 
141
162
  Ok(())
142
163
  }
164
+
165
+ pub fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>> {
166
+ let mut conn = self.conn()?;
167
+ let pattern = self.key(&["exec_claim", "*"]);
168
+
169
+ let mut job_ids = Vec::new();
170
+ let mut cursor: u64 = 0;
171
+ loop {
172
+ let (next_cursor, keys): (u64, Vec<String>) = redis::cmd("SCAN")
173
+ .arg(cursor)
174
+ .arg("MATCH")
175
+ .arg(&pattern)
176
+ .arg("COUNT")
177
+ .arg(100)
178
+ .query(&mut conn)
179
+ .map_err(map_err)?;
180
+
181
+ for key in keys {
182
+ let value: Option<String> = conn.get(&key).map_err(map_err)?;
183
+ if let Some(val) = value {
184
+ // Value format is "{worker_id}:{timestamp}"
185
+ if val.starts_with(worker_id) && val[worker_id.len()..].starts_with(':') {
186
+ // Extract job_id from key: "{prefix}exec_claim:{job_id}"
187
+ let prefix = self.key(&["exec_claim", ""]);
188
+ if let Some(job_id) = key.strip_prefix(&prefix) {
189
+ job_ids.push(job_id.to_string());
190
+ }
191
+ }
192
+ }
193
+ }
194
+
195
+ cursor = next_cursor;
196
+ if cursor == 0 {
197
+ break;
198
+ }
199
+ }
200
+
201
+ Ok(job_ids)
202
+ }
143
203
  }
@@ -153,6 +153,10 @@ diesel::table! {
153
153
  resources -> Nullable<Text>,
154
154
  resource_health -> Nullable<Text>,
155
155
  threads -> Integer,
156
+ started_at -> Nullable<BigInt>,
157
+ hostname -> Nullable<Text>,
158
+ pid -> Nullable<Integer>,
159
+ pool_type -> Nullable<Text>,
156
160
  }
157
161
  }
158
162
 
@@ -356,6 +356,15 @@ impl SqliteStorage {
356
356
  "ALTER TABLE workers ADD COLUMN threads INTEGER NOT NULL DEFAULT 0",
357
357
  );
358
358
 
359
+ // Migration: add worker discovery metadata columns
360
+ migration_alter(
361
+ &mut conn,
362
+ "ALTER TABLE workers ADD COLUMN started_at INTEGER",
363
+ );
364
+ migration_alter(&mut conn, "ALTER TABLE workers ADD COLUMN hostname TEXT");
365
+ migration_alter(&mut conn, "ALTER TABLE workers ADD COLUMN pid INTEGER");
366
+ migration_alter(&mut conn, "ALTER TABLE workers ADD COLUMN pool_type TEXT");
367
+
359
368
  // ── Queue State ──────────────────────────────────
360
369
  diesel::sql_query(
361
370
  "CREATE TABLE IF NOT EXISTS queue_state (
@@ -1,7 +1,7 @@
1
1
  use diesel::prelude::*;
2
2
 
3
3
  use super::super::models::*;
4
- use super::super::schema::workers;
4
+ use super::super::schema::{execution_claims, workers};
5
5
  use super::SqliteStorage;
6
6
  use crate::error::Result;
7
7
  use crate::job::now_millis;
@@ -11,6 +11,7 @@ const DEAD_WORKER_THRESHOLD_MS: i64 = 30_000;
11
11
 
12
12
  impl SqliteStorage {
13
13
  /// Register a new worker or update an existing one.
14
+ #[allow(clippy::too_many_arguments)]
14
15
  pub fn register_worker(
15
16
  &self,
16
17
  worker_id: &str,
@@ -19,6 +20,9 @@ impl SqliteStorage {
19
20
  resources: Option<&str>,
20
21
  resource_health: Option<&str>,
21
22
  threads: i32,
23
+ hostname: Option<&str>,
24
+ pid: Option<i32>,
25
+ pool_type: Option<&str>,
22
26
  ) -> Result<()> {
23
27
  let mut conn = self.conn()?;
24
28
  let now = now_millis();
@@ -32,6 +36,10 @@ impl SqliteStorage {
32
36
  resources,
33
37
  resource_health,
34
38
  threads,
39
+ started_at: Some(now),
40
+ hostname,
41
+ pid,
42
+ pool_type,
35
43
  };
36
44
 
37
45
  diesel::replace_into(workers::table)
@@ -57,6 +65,18 @@ impl SqliteStorage {
57
65
  Ok(())
58
66
  }
59
67
 
68
+ /// Update the status of a worker.
69
+ pub fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()> {
70
+ let mut conn = self.conn()?;
71
+
72
+ diesel::update(workers::table)
73
+ .filter(workers::worker_id.eq(worker_id))
74
+ .set(workers::status.eq(status))
75
+ .execute(&mut conn)?;
76
+
77
+ Ok(())
78
+ }
79
+
60
80
  /// List all workers with their heartbeat status.
61
81
  pub fn list_workers(&self) -> Result<Vec<WorkerRow>> {
62
82
  let mut conn = self.conn()?;
@@ -69,14 +89,22 @@ impl SqliteStorage {
69
89
  }
70
90
 
71
91
  /// Remove workers that haven't sent a heartbeat within the threshold.
72
- pub fn reap_dead_workers(&self) -> Result<u64> {
92
+ /// Returns the IDs of the reaped workers.
93
+ pub fn reap_dead_workers(&self) -> Result<Vec<String>> {
73
94
  let mut conn = self.conn()?;
74
95
  let cutoff = now_millis().saturating_sub(DEAD_WORKER_THRESHOLD_MS);
75
96
 
76
- let affected = diesel::delete(workers::table.filter(workers::last_heartbeat.lt(cutoff)))
77
- .execute(&mut conn)?;
97
+ let dead_ids: Vec<String> = workers::table
98
+ .filter(workers::last_heartbeat.lt(cutoff))
99
+ .select(workers::worker_id)
100
+ .load(&mut conn)?;
101
+
102
+ if !dead_ids.is_empty() {
103
+ diesel::delete(workers::table.filter(workers::worker_id.eq_any(&dead_ids)))
104
+ .execute(&mut conn)?;
105
+ }
78
106
 
79
- Ok(affected as u64)
107
+ Ok(dead_ids)
80
108
  }
81
109
 
82
110
  /// Unregister a worker (called on shutdown).
@@ -88,4 +116,16 @@ impl SqliteStorage {
88
116
 
89
117
  Ok(())
90
118
  }
119
+
120
+ /// List all job IDs currently claimed by a worker.
121
+ pub fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>> {
122
+ let mut conn = self.conn()?;
123
+
124
+ let job_ids: Vec<String> = execution_claims::table
125
+ .filter(execution_claims::worker_id.eq(worker_id))
126
+ .select(execution_claims::job_id)
127
+ .load(&mut conn)?;
128
+
129
+ Ok(job_ids)
130
+ }
91
131
  }
@@ -119,6 +119,7 @@ pub trait Storage: Send + Sync + Clone {
119
119
 
120
120
  // ── Worker operations ───────────────────────────────────────────
121
121
 
122
+ #[allow(clippy::too_many_arguments)]
122
123
  fn register_worker(
123
124
  &self,
124
125
  worker_id: &str,
@@ -127,11 +128,16 @@ pub trait Storage: Send + Sync + Clone {
127
128
  resources: Option<&str>,
128
129
  resource_health: Option<&str>,
129
130
  threads: i32,
131
+ hostname: Option<&str>,
132
+ pid: Option<i32>,
133
+ pool_type: Option<&str>,
130
134
  ) -> Result<()>;
131
135
  fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()>;
136
+ fn update_worker_status(&self, worker_id: &str, status: &str) -> Result<()>;
132
137
  fn list_workers(&self) -> Result<Vec<WorkerRow>>;
133
- fn reap_dead_workers(&self) -> Result<u64>;
138
+ fn reap_dead_workers(&self) -> Result<Vec<String>>;
134
139
  fn unregister_worker(&self, worker_id: &str) -> Result<()>;
140
+ fn list_claims_by_worker(&self, worker_id: &str) -> Result<Vec<String>>;
135
141
 
136
142
  // ── Queue pause/resume ───────────────────────────────────────
137
143
 
@@ -165,8 +165,18 @@ fn test_workers(s: &impl Storage) {
165
165
  let resources = Some(r#"["db","redis"]"#);
166
166
  let health = Some(r#"{"db":"healthy","redis":"healthy"}"#);
167
167
 
168
- s.register_worker("w-test-1", "q-workers", None, resources, health, 4)
169
- .unwrap();
168
+ s.register_worker(
169
+ "w-test-1",
170
+ "q-workers",
171
+ None,
172
+ resources,
173
+ health,
174
+ 4,
175
+ Some("test-host"),
176
+ Some(12345),
177
+ Some("thread"),
178
+ )
179
+ .unwrap();
170
180
  s.heartbeat("w-test-1", Some(r#"{"db":"unhealthy","redis":"healthy"}"#))
171
181
  .unwrap();
172
182
 
@@ -176,6 +186,16 @@ fn test_workers(s: &impl Storage) {
176
186
  assert_eq!(w.threads, 4);
177
187
  assert!(w.resources.as_deref().unwrap().contains("db"));
178
188
  assert!(w.resource_health.as_deref().unwrap().contains("unhealthy"));
189
+ assert_eq!(w.hostname.as_deref(), Some("test-host"));
190
+ assert_eq!(w.pid, Some(12345));
191
+ assert_eq!(w.pool_type.as_deref(), Some("thread"));
192
+ assert!(w.started_at.is_some());
193
+
194
+ // Test update_worker_status
195
+ s.update_worker_status("w-test-1", "draining").unwrap();
196
+ let workers = s.list_workers().unwrap();
197
+ let w = workers.iter().find(|w| w.worker_id == "w-test-1").unwrap();
198
+ assert_eq!(w.status, "draining");
179
199
 
180
200
  s.unregister_worker("w-test-1").unwrap();
181
201
  }
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "taskito-python"
3
- version = "0.8.0"
3
+ version = "0.9.0"
4
4
  edition = "2021"
5
5
 
6
6
  [features]
@@ -23,4 +23,7 @@ uuid = { workspace = true }
23
23
  async-trait = { workspace = true }
24
24
  taskito-async = { path = "../taskito-async", optional = true }
25
25
  serde_json = { workspace = true }
26
+ serde = { workspace = true }
27
+ base64 = "0.22"
26
28
  log = { workspace = true }
29
+ gethostname = "1.1.0"
@@ -2,6 +2,7 @@ use pyo3::prelude::*;
2
2
 
3
3
  #[cfg(not(feature = "native-async"))]
4
4
  mod async_worker;
5
+ mod prefork;
5
6
  mod py_config;
6
7
  mod py_job;
7
8
  mod py_queue;