taskito 0.4.0__tar.gz → 0.5.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.
- {taskito-0.4.0 → taskito-0.5.0}/Cargo.lock +20 -8
- {taskito-0.4.0 → taskito-0.5.0}/PKG-INFO +6 -3
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/Cargo.toml +1 -1
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/mod.rs +31 -7
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/models.rs +6 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/mod.rs +14 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/workers.rs +17 -3
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/workers.rs +26 -10
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/schema.rs +3 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/mod.rs +11 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/workers.rs +17 -3
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/traits.rs +10 -2
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/tests/rust/storage_tests.rs +11 -2
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/Cargo.toml +3 -1
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/lib.rs +3 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_queue/inspection.rs +3 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_queue/worker.rs +79 -23
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/__init__.py +23 -1
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/_taskito.pyi +39 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/app.py +462 -80
- taskito-0.5.0/py_src/taskito/async_support/__init__.py +25 -0
- taskito-0.5.0/py_src/taskito/async_support/context.py +32 -0
- taskito-0.5.0/py_src/taskito/async_support/executor.py +218 -0
- taskito-0.5.0/py_src/taskito/async_support/helpers.py +17 -0
- taskito-0.5.0/py_src/taskito/async_support/locks.py +95 -0
- taskito-0.5.0/py_src/taskito/async_support/mixins.py +183 -0
- taskito-0.5.0/py_src/taskito/async_support/result.py +61 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/cli.py +111 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/context.py +10 -3
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/fastapi.py +5 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/prometheus.py +126 -3
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/dashboard.py +82 -29
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/exceptions.py +28 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/health.py +16 -0
- taskito-0.5.0/py_src/taskito/inject.py +42 -0
- taskito-0.5.0/py_src/taskito/interception/__init__.py +25 -0
- taskito-0.5.0/py_src/taskito/interception/built_in.py +363 -0
- taskito-0.5.0/py_src/taskito/interception/converters.py +243 -0
- taskito-0.5.0/py_src/taskito/interception/errors.py +45 -0
- taskito-0.5.0/py_src/taskito/interception/interceptor.py +207 -0
- taskito-0.5.0/py_src/taskito/interception/metrics.py +46 -0
- taskito-0.5.0/py_src/taskito/interception/reconstruct.py +69 -0
- taskito-0.5.0/py_src/taskito/interception/registry.py +86 -0
- taskito-0.5.0/py_src/taskito/interception/strategy.py +13 -0
- taskito-0.5.0/py_src/taskito/interception/walker.py +266 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/locks.py +6 -80
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/mixins.py +3 -95
- taskito-0.5.0/py_src/taskito/proxies/__init__.py +14 -0
- taskito-0.5.0/py_src/taskito/proxies/built_in.py +77 -0
- taskito-0.5.0/py_src/taskito/proxies/handler.py +30 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/__init__.py +9 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/boto3_client.py +54 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/file.py +78 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/gcs_client.py +75 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/httpx_client.py +61 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/logger.py +32 -0
- taskito-0.5.0/py_src/taskito/proxies/handlers/requests_session.py +49 -0
- taskito-0.5.0/py_src/taskito/proxies/metrics.py +86 -0
- taskito-0.5.0/py_src/taskito/proxies/no_proxy.py +22 -0
- taskito-0.5.0/py_src/taskito/proxies/reconstruct.py +203 -0
- taskito-0.5.0/py_src/taskito/proxies/registry.py +32 -0
- taskito-0.5.0/py_src/taskito/proxies/schema.py +50 -0
- taskito-0.5.0/py_src/taskito/proxies/signing.py +35 -0
- taskito-0.5.0/py_src/taskito/resources/__init__.py +22 -0
- taskito-0.5.0/py_src/taskito/resources/definition.py +39 -0
- taskito-0.5.0/py_src/taskito/resources/frozen.py +40 -0
- taskito-0.5.0/py_src/taskito/resources/graph.py +76 -0
- taskito-0.5.0/py_src/taskito/resources/health.py +105 -0
- taskito-0.5.0/py_src/taskito/resources/pool.py +144 -0
- taskito-0.5.0/py_src/taskito/resources/runtime.py +266 -0
- taskito-0.5.0/py_src/taskito/resources/thread_local.py +61 -0
- taskito-0.5.0/py_src/taskito/resources/toml_config.py +117 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/result.py +3 -47
- taskito-0.5.0/py_src/taskito/scaler.py +121 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/task.py +21 -0
- taskito-0.5.0/py_src/taskito/templates/dashboard.css +368 -0
- taskito-0.5.0/py_src/taskito/templates/dashboard.html +40 -0
- taskito-0.5.0/py_src/taskito/templates/js/actions.js +34 -0
- taskito-0.5.0/py_src/taskito/templates/js/app.js +93 -0
- taskito-0.5.0/py_src/taskito/templates/js/chart.js +150 -0
- taskito-0.5.0/py_src/taskito/templates/js/components.js +58 -0
- taskito-0.5.0/py_src/taskito/templates/js/utils.js +19 -0
- taskito-0.5.0/py_src/taskito/templates/js/views.js +348 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/testing.py +73 -1
- {taskito-0.4.0 → taskito-0.5.0}/pyproject.toml +5 -4
- taskito-0.4.0/py_src/taskito/templates/dashboard.html +0 -1226
- {taskito-0.4.0 → taskito-0.5.0}/Cargo.toml +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/LICENSE +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/README.md +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/error.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/job.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/lib.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/periodic.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/resilience/circuit_breaker.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/resilience/dlq.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/resilience/mod.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/resilience/rate_limiter.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/resilience/retry.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/scheduler/maintenance.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/scheduler/mod.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/scheduler/poller.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/scheduler/result_handler.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/diesel_common/jobs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/diesel_common/locks.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/diesel_common/logs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/diesel_common/metrics.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/diesel_common/mod.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/archival.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/circuit_breakers.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/dead_letter.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/jobs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/locks.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/logs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/metrics.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/periodic.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/queue_state.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/rate_limits.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/postgres/trait_impl.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/archival.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/circuit_breakers.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/dead_letter.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/jobs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/locks.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/logs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/metrics.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/mod.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/periodic.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/queue_state.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/rate_limits.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/redis_backend/trait_impl.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/archival.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/circuit_breakers.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/dead_letter.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/jobs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/locks.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/logs.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/metrics.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/periodic.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/queue_state.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/rate_limits.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/tests.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/storage/sqlite/trait_impl.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/src/worker.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-core/tests/rust.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/async_worker.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_config.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_job.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_queue/mod.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/crates/taskito-python/src/py_worker.rs +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/canvas.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/__init__.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/__init__.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/admin.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/apps.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/management/__init__.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/management/commands/__init__.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/management/commands/taskito_dashboard.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/management/commands/taskito_info.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/management/commands/taskito_worker.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/django/settings.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/flask.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/otel.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/contrib/sentry.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/events.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/middleware.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/py.typed +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/serializers.py +0 -0
- {taskito-0.4.0 → taskito-0.5.0}/py_src/taskito/webhooks.py +0 -0
|
@@ -194,9 +194,9 @@ dependencies = [
|
|
|
194
194
|
|
|
195
195
|
[[package]]
|
|
196
196
|
name = "diesel"
|
|
197
|
-
version = "2.3.
|
|
197
|
+
version = "2.3.7"
|
|
198
198
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
199
|
-
checksum = "
|
|
199
|
+
checksum = "f4ae09a41a4b89f94ec1e053623da8340d996bc32c6517d325a9daad9b239358"
|
|
200
200
|
dependencies = [
|
|
201
201
|
"bitflags",
|
|
202
202
|
"byteorder",
|
|
@@ -693,9 +693,9 @@ dependencies = [
|
|
|
693
693
|
|
|
694
694
|
[[package]]
|
|
695
695
|
name = "once_cell"
|
|
696
|
-
version = "1.21.
|
|
696
|
+
version = "1.21.4"
|
|
697
697
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
698
|
-
checksum = "
|
|
698
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
699
699
|
|
|
700
700
|
[[package]]
|
|
701
701
|
name = "openssl-src"
|
|
@@ -708,9 +708,9 @@ dependencies = [
|
|
|
708
708
|
|
|
709
709
|
[[package]]
|
|
710
710
|
name = "openssl-sys"
|
|
711
|
-
version = "0.9.
|
|
711
|
+
version = "0.9.112"
|
|
712
712
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
713
|
-
checksum = "
|
|
713
|
+
checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb"
|
|
714
714
|
dependencies = [
|
|
715
715
|
"cc",
|
|
716
716
|
"libc",
|
|
@@ -1199,9 +1199,20 @@ version = "0.12.16"
|
|
|
1199
1199
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1200
1200
|
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|
1201
1201
|
|
|
1202
|
+
[[package]]
|
|
1203
|
+
name = "taskito-async"
|
|
1204
|
+
version = "0.5.0"
|
|
1205
|
+
dependencies = [
|
|
1206
|
+
"async-trait",
|
|
1207
|
+
"crossbeam-channel",
|
|
1208
|
+
"pyo3",
|
|
1209
|
+
"taskito-core",
|
|
1210
|
+
"tokio",
|
|
1211
|
+
]
|
|
1212
|
+
|
|
1202
1213
|
[[package]]
|
|
1203
1214
|
name = "taskito-core"
|
|
1204
|
-
version = "0.
|
|
1215
|
+
version = "0.5.0"
|
|
1205
1216
|
dependencies = [
|
|
1206
1217
|
"async-trait",
|
|
1207
1218
|
"chrono",
|
|
@@ -1225,11 +1236,12 @@ dependencies = [
|
|
|
1225
1236
|
|
|
1226
1237
|
[[package]]
|
|
1227
1238
|
name = "taskito-python"
|
|
1228
|
-
version = "0.
|
|
1239
|
+
version = "0.5.0"
|
|
1229
1240
|
dependencies = [
|
|
1230
1241
|
"async-trait",
|
|
1231
1242
|
"crossbeam-channel",
|
|
1232
1243
|
"pyo3",
|
|
1244
|
+
"taskito-async",
|
|
1233
1245
|
"taskito-core",
|
|
1234
1246
|
"tokio",
|
|
1235
1247
|
"uuid",
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskito
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
9
8
|
Classifier: Programming Language :: Python :: 3.10
|
|
10
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
11
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -14,6 +13,7 @@ Classifier: Programming Language :: Rust
|
|
|
14
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
14
|
Classifier: Topic :: System :: Distributed Computing
|
|
16
15
|
Requires-Dist: cloudpickle>=3.0
|
|
16
|
+
Requires-Dist: boto3>=1.20 ; extra == 'aws'
|
|
17
17
|
Requires-Dist: pytest>=7.0 ; extra == 'dev'
|
|
18
18
|
Requires-Dist: pytest-asyncio>=0.21 ; extra == 'dev'
|
|
19
19
|
Requires-Dist: pytest-cov>=4.0 ; extra == 'dev'
|
|
@@ -25,17 +25,20 @@ Requires-Dist: cryptography ; extra == 'encryption'
|
|
|
25
25
|
Requires-Dist: fastapi>=0.100.0 ; extra == 'fastapi'
|
|
26
26
|
Requires-Dist: pydantic>=2.0 ; extra == 'fastapi'
|
|
27
27
|
Requires-Dist: flask>=2.0 ; extra == 'flask'
|
|
28
|
+
Requires-Dist: google-cloud-storage>=2.0 ; extra == 'gcs'
|
|
28
29
|
Requires-Dist: msgpack ; extra == 'msgpack'
|
|
29
30
|
Requires-Dist: opentelemetry-api ; extra == 'otel'
|
|
30
31
|
Requires-Dist: opentelemetry-sdk ; extra == 'otel'
|
|
31
32
|
Requires-Dist: prometheus-client ; extra == 'prometheus'
|
|
32
33
|
Requires-Dist: sentry-sdk ; extra == 'sentry'
|
|
34
|
+
Provides-Extra: aws
|
|
33
35
|
Provides-Extra: dev
|
|
34
36
|
Provides-Extra: django
|
|
35
37
|
Provides-Extra: docs
|
|
36
38
|
Provides-Extra: encryption
|
|
37
39
|
Provides-Extra: fastapi
|
|
38
40
|
Provides-Extra: flask
|
|
41
|
+
Provides-Extra: gcs
|
|
39
42
|
Provides-Extra: msgpack
|
|
40
43
|
Provides-Extra: otel
|
|
41
44
|
Provides-Extra: postgres
|
|
@@ -44,7 +47,7 @@ Provides-Extra: redis
|
|
|
44
47
|
Provides-Extra: sentry
|
|
45
48
|
License-File: LICENSE
|
|
46
49
|
Summary: Rust-powered task queue for Python. No broker required.
|
|
47
|
-
Requires-Python: >=3.
|
|
50
|
+
Requires-Python: >=3.10
|
|
48
51
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
49
52
|
Project-URL: Changelog, https://github.com/pratyush618/taskito/blob/master/docs/changelog.md
|
|
50
53
|
Project-URL: Documentation, https://taskito.grigori.in
|
|
@@ -344,11 +344,18 @@ macro_rules! impl_storage {
|
|
|
344
344
|
worker_id: &str,
|
|
345
345
|
queues: &str,
|
|
346
346
|
tags: Option<&str>,
|
|
347
|
+
resources: Option<&str>,
|
|
348
|
+
resource_health: Option<&str>,
|
|
349
|
+
threads: i32,
|
|
347
350
|
) -> $crate::error::Result<()> {
|
|
348
|
-
self.register_worker(worker_id, queues, tags)
|
|
351
|
+
self.register_worker(worker_id, queues, tags, resources, resource_health, threads)
|
|
349
352
|
}
|
|
350
|
-
fn heartbeat(
|
|
351
|
-
self
|
|
353
|
+
fn heartbeat(
|
|
354
|
+
&self,
|
|
355
|
+
worker_id: &str,
|
|
356
|
+
resource_health: Option<&str>,
|
|
357
|
+
) -> $crate::error::Result<()> {
|
|
358
|
+
self.heartbeat(worker_id, resource_health)
|
|
352
359
|
}
|
|
353
360
|
fn list_workers(
|
|
354
361
|
&self,
|
|
@@ -705,11 +712,28 @@ impl Storage for StorageBackend {
|
|
|
705
712
|
fn list_circuit_breakers(&self) -> Result<Vec<models::CircuitBreakerRow>> {
|
|
706
713
|
delegate!(self, list_circuit_breakers)
|
|
707
714
|
}
|
|
708
|
-
fn register_worker(
|
|
709
|
-
|
|
715
|
+
fn register_worker(
|
|
716
|
+
&self,
|
|
717
|
+
worker_id: &str,
|
|
718
|
+
queues: &str,
|
|
719
|
+
tags: Option<&str>,
|
|
720
|
+
resources: Option<&str>,
|
|
721
|
+
resource_health: Option<&str>,
|
|
722
|
+
threads: i32,
|
|
723
|
+
) -> Result<()> {
|
|
724
|
+
delegate!(
|
|
725
|
+
self,
|
|
726
|
+
register_worker,
|
|
727
|
+
worker_id,
|
|
728
|
+
queues,
|
|
729
|
+
tags,
|
|
730
|
+
resources,
|
|
731
|
+
resource_health,
|
|
732
|
+
threads
|
|
733
|
+
)
|
|
710
734
|
}
|
|
711
|
-
fn heartbeat(&self, worker_id: &str) -> Result<()> {
|
|
712
|
-
delegate!(self, heartbeat, worker_id)
|
|
735
|
+
fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
|
|
736
|
+
delegate!(self, heartbeat, worker_id, resource_health)
|
|
713
737
|
}
|
|
714
738
|
fn list_workers(&self) -> Result<Vec<models::WorkerRow>> {
|
|
715
739
|
delegate!(self, list_workers)
|
|
@@ -284,6 +284,9 @@ pub struct WorkerRow {
|
|
|
284
284
|
pub queues: String,
|
|
285
285
|
pub status: String,
|
|
286
286
|
pub tags: Option<String>,
|
|
287
|
+
pub resources: Option<String>,
|
|
288
|
+
pub resource_health: Option<String>,
|
|
289
|
+
pub threads: i32,
|
|
287
290
|
}
|
|
288
291
|
|
|
289
292
|
#[derive(Insertable, AsChangeset, Debug)]
|
|
@@ -294,6 +297,9 @@ pub struct NewWorkerRow<'a> {
|
|
|
294
297
|
pub queues: &'a str,
|
|
295
298
|
pub status: &'a str,
|
|
296
299
|
pub tags: Option<&'a str>,
|
|
300
|
+
pub resources: Option<&'a str>,
|
|
301
|
+
pub resource_health: Option<&'a str>,
|
|
302
|
+
pub threads: i32,
|
|
297
303
|
}
|
|
298
304
|
|
|
299
305
|
// ── Queue State ─────────────────────────────────────────────────
|
|
@@ -340,6 +340,20 @@ impl PostgresStorage {
|
|
|
340
340
|
"ALTER TABLE workers ADD COLUMN IF NOT EXISTS tags TEXT",
|
|
341
341
|
);
|
|
342
342
|
|
|
343
|
+
// Migration: add resource advertisement columns to workers
|
|
344
|
+
migration_alter(
|
|
345
|
+
&mut conn,
|
|
346
|
+
"ALTER TABLE workers ADD COLUMN IF NOT EXISTS resources TEXT",
|
|
347
|
+
);
|
|
348
|
+
migration_alter(
|
|
349
|
+
&mut conn,
|
|
350
|
+
"ALTER TABLE workers ADD COLUMN IF NOT EXISTS resource_health TEXT",
|
|
351
|
+
);
|
|
352
|
+
migration_alter(
|
|
353
|
+
&mut conn,
|
|
354
|
+
"ALTER TABLE workers ADD COLUMN IF NOT EXISTS threads INTEGER NOT NULL DEFAULT 0",
|
|
355
|
+
);
|
|
356
|
+
|
|
343
357
|
diesel::sql_query(
|
|
344
358
|
"CREATE TABLE IF NOT EXISTS queue_state (
|
|
345
359
|
queue_name TEXT PRIMARY KEY,
|
|
@@ -11,7 +11,15 @@ 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
|
-
pub fn register_worker(
|
|
14
|
+
pub fn register_worker(
|
|
15
|
+
&self,
|
|
16
|
+
worker_id: &str,
|
|
17
|
+
queues: &str,
|
|
18
|
+
tags: Option<&str>,
|
|
19
|
+
resources: Option<&str>,
|
|
20
|
+
resource_health: Option<&str>,
|
|
21
|
+
threads: i32,
|
|
22
|
+
) -> Result<()> {
|
|
15
23
|
let mut conn = self.conn()?;
|
|
16
24
|
let now = now_millis();
|
|
17
25
|
|
|
@@ -21,6 +29,9 @@ impl PostgresStorage {
|
|
|
21
29
|
queues,
|
|
22
30
|
status: "active",
|
|
23
31
|
tags,
|
|
32
|
+
resources,
|
|
33
|
+
resource_health,
|
|
34
|
+
threads,
|
|
24
35
|
};
|
|
25
36
|
|
|
26
37
|
diesel::insert_into(workers::table)
|
|
@@ -34,13 +45,16 @@ impl PostgresStorage {
|
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
/// Update the heartbeat timestamp for a worker.
|
|
37
|
-
pub fn heartbeat(&self, worker_id: &str) -> Result<()> {
|
|
48
|
+
pub fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
|
|
38
49
|
let mut conn = self.conn()?;
|
|
39
50
|
let now = now_millis();
|
|
40
51
|
|
|
41
52
|
diesel::update(workers::table)
|
|
42
53
|
.filter(workers::worker_id.eq(worker_id))
|
|
43
|
-
.set(
|
|
54
|
+
.set((
|
|
55
|
+
workers::last_heartbeat.eq(now),
|
|
56
|
+
workers::resource_health.eq(resource_health),
|
|
57
|
+
))
|
|
44
58
|
.execute(&mut conn)?;
|
|
45
59
|
|
|
46
60
|
Ok(())
|
|
@@ -8,7 +8,15 @@ use crate::storage::models::WorkerRow;
|
|
|
8
8
|
const DEAD_WORKER_THRESHOLD_MS: i64 = 30_000;
|
|
9
9
|
|
|
10
10
|
impl RedisStorage {
|
|
11
|
-
pub fn register_worker(
|
|
11
|
+
pub fn register_worker(
|
|
12
|
+
&self,
|
|
13
|
+
worker_id: &str,
|
|
14
|
+
queues: &str,
|
|
15
|
+
tags: Option<&str>,
|
|
16
|
+
resources: Option<&str>,
|
|
17
|
+
resource_health: Option<&str>,
|
|
18
|
+
threads: i32,
|
|
19
|
+
) -> Result<()> {
|
|
12
20
|
let mut conn = self.conn()?;
|
|
13
21
|
let now = now_millis();
|
|
14
22
|
let wkey = self.key(&["worker", worker_id]);
|
|
@@ -19,19 +27,24 @@ impl RedisStorage {
|
|
|
19
27
|
pipe.hset(&wkey, "queues", queues);
|
|
20
28
|
pipe.hset(&wkey, "status", "active");
|
|
21
29
|
pipe.hset(&wkey, "tags", tags.unwrap_or(""));
|
|
30
|
+
pipe.hset(&wkey, "resources", resources.unwrap_or(""));
|
|
31
|
+
pipe.hset(&wkey, "resource_health", resource_health.unwrap_or(""));
|
|
32
|
+
pipe.hset(&wkey, "threads", threads);
|
|
22
33
|
pipe.sadd(&wall, worker_id);
|
|
23
34
|
pipe.query::<()>(&mut conn).map_err(map_err)?;
|
|
24
35
|
|
|
25
36
|
Ok(())
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
pub fn heartbeat(&self, worker_id: &str) -> Result<()> {
|
|
39
|
+
pub fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
|
|
29
40
|
let mut conn = self.conn()?;
|
|
30
41
|
let now = now_millis();
|
|
31
42
|
let wkey = self.key(&["worker", worker_id]);
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
let pipe = &mut redis::pipe();
|
|
45
|
+
pipe.hset(&wkey, "last_heartbeat", now);
|
|
46
|
+
pipe.hset(&wkey, "resource_health", resource_health.unwrap_or(""));
|
|
47
|
+
pipe.query::<()>(&mut conn).map_err(map_err)?;
|
|
35
48
|
|
|
36
49
|
Ok(())
|
|
37
50
|
}
|
|
@@ -52,7 +65,8 @@ impl RedisStorage {
|
|
|
52
65
|
continue;
|
|
53
66
|
}
|
|
54
67
|
|
|
55
|
-
let
|
|
68
|
+
let to_opt =
|
|
69
|
+
|key: &str| -> Option<String> { data.get(key).filter(|s| !s.is_empty()).cloned() };
|
|
56
70
|
|
|
57
71
|
rows.push(WorkerRow {
|
|
58
72
|
worker_id: wid,
|
|
@@ -68,11 +82,13 @@ impl RedisStorage {
|
|
|
68
82
|
.get("status")
|
|
69
83
|
.cloned()
|
|
70
84
|
.unwrap_or_else(|| "active".to_string()),
|
|
71
|
-
tags:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
tags: to_opt("tags"),
|
|
86
|
+
resources: to_opt("resources"),
|
|
87
|
+
resource_health: to_opt("resource_health"),
|
|
88
|
+
threads: data
|
|
89
|
+
.get("threads")
|
|
90
|
+
.and_then(|s| s.parse().ok())
|
|
91
|
+
.unwrap_or(0),
|
|
76
92
|
});
|
|
77
93
|
}
|
|
78
94
|
|
|
@@ -340,6 +340,17 @@ impl SqliteStorage {
|
|
|
340
340
|
// Migration: add tags column to workers
|
|
341
341
|
migration_alter(&mut conn, "ALTER TABLE workers ADD COLUMN tags TEXT");
|
|
342
342
|
|
|
343
|
+
// Migration: add resource advertisement columns to workers
|
|
344
|
+
migration_alter(&mut conn, "ALTER TABLE workers ADD COLUMN resources TEXT");
|
|
345
|
+
migration_alter(
|
|
346
|
+
&mut conn,
|
|
347
|
+
"ALTER TABLE workers ADD COLUMN resource_health TEXT",
|
|
348
|
+
);
|
|
349
|
+
migration_alter(
|
|
350
|
+
&mut conn,
|
|
351
|
+
"ALTER TABLE workers ADD COLUMN threads INTEGER NOT NULL DEFAULT 0",
|
|
352
|
+
);
|
|
353
|
+
|
|
343
354
|
// ── Queue State ──────────────────────────────────
|
|
344
355
|
diesel::sql_query(
|
|
345
356
|
"CREATE TABLE IF NOT EXISTS queue_state (
|
|
@@ -11,7 +11,15 @@ 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
|
-
pub fn register_worker(
|
|
14
|
+
pub fn register_worker(
|
|
15
|
+
&self,
|
|
16
|
+
worker_id: &str,
|
|
17
|
+
queues: &str,
|
|
18
|
+
tags: Option<&str>,
|
|
19
|
+
resources: Option<&str>,
|
|
20
|
+
resource_health: Option<&str>,
|
|
21
|
+
threads: i32,
|
|
22
|
+
) -> Result<()> {
|
|
15
23
|
let mut conn = self.conn()?;
|
|
16
24
|
let now = now_millis();
|
|
17
25
|
|
|
@@ -21,6 +29,9 @@ impl SqliteStorage {
|
|
|
21
29
|
queues,
|
|
22
30
|
status: "active",
|
|
23
31
|
tags,
|
|
32
|
+
resources,
|
|
33
|
+
resource_health,
|
|
34
|
+
threads,
|
|
24
35
|
};
|
|
25
36
|
|
|
26
37
|
diesel::replace_into(workers::table)
|
|
@@ -31,13 +42,16 @@ impl SqliteStorage {
|
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
/// Update the heartbeat timestamp for a worker.
|
|
34
|
-
pub fn heartbeat(&self, worker_id: &str) -> Result<()> {
|
|
45
|
+
pub fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()> {
|
|
35
46
|
let mut conn = self.conn()?;
|
|
36
47
|
let now = now_millis();
|
|
37
48
|
|
|
38
49
|
diesel::update(workers::table)
|
|
39
50
|
.filter(workers::worker_id.eq(worker_id))
|
|
40
|
-
.set(
|
|
51
|
+
.set((
|
|
52
|
+
workers::last_heartbeat.eq(now),
|
|
53
|
+
workers::resource_health.eq(resource_health),
|
|
54
|
+
))
|
|
41
55
|
.execute(&mut conn)?;
|
|
42
56
|
|
|
43
57
|
Ok(())
|
|
@@ -113,8 +113,16 @@ pub trait Storage: Send + Sync + Clone {
|
|
|
113
113
|
|
|
114
114
|
// ── Worker operations ───────────────────────────────────────────
|
|
115
115
|
|
|
116
|
-
fn register_worker(
|
|
117
|
-
|
|
116
|
+
fn register_worker(
|
|
117
|
+
&self,
|
|
118
|
+
worker_id: &str,
|
|
119
|
+
queues: &str,
|
|
120
|
+
tags: Option<&str>,
|
|
121
|
+
resources: Option<&str>,
|
|
122
|
+
resource_health: Option<&str>,
|
|
123
|
+
threads: i32,
|
|
124
|
+
) -> Result<()>;
|
|
125
|
+
fn heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> Result<()>;
|
|
118
126
|
fn list_workers(&self) -> Result<Vec<WorkerRow>>;
|
|
119
127
|
fn reap_dead_workers(&self) -> Result<u64>;
|
|
120
128
|
fn unregister_worker(&self, worker_id: &str) -> Result<()>;
|
|
@@ -162,11 +162,20 @@ fn test_record_and_get_errors(s: &impl Storage) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
fn test_workers(s: &impl Storage) {
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
let resources = Some(r#"["db","redis"]"#);
|
|
166
|
+
let health = Some(r#"{"db":"healthy","redis":"healthy"}"#);
|
|
167
|
+
|
|
168
|
+
s.register_worker("w-test-1", "q-workers", None, resources, health, 4)
|
|
169
|
+
.unwrap();
|
|
170
|
+
s.heartbeat("w-test-1", Some(r#"{"db":"unhealthy","redis":"healthy"}"#))
|
|
171
|
+
.unwrap();
|
|
167
172
|
|
|
168
173
|
let workers = s.list_workers().unwrap();
|
|
169
174
|
assert!(!workers.is_empty());
|
|
175
|
+
let w = workers.iter().find(|w| w.worker_id == "w-test-1").unwrap();
|
|
176
|
+
assert_eq!(w.threads, 4);
|
|
177
|
+
assert!(w.resources.as_deref().unwrap().contains("db"));
|
|
178
|
+
assert!(w.resource_health.as_deref().unwrap().contains("unhealthy"));
|
|
170
179
|
|
|
171
180
|
s.unregister_worker("w-test-1").unwrap();
|
|
172
181
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "taskito-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
[features]
|
|
@@ -8,6 +8,7 @@ default = []
|
|
|
8
8
|
extension-module = ["pyo3/extension-module"]
|
|
9
9
|
postgres = ["taskito-core/postgres"]
|
|
10
10
|
redis = ["taskito-core/redis"]
|
|
11
|
+
native-async = ["dep:taskito-async"]
|
|
11
12
|
|
|
12
13
|
[lib]
|
|
13
14
|
name = "_taskito"
|
|
@@ -20,3 +21,4 @@ tokio = { workspace = true }
|
|
|
20
21
|
crossbeam-channel = { workspace = true }
|
|
21
22
|
uuid = { workspace = true }
|
|
22
23
|
async-trait = { workspace = true }
|
|
24
|
+
taskito-async = { path = "../taskito-async", optional = true }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
use pyo3::prelude::*;
|
|
2
2
|
|
|
3
|
+
#[cfg(not(feature = "native-async"))]
|
|
3
4
|
mod async_worker;
|
|
4
5
|
mod py_config;
|
|
5
6
|
mod py_job;
|
|
@@ -15,5 +16,7 @@ fn _taskito(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
15
16
|
m.add_class::<PyQueue>()?;
|
|
16
17
|
m.add_class::<PyJob>()?;
|
|
17
18
|
m.add_class::<PyTaskConfig>()?;
|
|
19
|
+
#[cfg(feature = "native-async")]
|
|
20
|
+
m.add_class::<taskito_async::PyResultSender>()?;
|
|
18
21
|
Ok(())
|
|
19
22
|
}
|
|
@@ -371,6 +371,9 @@ impl PyQueue {
|
|
|
371
371
|
dict.set_item("queues", r.queues)?;
|
|
372
372
|
dict.set_item("status", r.status)?;
|
|
373
373
|
dict.set_item("tags", r.tags)?;
|
|
374
|
+
dict.set_item("resources", r.resources)?;
|
|
375
|
+
dict.set_item("resource_health", r.resource_health)?;
|
|
376
|
+
dict.set_item("threads", r.threads)?;
|
|
374
377
|
result.push(dict.into());
|
|
375
378
|
}
|
|
376
379
|
Ok(result)
|
|
@@ -11,6 +11,7 @@ use taskito_core::scheduler::{JobResult, Scheduler, SchedulerConfig, TaskConfig}
|
|
|
11
11
|
use taskito_core::storage::Storage;
|
|
12
12
|
|
|
13
13
|
use super::PyQueue;
|
|
14
|
+
#[cfg(not(feature = "native-async"))]
|
|
14
15
|
use crate::async_worker::AsyncWorkerPool;
|
|
15
16
|
use crate::py_config::PyTaskConfig;
|
|
16
17
|
|
|
@@ -18,7 +19,21 @@ use crate::py_config::PyTaskConfig;
|
|
|
18
19
|
#[allow(clippy::useless_conversion)]
|
|
19
20
|
impl PyQueue {
|
|
20
21
|
/// Run the worker loop. This blocks until interrupted.
|
|
21
|
-
|
|
22
|
+
///
|
|
23
|
+
/// The heartbeat is now driven from Python (see `worker_heartbeat`),
|
|
24
|
+
/// so the internal Rust heartbeat thread is removed.
|
|
25
|
+
#[pyo3(signature = (
|
|
26
|
+
task_registry,
|
|
27
|
+
task_configs,
|
|
28
|
+
queues=None,
|
|
29
|
+
drain_timeout_secs=None,
|
|
30
|
+
tags=None,
|
|
31
|
+
worker_id=None,
|
|
32
|
+
resources=None,
|
|
33
|
+
threads=1,
|
|
34
|
+
async_concurrency=100,
|
|
35
|
+
))]
|
|
36
|
+
#[allow(clippy::too_many_arguments)]
|
|
22
37
|
pub fn run_worker(
|
|
23
38
|
&self,
|
|
24
39
|
py: Python<'_>,
|
|
@@ -27,6 +42,10 @@ impl PyQueue {
|
|
|
27
42
|
queues: Option<Vec<String>>,
|
|
28
43
|
drain_timeout_secs: Option<u64>,
|
|
29
44
|
tags: Option<String>,
|
|
45
|
+
worker_id: Option<String>,
|
|
46
|
+
resources: Option<String>,
|
|
47
|
+
threads: i32,
|
|
48
|
+
#[allow(unused_variables)] async_concurrency: i32,
|
|
30
49
|
) -> PyResult<()> {
|
|
31
50
|
// Reset shutdown flag for this run
|
|
32
51
|
self.shutdown_flag.store(false, Ordering::SeqCst);
|
|
@@ -113,25 +132,39 @@ impl PyQueue {
|
|
|
113
132
|
let scheduler_arc = Arc::new(scheduler);
|
|
114
133
|
let scheduler_for_dispatch = scheduler_arc.clone();
|
|
115
134
|
|
|
116
|
-
// Generate
|
|
117
|
-
let worker_id = uuid::Uuid::now_v7().to_string();
|
|
118
|
-
let _ = self
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
// Generate or use the provided worker ID and register
|
|
136
|
+
let worker_id = worker_id.unwrap_or_else(|| uuid::Uuid::now_v7().to_string());
|
|
137
|
+
let _ = self.storage.register_worker(
|
|
138
|
+
&worker_id,
|
|
139
|
+
&queues_str,
|
|
140
|
+
tags.as_deref(),
|
|
141
|
+
resources.as_deref(),
|
|
142
|
+
None,
|
|
143
|
+
threads,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Create the async executor for native async tasks (if feature enabled)
|
|
147
|
+
#[cfg(feature = "native-async")]
|
|
148
|
+
let async_executor = {
|
|
149
|
+
let sender = taskito_async::PyResultSender::new(result_tx.clone());
|
|
150
|
+
Python::with_gil(|py| -> PyResult<Arc<PyObject>> {
|
|
151
|
+
let sender_obj = pyo3::Py::new(py, sender)?;
|
|
152
|
+
let mod_ = py.import_bound("taskito.async_support.executor")?;
|
|
153
|
+
let cls = mod_.getattr("AsyncTaskExecutor")?;
|
|
154
|
+
let context_mod = py.import_bound("taskito.context")?;
|
|
155
|
+
let queue_ref = context_mod.getattr("_queue_ref")?;
|
|
156
|
+
let executor = cls.call1((
|
|
157
|
+
sender_obj,
|
|
158
|
+
registry_arc.clone_ref(py),
|
|
159
|
+
queue_ref,
|
|
160
|
+
async_concurrency,
|
|
161
|
+
))?;
|
|
162
|
+
executor.call_method0("start")?;
|
|
163
|
+
Ok(Arc::new(executor.into_py(py)))
|
|
164
|
+
})?
|
|
165
|
+
};
|
|
133
166
|
|
|
134
|
-
// Create multi-threaded tokio runtime for scheduler +
|
|
167
|
+
// Create multi-threaded tokio runtime for scheduler + worker pool
|
|
135
168
|
let num_workers = self.num_workers;
|
|
136
169
|
// Move result_tx into the runtime — don't keep a copy in the main thread
|
|
137
170
|
// so result_rx disconnects when all workers are done.
|
|
@@ -149,15 +182,29 @@ impl PyQueue {
|
|
|
149
182
|
};
|
|
150
183
|
|
|
151
184
|
rt.block_on(async {
|
|
152
|
-
let pool = AsyncWorkerPool::new(num_workers, registry_arc, filters_arc);
|
|
153
|
-
|
|
154
185
|
let scheduler_task = tokio::spawn(async move {
|
|
155
186
|
scheduler_for_dispatch.run(job_tx).await;
|
|
156
187
|
});
|
|
157
188
|
|
|
158
189
|
let worker_task = tokio::spawn(async move {
|
|
159
190
|
use taskito_core::worker::WorkerDispatcher;
|
|
160
|
-
|
|
191
|
+
|
|
192
|
+
#[cfg(feature = "native-async")]
|
|
193
|
+
{
|
|
194
|
+
let pool = taskito_async::NativeAsyncPool::new(
|
|
195
|
+
num_workers,
|
|
196
|
+
registry_arc,
|
|
197
|
+
filters_arc,
|
|
198
|
+
async_executor,
|
|
199
|
+
);
|
|
200
|
+
pool.run(job_rx, result_tx).await;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
#[cfg(not(feature = "native-async"))]
|
|
204
|
+
{
|
|
205
|
+
let pool = AsyncWorkerPool::new(num_workers, registry_arc, filters_arc);
|
|
206
|
+
pool.run(job_rx, result_tx).await;
|
|
207
|
+
}
|
|
161
208
|
});
|
|
162
209
|
|
|
163
210
|
let _ = tokio::join!(scheduler_task, worker_task);
|
|
@@ -245,11 +292,20 @@ impl PyQueue {
|
|
|
245
292
|
}
|
|
246
293
|
|
|
247
294
|
let _ = runtime_handle.join();
|
|
248
|
-
let _ = heartbeat_handle.join();
|
|
249
295
|
|
|
250
296
|
// Unregister worker on shutdown
|
|
251
297
|
let _ = self.storage.unregister_worker(&worker_id);
|
|
252
298
|
|
|
253
299
|
Ok(())
|
|
254
300
|
}
|
|
301
|
+
|
|
302
|
+
/// Update the heartbeat for a running worker. Called from Python every 5s.
|
|
303
|
+
#[pyo3(signature = (worker_id, resource_health=None))]
|
|
304
|
+
pub fn worker_heartbeat(&self, worker_id: &str, resource_health: Option<&str>) -> PyResult<()> {
|
|
305
|
+
self.storage
|
|
306
|
+
.heartbeat(worker_id, resource_health)
|
|
307
|
+
.map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
|
|
308
|
+
let _ = self.storage.reap_dead_workers();
|
|
309
|
+
Ok(())
|
|
310
|
+
}
|
|
255
311
|
}
|