From 62943ea592af670b3598395ac593dcc2ec46512f Mon Sep 17 00:00:00 2001 From: geofmureithi Date: Sat, 25 Jul 2026 14:23:24 +0300 Subject: [PATCH] api: standardize `Config` by adding `Backend::Config` --- CHANGELOG.md | 3 +- Cargo.lock | 235 ++++++++++-------- apalis-core/Cargo.toml | 16 +- apalis-core/README.md | 16 +- apalis-core/src/backend/custom.rs | 28 +-- apalis-core/src/backend/expose.rs | 6 +- apalis-core/src/backend/ext/delegate.rs | 6 +- apalis-core/src/backend/ext/inspect_err.rs | 14 +- apalis-core/src/backend/ext/map_err.rs | 14 +- apalis-core/src/backend/ext/mod.rs | 4 +- apalis-core/src/backend/ext/pipe.rs | 71 +++--- apalis-core/src/backend/ext/raw.rs | 8 +- apalis-core/src/backend/ext/with_codec.rs | 15 +- .../src/backend/ext/with_poll_strategy.rs | 9 +- apalis-core/src/backend/factory.rs | 33 +++ apalis-core/src/backend/impls/dequeue.rs | 16 +- apalis-core/src/backend/impls/memory.rs | 74 +++--- apalis-core/src/backend/mod.rs | 23 +- apalis-core/src/backend/poll_strategy/mod.rs | 2 +- apalis-core/src/backend/queue.rs | 5 +- apalis-core/src/backend/shared.rs | 33 --- apalis-core/src/backend/sink.rs | 11 +- apalis-core/src/lib.rs | 14 +- apalis-core/src/macros.rs | 2 +- apalis-core/src/monitor/mod.rs | 22 +- apalis-core/src/task/attempt.rs | 4 +- apalis-core/src/task/builder.rs | 16 +- apalis-core/src/task/data.rs | 12 +- apalis-core/src/task/metadata.rs | 21 +- apalis-core/src/task/mod.rs | 50 ++-- apalis-core/src/task/task_id.rs | 8 +- apalis-core/src/task_fn/from_request.rs | 4 +- apalis-core/src/task_fn/guide.rs | 4 +- apalis-core/src/task_fn/mod.rs | 56 ++--- apalis-core/src/worker/builder.rs | 73 +++--- apalis-core/src/worker/call_all.rs | 12 +- apalis-core/src/worker/context.rs | 6 +- apalis-core/src/worker/ext/ack/mod.rs | 48 ++-- .../src/worker/ext/circuit_breaker/mod.rs | 14 +- .../src/worker/ext/event_listener/mod.rs | 16 +- .../src/worker/ext/long_running/mod.rs | 24 +- apalis-core/src/worker/ext/mod.rs | 10 +- apalis-core/src/worker/ext/parallelize/mod.rs | 17 +- apalis-core/src/worker/mod.rs | 32 ++- apalis-core/src/worker/test_worker.rs | 49 ++-- apalis-sql/src/from_row.rs | 7 +- apalis-workflow/Cargo.toml | 16 +- apalis-workflow/src/dag/executor.rs | 15 +- apalis-workflow/src/dag/mod.rs | 22 +- apalis-workflow/src/dag/node.rs | 15 +- apalis-workflow/src/dag/service.rs | 13 +- apalis-workflow/src/id_generator.rs | 2 +- apalis-workflow/src/lib.rs | 5 +- .../src/sequential/and_then/mod.rs | 25 +- apalis-workflow/src/sequential/delay/mod.rs | 29 +-- .../src/sequential/filter_map/mod.rs | 26 +- apalis-workflow/src/sequential/fold/mod.rs | 26 +- .../src/sequential/repeat_until/mod.rs | 28 +-- apalis-workflow/src/sequential/router.rs | 2 +- apalis-workflow/src/sequential/service.rs | 16 +- apalis-workflow/src/sequential/workflow.rs | 6 +- apalis-workflow/src/sink.rs | 5 +- apalis/Cargo.toml | 20 +- apalis/src/layers/catch_panic/mod.rs | 14 +- apalis/src/layers/mod.rs | 82 +++--- apalis/src/layers/opentelemetry/mod.rs | 7 +- apalis/src/layers/prometheus/mod.rs | 6 +- apalis/src/layers/retry/mod.rs | 34 ++- apalis/src/layers/sentry/mod.rs | 6 +- apalis/src/layers/tracing/contextual_span.rs | 4 +- apalis/src/layers/tracing/make_span.rs | 18 +- apalis/src/layers/tracing/mod.rs | 21 +- apalis/src/layers/tracing/on_request.rs | 14 +- apalis/src/lib.rs | 2 +- examples/basics/Cargo.toml | 4 +- examples/catch-panic/Cargo.toml | 2 +- examples/dag-workflow/Cargo.toml | 2 +- examples/dynamic-workers/Cargo.toml | 2 +- examples/email-service/Cargo.toml | 4 +- examples/fn-args/Cargo.toml | 2 +- examples/graceful-shutdown/Cargo.toml | 4 +- examples/long-running/Cargo.toml | 2 +- examples/monitor/Cargo.toml | 2 +- examples/opentelemetry/Cargo.toml | 4 +- examples/prometheus/Cargo.toml | 10 +- examples/retries/Cargo.toml | 2 +- examples/sentry/Cargo.toml | 8 +- examples/stepped-workflow/Cargo.toml | 2 +- examples/tracing/Cargo.toml | 2 +- examples/unique-jobs/Cargo.toml | 2 +- examples/unmonitored-worker/Cargo.toml | 2 +- supply-chain/config.toml | 90 ++++--- utils/apalis-codec/Cargo.toml | 2 +- utils/apalis-file-storage/Cargo.toml | 12 +- utils/apalis-file-storage/src/lib.rs | 44 ++-- utils/apalis-file-storage/src/shared.rs | 71 ++---- utils/apalis-file-storage/src/sink.rs | 19 +- utils/apalis-file-storage/src/util.rs | 2 +- 98 files changed, 880 insertions(+), 1058 deletions(-) create mode 100644 apalis-core/src/backend/factory.rs delete mode 100644 apalis-core/src/backend/shared.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 86cb0fd8..cb7ece72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,8 @@ All notable changes to this project are documented in this file. ### Breaking Changes -- **api**: `Parts` becomes to `ExecutionContext` and merges Ctx into the task ([#751](https://github.com/apalis-dev/apalis/pull/751)) +- **api**: standardize `Config` by adding `Backend::Config` and drops `Backend::Connection` ([#772](https://github.com/apalis-dev/apalis/pull/772)) +- **api**: `Parts` becomes `ExecutionContext` and merges Ctx into the task ([#751](https://github.com/apalis-dev/apalis/pull/751)) - **api**: Changed `Task` to `Task` ([#751](https://github.com/apalis-dev/apalis/pull/751)) - **crates**: Moved backend crates to respective repos ([#586](https://github.com/apalis-dev/apalis/pull/586)) - **api**: `Backend` must be the second input in `WorkerBuilder` ([#586](https://github.com/apalis-dev/apalis/pull/586)) diff --git a/Cargo.lock b/Cargo.lock index 9b5c9232..fc2ca1f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "apalis" @@ -337,7 +337,7 @@ dependencies = [ "apalis-file-storage", "futures", "petgraph", - "rand 0.9.5", + "rand 0.10.2", "serde", "serde_json", "thiserror", @@ -350,13 +350,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -373,9 +373,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.17.1" +version = "1.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" +checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" dependencies = [ "aws-lc-sys", "zeroize", @@ -383,9 +383,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.42.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" +checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" dependencies = [ "cc", "cmake", @@ -455,7 +455,7 @@ checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -585,9 +585,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.67" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "jobserver", @@ -740,7 +740,7 @@ dependencies = [ "defmt-parser", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -790,7 +790,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.119", "unicode-xid", ] @@ -812,7 +812,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -850,9 +850,9 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "email-service" @@ -893,7 +893,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -948,9 +948,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fd-lock" @@ -1050,9 +1050,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" dependencies = [ "futures-channel", "futures-core", @@ -1065,9 +1065,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", "futures-sink", @@ -1075,15 +1075,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" dependencies = [ "futures-core", "futures-task", @@ -1092,32 +1092,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-timer" @@ -1127,9 +1127,9 @@ checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-channel", "futures-core", @@ -1264,9 +1264,9 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hdrhistogram" -version = "7.5.4" +version = "7.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +checksum = "f49d1053f4708f0af3cf9fc5bffc7e68a914a3c45becb231c80068c9c3f78bea" dependencies = [ "byteorder", "num-traits", @@ -1347,9 +1347,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" dependencies = [ "atomic-waker", "bytes", @@ -1551,9 +1551,9 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.3.1" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a84fd5aa25fae5c0f4a33d9cac2ca017fc622cbd089be2229993514990f870" +checksum = "277ff51754a3f68f12f58446c5d006aa8baa4914ea273cce24a599cfaff33d4f" [[package]] name = "indexmap" @@ -1594,11 +1594,12 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961d16382652bfdd8c6f68b223b26a8c93e0d475c672f414411db31c6c5c900e" +checksum = "e184d09547b80eb7e20d141ba2fb1fbac843ca53f4cf1b31210adc4c1adc6e16" dependencies = [ "defmt", + "jiff-core", "jiff-static", "log", "portable-atomic", @@ -1606,15 +1607,25 @@ dependencies = [ "serde_core", ] +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + [[package]] name = "jiff-static" -version = "0.2.32" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0879bd39df99c4c5e2c6615ccc026391a423dde10532c573e6086eb94a802cc" +checksum = "323da076b7a6faf914dc677cb05a4b907742ff7375c8322c9e7f5061e5e0e9de" dependencies = [ + "jiff-core", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -1652,9 +1663,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "left-right" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0c21e4c8ff95f487fb34e6f9182875f42c84cef966d29216bf115d9bba835a" +checksum = "8bc015ded5d9b3054dbbdb63332cdd6ee42352ccef19e911e25117490e2f48ee" dependencies = [ "crossbeam-utils", "loom", @@ -1663,9 +1674,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "linux-raw-sys" @@ -2102,7 +2113,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2308,7 +2319,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2325,9 +2336,9 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" [[package]] name = "portable-atomic-util" @@ -2364,9 +2375,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -2423,7 +2434,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -2443,9 +2454,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -2721,9 +2732,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] @@ -2955,9 +2966,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -2965,29 +2976,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -3119,6 +3130,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3136,7 +3158,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3154,22 +3176,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -3183,9 +3205,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.53" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" dependencies = [ "deranged", "num-conv", @@ -3203,9 +3225,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -3223,9 +3245,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.53.0" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ "bytes", "libc", @@ -3246,7 +3268,7 @@ checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3271,13 +3293,14 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", + "libc", "pin-project-lite", "tokio", ] @@ -3352,7 +3375,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3448,9 +3471,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ulid" -version = "2.0.1" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39493d572b98fe1d142e132e7a726c50c68121bce84429216a5ec20e1ad7fec5" +checksum = "947dde63b6d514cc5e044edad4e0ca7261afd1099d16c83d942cb2b2f348689c" dependencies = [ "rand 0.10.2", "uuid", @@ -3679,7 +3702,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] @@ -3714,9 +3737,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" dependencies = [ "rustls-pki-types", ] @@ -3764,7 +3787,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3775,7 +3798,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3924,28 +3947,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.54" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.54" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -3965,7 +3988,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", "synstructure", ] @@ -4005,7 +4028,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] diff --git a/apalis-core/Cargo.toml b/apalis-core/Cargo.toml index 0d62057a..031d612e 100644 --- a/apalis-core/Cargo.toml +++ b/apalis-core/Cargo.toml @@ -15,24 +15,24 @@ publish = true [dependencies] serde = { version = "1.0", features = ["derive"], optional = true } -futures-util = { version = "0.3.30", features = [ +futures-util = { version = "0.3.33", features = [ "sink", "async-await", "async-await-macro", "std", ], default-features = false } -futures-core = { version = "0.3.30", default-features = false } -futures-channel = { version = "0.3.30", features = [ +futures-core = { version = "0.3.33", default-features = false } +futures-channel = { version = "0.3.33", features = [ "sink", "std", ], default-features = false } -futures-sink = { version = "0.3.30", default-features = false } +futures-sink = { version = "0.3.33", default-features = false } tower-service = "0.3.3" tower-layer = "0.3.3" pin-project = "1" -thiserror = "2.0.0" -futures-timer = { version = "3.0.3", optional = true } -tracing = { version = "0.1.41", default-features = false, optional = true } +thiserror = "2.0.19" +futures-timer = { version = "3.0.4", optional = true } +tracing = { version = "0.1.44", default-features = false, optional = true } [dependencies.document-features] version = "0.2" @@ -58,7 +58,7 @@ all-features = true [dev-dependencies] -tokio = { version = "1.37.0", features = [ +tokio = { version = "1.53.1", features = [ "macros", "rt", "sync", diff --git a/apalis-core/README.md b/apalis-core/README.md index 1cba3c54..20d26d51 100644 --- a/apalis-core/README.md +++ b/apalis-core/README.md @@ -20,10 +20,10 @@ The framework leverages the `tower` service abstraction to provide a rich middle ecosystem like error handling, timeouts, rate limiting, and observability. - ### Tasks The task struct provides type-safe components for task data and metadata: + - [`Args`](crate::task_fn::guide) - The primary structure for the task - [`ExecutionContext`](crate::task::ExecutionContext) - Wrapper type for information for task execution includes context, status, attempts, task_id and metadata - [`Context`](crate::backend::Backend#required-associated-types) - contextual information with the task provided by the backend @@ -43,9 +43,11 @@ let task: Task = TaskBuilder::new("my-task".to_string()) .run_in_minutes(10) .build(); ``` + Specific documentation for tasks can be found in the [`task`] and [`task::builder`] modules. ##### Relevant Guides: + - [**Defining Task arguments**](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/task_fn/guide/index.html) - Creating effective task arguments that are scalable and type-safe ### Backends @@ -56,17 +58,16 @@ It defines task polling mechanisms, streaming interfaces, and middleware integra
Associated Types: -- `Stream` - Defines the task stream type for polling operations - `Layer` - Specifies the middleware layer stack for the backend - `Codec` - Determines serialization format for task data persistence -- `Beat` - Heartbeat stream for worker liveness checks - `Id` - Type used for unique task identifiers -- `Conn` - Context associated with tasks +- `Config` - Config for the backend - `Error` - Error type for backend operations
#### Inbuilt Implementations + - [`MemoryStorage`](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/backend/memory/struct.MemoryStorage.html) : In-memory storage based on channels - [`Pipe`](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/backend/pipe/index.html) : Pipe-based backend for a stream-to-backend pipeline - [`CustomBackend`](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/backend/custom/index.html) : Flexible backend composition allowing custom functions for task management @@ -96,6 +97,7 @@ The following are the main components the worker module: - [`Ext`](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/worker/ext/index.html) - Extension traits and middleware for adding functionality to workers #### Example: Building and Running a Worker + ```rust #[tokio::main] async fn main() { @@ -125,6 +127,7 @@ async fn main() { Learn more about workers in the [`worker`](crate::worker) and [`worker::builder`](crate::worker::builder) modules. ##### Relevant Tutorials: + - [**Creating task handlers**](crate::task_fn::guide) - Defining task processing functions using the [`TaskFn`] trait - [**Testing task handlers with `TestWorker`**](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/worker/test_worker/index.html) - Specialized worker implementation for unit and integration testing @@ -133,10 +136,12 @@ Learn more about workers in the [`worker`](crate::worker) and [`worker::builder` The [`Monitor`](https://docs.rs/apalis-core/1.0.0-rc.9/apalis_core/monitor/struct.Monitor.html) helps manage and coordinate multiple workers: **Main Features:** + - **Worker Registry** - Keeps track of active workers - **Event Handling** - Handles and processes worker events - **Graceful Shutdown** - Stops all workers together safely - **Health Monitoring** - Restarts and manages worker health + #### Example: Using `Monitor` with a Worker ```rust @@ -170,6 +175,7 @@ Built on the `tower` ecosystem, `apalis-core` provides extensive middleware supp #### Core Middleware The following middleware layers are included with their worker extensions: + - [`AcknowledgmentLayer`] - Task acknowledgment after processing - [`EventListenerLayer`] - Worker event emission and handling - [`CircuitBreakerLayer`] - Circuit breaker pattern for failure handling @@ -224,6 +230,7 @@ impl Layer for LoggingLayer { } } ``` + If you want your middleware to do more than just intercept requests and responses, you can use extension traits. See the [`worker::ext`](crate::worker::ext) module for examples. @@ -245,6 +252,7 @@ appropriate retry behavior for different failure scenarios. workers stop safely and all tasks finish before shutting down: **Key Features:** + - Task tracking: Workers keep track of how many tasks are running. - Shutdown control: The system waits until all tasks are finished before shutting down. - Monitor coordination: A shared [`Shutdown`] token helps all workers stop together. diff --git a/apalis-core/src/backend/custom.rs b/apalis-core/src/backend/custom.rs index ce05b05b..e28d5aa4 100644 --- a/apalis-core/src/backend/custom.rs +++ b/apalis-core/src/backend/custom.rs @@ -34,7 +34,7 @@ //! #[tokio::main] //! async fn main() { //! // Create a memory-backed VecDeque -//! let memory = Arc::new(Mutex::new(VecDeque::>::new())); +//! let memory = Arc::new(Mutex::new(VecDeque::>::new())); //! //! // Build the custom backend //! let mut backend = BackendBuilder::new() @@ -100,7 +100,6 @@ use thiserror::Error; use tower_layer::Identity; use crate::backend::codec::IdentityCodec; -use crate::backend::queue::Queue; use crate::error::BoxDynError; use crate::features_table; use crate::{backend::Backend, task::Task, worker::context::WorkerContext}; @@ -131,7 +130,7 @@ type Sinker = Arc Sink + Send FetchById => not_supported("Allow fetching a task by its ID"), RegisterWorker => not_implemented("Allow registering a worker with the backend"), PipeExt => limited("Allow other backends to pipe to this backend", false), // Would require Clone, - MakeShared => not_implemented("Share the same [`CustomBackend`] across multiple workers", false), + BackendFactory => not_implemented("Share the same [`CustomBackend`] across multiple workers", false), Workflow => not_implemented("Flexible enough to support workflows"), WaitForCompletion => not_implemented("Wait for tasks to complete without blocking"), // Would require Clone ResumeById => not_supported("Resume a task by its ID"), @@ -347,19 +346,20 @@ pub enum CustomBackendError { Inner(#[from] BoxDynError), } -impl Backend +impl Backend for CustomBackend where - Fetch: Stream>, E>> + Unpin + Send + 'static, - S: Sink, Error = E> + Unpin + Send + 'static, + Fetch: Stream>, E>> + Unpin + Send + 'static, + S: Sink, Error = E> + Unpin + Send + 'static, E: Into, Id: Clone + Send + Sync + 'static, Args: Clone, + Config: Default, { type Args = Args; type Id = Id; - type Connection = Conn; + type Config = Config; type Error = CustomBackendError; @@ -373,8 +373,8 @@ where &IdentityCodec } - fn queue(&self) -> Queue { - Queue::from(std::any::type_name::()) + fn config(&self) -> &Self::Config { + &self.config } fn middleware(&self) -> Self::Layer { @@ -393,7 +393,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { if self.stream.is_none() { self.stream = Some((self.fetcher)(&mut self.db, &self.config, worker)); } @@ -417,10 +417,10 @@ where } } -impl Sink> +impl Sink> for CustomBackend where - S: Sink>, + S: Sink>, S::Error: Into, { type Error = CustomBackendError; @@ -432,7 +432,7 @@ where .map_err(|e| CustomBackendError::Inner(e.into())) } - fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { self.project() .current_sink .start_send_unpin(item) @@ -472,7 +472,7 @@ mod tests { #[tokio::test] async fn basic_custom_backend() { - let memory: Arc>>> = + let memory: Arc>>> = Arc::new(Mutex::new(VecDeque::new())); let mut backend = BackendBuilder::new() diff --git a/apalis-core/src/backend/expose.rs b/apalis-core/src/backend/expose.rs index 52d53a6b..eed767d4 100644 --- a/apalis-core/src/backend/expose.rs +++ b/apalis-core/src/backend/expose.rs @@ -43,7 +43,7 @@ pub trait ListTasks: Backend { fn list_tasks( &self, filter: &Filter, - ) -> impl Future>, Self::Error>> + Send; + ) -> impl Future>, Self::Error>> + Send; } /// Allows listing tasks across all queues with optional filtering @@ -53,9 +53,7 @@ pub trait ListAllTasks: Backend { fn list_all_tasks( &self, filter: &Filter, - ) -> impl Future< - Output = Result>, Self::Error>, - > + Send; + ) -> impl Future>, Self::Error>> + Send; } /// Allows collecting metrics from the backend diff --git a/apalis-core/src/backend/ext/delegate.rs b/apalis-core/src/backend/ext/delegate.rs index f435b089..4be7dbf2 100644 --- a/apalis-core/src/backend/ext/delegate.rs +++ b/apalis-core/src/backend/ext/delegate.rs @@ -99,7 +99,7 @@ macro_rules! delegate_expose { async fn fetch_by_id( &mut self, task_id: &$crate::task::task_id::TaskId, - ) -> Result>, Self::Error> { + ) -> Result>, Self::Error> { let $result = self.$field.fetch_by_id(task_id).await; #[allow(unused_variables)] let $this = &*self; @@ -115,7 +115,7 @@ macro_rules! delegate_expose { { async fn update( &mut self, - task: Task, + task: Task, ) -> Result<(), Self::Error> { let $result = self.$field.update(task).await; #[allow(unused_variables)] @@ -132,7 +132,7 @@ macro_rules! delegate_expose { { async fn reschedule( &mut self, - task: Task, + task: Task, wait: std::time::Duration, ) -> Result<(), Self::Error> { let $result = self.$field.reschedule(task, wait).await; diff --git a/apalis-core/src/backend/ext/inspect_err.rs b/apalis-core/src/backend/ext/inspect_err.rs index 9596b575..c07630ff 100644 --- a/apalis-core/src/backend/ext/inspect_err.rs +++ b/apalis-core/src/backend/ext/inspect_err.rs @@ -7,11 +7,7 @@ use futures_sink::Sink; use futures_util::SinkExt; use futures_util::TryStreamExt; -use crate::{ - backend::{queue::Queue, *}, - task::Task, - worker::context::WorkerContext, -}; +use crate::{backend::*, task::Task, worker::context::WorkerContext}; /// A `Backend` wrapper that runs a callback `F` on each error yielded by the poll stream. #[derive(Debug, Clone)] @@ -27,7 +23,7 @@ where { type Args = B::Args; type Id = B::Id; - type Connection = B::Connection; + type Config = B::Config; type Error = B::Error; type Codec = B::Codec; type Compact = B::Compact; @@ -37,8 +33,8 @@ where self.backend.codec() } - fn queue(&self) -> Queue { - self.backend.queue() + fn config(&self) -> &Self::Config { + self.backend.config() } fn middleware(&self) -> Self::Layer { @@ -60,7 +56,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.backend.poll_next(cx, worker).map(|opt| { opt.map(|res| { res.inspect_err(|err| { diff --git a/apalis-core/src/backend/ext/map_err.rs b/apalis-core/src/backend/ext/map_err.rs index 073abd99..96225f2b 100644 --- a/apalis-core/src/backend/ext/map_err.rs +++ b/apalis-core/src/backend/ext/map_err.rs @@ -7,11 +7,7 @@ use futures_sink::Sink; use futures_util::SinkExt; use futures_util::TryStreamExt; -use crate::{ - backend::{queue::Queue, *}, - task::Task, - worker::context::WorkerContext, -}; +use crate::{backend::*, task::Task, worker::context::WorkerContext}; /// A `Backend` wrapper that maps the backend's error type `Self::Error` into `E2`. #[derive(Debug, Clone)] @@ -28,7 +24,7 @@ where { type Args = B::Args; type Id = B::Id; - type Connection = B::Connection; + type Config = B::Config; type Error = E2; type Codec = B::Codec; type Compact = B::Compact; @@ -38,8 +34,8 @@ where self.backend.codec() } - fn queue(&self) -> Queue { - self.backend.queue() + fn config(&self) -> &Self::Config { + self.backend.config() } fn middleware(&self) -> Self::Layer { @@ -60,7 +56,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.backend .poll_next(cx, worker) .map(|opt| opt.map(|res| res.map_err(|err| (self.f)(err)))) diff --git a/apalis-core/src/backend/ext/mod.rs b/apalis-core/src/backend/ext/mod.rs index 0a25ac3f..c871a2c8 100644 --- a/apalis-core/src/backend/ext/mod.rs +++ b/apalis-core/src/backend/ext/mod.rs @@ -68,7 +68,7 @@ pub trait BackendExt: Backend { &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, PollNextArgsError>>> + ) -> Poll, PollNextArgsError>>> where Self: Sized, >::Error: std::error::Error, @@ -93,7 +93,7 @@ pub trait BackendExt: Backend { /// Useful for bridging two backend implementations — e.g. draining an /// ephemeral/legacy queue into a durable one, or fanning a lightweight /// source into a shared sink that multiple producers write into. - fn pipe_to(self, backend: Dst) -> Pipe, Self::Args, Dst::Connection> + fn pipe_to(self, backend: Dst) -> Pipe, Self::Args> where Self: Sized, Dst: Backend, diff --git a/apalis-core/src/backend/ext/pipe.rs b/apalis-core/src/backend/ext/pipe.rs index a8f837e8..8190b65e 100644 --- a/apalis-core/src/backend/ext/pipe.rs +++ b/apalis-core/src/backend/ext/pipe.rs @@ -54,7 +54,6 @@ use std::{ }; use crate::backend::ext::{BackendExt, PollNextArgsError}; -use crate::backend::queue::Queue; use crate::backend::*; use crate::error::BoxDynError; use crate::features_table; @@ -72,10 +71,10 @@ use futures_util::TryStreamExt; TaskSink => supported("Ability to push new tasks", false), InheritsFeatures => limited("Inherits features from the underlying backend", false), }] -pub struct Pipe { +pub struct Pipe { pub(crate) from: S, pub(crate) into: Dst, - pub(crate) _req: PhantomData<(Args, Conn)>, + pub(crate) _req: PhantomData, } /// Adapts a [`Backend`] into an [`IntoArgsStream`] source, so it can be @@ -114,7 +113,7 @@ impl fmt::Debug for FromBackend { /// /// [`Pipe`] is generic over this trait rather than over `Stream` directly, /// which is what lets one `Pipe` type serve both streams and backends. -pub trait PipeNextStream { +pub trait PipeNextStream { /// The error type yielded alongside `Args` on failure. type Error; @@ -125,16 +124,15 @@ pub trait PipeNextStream { &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>>; + ) -> Poll, Self::Error>>>; } // Plain-stream case: any stream of `Result` is already exactly // what we need, so this is just a passthrough. -impl PipeNextStream for S +impl PipeNextStream for S where S: Stream> + Send + Unpin + 'static, Args: 'static, - Conn: 'static, Id: 'static, Err: 'static, { @@ -144,7 +142,7 @@ where &mut self, cx: &mut Context<'_>, _: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { let next = Stream::poll_next(Pin::new(self), cx); next.map(|item| item.map(|res| res.map(TaskBuilder::new).map(|t| t.build()))) } @@ -152,14 +150,13 @@ where // Backend case: poll the backend, drop `None`s (no task available right // now), and project each `Task` down to its `args`. -impl PipeNextStream for FromBackend +impl PipeNextStream for FromBackend where B: Backend + Send + 'static, B::Error: std::error::Error + Send + Sync + 'static, B::Args: Send + 'static, B::Id: Display, Id: 'static, - Conn: 'static, >::Error: std::error::Error + Send + Sync + 'static, { type Error = PollNextArgsError; @@ -168,17 +165,17 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { let next = self.0.poll_next_args(cx, worker); next.map(|item| match item { - Some(Ok(task)) => Some(Ok(task.map_backend::())), + Some(Ok(task)) => Some(Ok(task.map_id_type::())), Some(Err(e)) => Some(Err(e)), None => None, }) } } -impl Deref for Pipe { +impl Deref for Pipe { type Target = Dst; fn deref(&self) -> &Self::Target { @@ -186,13 +183,13 @@ impl Deref for Pipe { } } -impl DerefMut for Pipe { +impl DerefMut for Pipe { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.into } } -impl Pipe { +impl Pipe { /// Create a new `Pipe` from a raw `from` source and an `into` sink. /// Prefer [`PipeExt::pipe_to`] or [`BackendExt::pipe_to`] over calling /// this directly. @@ -205,7 +202,7 @@ impl Pipe { } } -impl fmt::Debug for Pipe { +impl fmt::Debug for Pipe { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Pipe") .field("from", &self.from) @@ -214,29 +211,28 @@ impl fmt::Debug for Pipe Backend for Pipe +impl Backend for Pipe where - S: PipeNextStream + Send + 'static, + S: PipeNextStream + Send + 'static, S::Error: std::error::Error + Send + Sync + 'static, TSink: Backend + TaskSink + Unpin + Send + 'static - + Sink>, + + Sink>, ::Error: std::error::Error + Send + Sync + 'static, TSink::Id: Display + Send + Sync + 'static, TSink::Codec: Codec + Send + Sync + 'static, - >>::Error: + >>::Error: std::error::Error + Send + Sync + 'static, Args: Send + 'static, CdcErr: std::error::Error + Send + Sync + 'static, TSink::Compact: Send, - Conn: 'static, { type Args = Args; type Id = TSink::Id; - type Connection = Conn; + type Config = TSink::Config; type Layer = TSink::Layer; type Error = PipeError; type Codec = TSink::Codec; @@ -246,8 +242,8 @@ where self.into.codec() } - fn queue(&self) -> Queue { - self.into.queue() + fn config(&self) -> &Self::Config { + self.into.config() } fn middleware(&self) -> Self::Layer { @@ -269,7 +265,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { let mut source_done = false; loop { @@ -323,7 +319,6 @@ where self.into .poll_next(cx, worker) - .map_ok(|task| task.map_backend()) .map_err(|e| PipeError::Inner(e.into())) } @@ -339,25 +334,24 @@ where } /// Utility for piping a plain stream of `Result` into a backend. -pub trait PipeExt +pub trait PipeExt where B: Backend, - Self: PipeNextStream + Sized, + Self: PipeNextStream + Sized, { /// Pipe the current stream into the provided sink backend. - fn pipe_to(self, backend: B) -> Pipe; + fn pipe_to(self, backend: B) -> Pipe; } -impl PipeExt for S +impl PipeExt for S where S: Stream> + Send + Unpin + 'static, B::Error: Into + Send + Sync + 'static, B: Backend + TaskSink, Err: 'static, Args: 'static, - Conn: 'static, { - fn pipe_to(self, backend: B) -> Pipe { + fn pipe_to(self, backend: B) -> Pipe { Pipe::new(self, backend) } } @@ -373,29 +367,28 @@ pub enum PipeError { Inner(BoxDynError), } -delegate_sink!(Pipe, into); +delegate_sink!(Pipe, into); delegate_expose!( - impl for Pipe + impl for Pipe where { B: Send + Sync, - S: PipeNextStream + Send + Sync + 'static, + S: PipeNextStream + Send + Sync + 'static, S::Error: std::error::Error + Send + Sync + 'static, - B: Backend + B: Backend + TaskSink + Unpin + Send + 'static - + Sink>, + + Sink>, ::Error: std::error::Error + Send + Sync + 'static, B::Id: Display + Send + Sync + 'static, B::Codec: Codec + Send + Sync + 'static, - >>::Error: + >>::Error: std::error::Error + Send + Sync + 'static, Args: Send + Sync + 'static, CdcErr: std::error::Error + Send + Sync + 'static, B::Compact: Send, - Conn: Send + Sync + 'static, } => into, wrap = |this, result| result.map_err(|e| PipeError::Inner(e.into())) diff --git a/apalis-core/src/backend/ext/raw.rs b/apalis-core/src/backend/ext/raw.rs index 97608742..93259e2d 100644 --- a/apalis-core/src/backend/ext/raw.rs +++ b/apalis-core/src/backend/ext/raw.rs @@ -54,7 +54,7 @@ where { type Args = B::Compact; type Id = B::Id; - type Connection = B::Connection; + type Config = B::Config; type Error = B::Error; type Layer = B::Layer; type Codec = IdentityCodec; @@ -63,8 +63,8 @@ where &IdentityCodec } - fn queue(&self) -> Queue { - self.inner.queue() + fn config(&self) -> &Self::Config { + self.inner.config() } fn middleware(&self) -> Self::Layer { @@ -83,7 +83,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.inner.poll_next(cx, worker) } fn poll_close( diff --git a/apalis-core/src/backend/ext/with_codec.rs b/apalis-core/src/backend/ext/with_codec.rs index edd31ebf..26395dfe 100644 --- a/apalis-core/src/backend/ext/with_codec.rs +++ b/apalis-core/src/backend/ext/with_codec.rs @@ -9,12 +9,7 @@ use std::{ use futures_sink::Sink; use futures_util::SinkExt; -use crate::{ - backend::{queue::Queue, *}, - features_table, - task::Task, - worker::context::WorkerContext, -}; +use crate::{backend::*, features_table, task::Task, worker::context::WorkerContext}; /// A `Backend` wrapper that swaps out the serialization codec entirely (JSON, /// MessagePack, Protobuf, ...) without touching storage logic. @@ -52,7 +47,7 @@ where { type Args = B::Args; type Id = B::Id; - type Connection = B::Connection; + type Config = B::Config; type Error = B::Error; type Codec = NewCodec; type Compact = B::Compact; @@ -62,8 +57,8 @@ where &self.codec } - fn queue(&self) -> Queue { - self.backend.queue() + fn config(&self) -> &Self::Config { + self.backend.config() } fn middleware(&self) -> Self::Layer { @@ -82,7 +77,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.backend.poll_next(cx, worker) } fn poll_close( diff --git a/apalis-core/src/backend/ext/with_poll_strategy.rs b/apalis-core/src/backend/ext/with_poll_strategy.rs index 1a0c17df..1eb888eb 100644 --- a/apalis-core/src/backend/ext/with_poll_strategy.rs +++ b/apalis-core/src/backend/ext/with_poll_strategy.rs @@ -12,7 +12,6 @@ use futures_util::SinkExt; use crate::{ backend::{ poll_strategy::{PollMetrics, PollStrategy}, - queue::Queue, *, }, task::Task, @@ -46,7 +45,7 @@ where { type Args = B::Args; type Id = B::Id; - type Connection = B::Connection; + type Config = B::Config; type Error = B::Error; type Codec = B::Codec; type Compact = B::Compact; @@ -56,8 +55,8 @@ where self.backend.codec() } - fn queue(&self) -> Queue { - self.backend.queue() + fn config(&self) -> &Self::Config { + self.backend.config() } fn middleware(&self) -> Self::Layer { @@ -81,7 +80,7 @@ where &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { match self.backend.poll_next(cx, worker) { Poll::Ready(task) => { self.poll_metrics.on_ready(); diff --git a/apalis-core/src/backend/factory.rs b/apalis-core/src/backend/factory.rs new file mode 100644 index 00000000..22ed1155 --- /dev/null +++ b/apalis-core/src/backend/factory.rs @@ -0,0 +1,33 @@ +//! # Shared connection support for backends +//! +//! The [`BackendFactory`] trait defines how to create backend using the same connection instances, potentially with configuration options. +//! This allows for flexible and reusable backend implementations that can be easily integrated into different parts of an application. +//! +//! ## Features: +//! - `BackendFactory` trait: Defines methods for creating backend instances from one connection, with or without configuration. +//! - Support for various backend types. +//! - Performance optimizations by allowing backends to reuse connections and resources. + +use crate::backend::Backend; + +/// Trait for creating backend instances, generic over job-type arguments. +pub trait BackendFactory { + /// The backend type produced by this factory. + type Backend: Backend; + /// The error returned if backend creation fails. + type Error; + + /// Create a backend using `Config::default()`. + fn create(&mut self) -> Result + where + ::Config: Default, + { + self.create_with_config(Default::default()) + } + + /// Create a backend using the given configuration. + fn create_with_config( + &mut self, + config: ::Config, + ) -> Result; +} diff --git a/apalis-core/src/backend/impls/dequeue.rs b/apalis-core/src/backend/impls/dequeue.rs index 87288cc0..e2e31b01 100644 --- a/apalis-core/src/backend/impls/dequeue.rs +++ b/apalis-core/src/backend/impls/dequeue.rs @@ -9,7 +9,7 @@ use futures_sink::Sink; use tower_layer::Identity; use crate::{ - backend::{Backend, codec::IdentityCodec, queue::Queue}, + backend::{Backend, codec::IdentityCodec}, error::BoxDynError, task::{Task, task_id::RandomId}, worker::context::WorkerContext, @@ -20,7 +20,7 @@ use crate::{ /// This backend is primarily intended for testing and demonstration purposes. It does not persist tasks and is not suitable for production use. #[derive(Debug, Clone)] pub struct VecDequeBackend { - queue: Arc>>>, + queue: Arc>>>, waker: Arc>>, } @@ -67,7 +67,7 @@ where { type Args = T; type Id = RandomId; - type Connection = (); + type Config = (); type Layer = Identity; type Error = VecDequeError; type Codec = IdentityCodec; @@ -77,8 +77,8 @@ where &IdentityCodec } - fn queue(&self) -> Queue { - Queue::from(std::any::type_name::()) + fn config(&self) -> &Self::Config { + &() } fn poll_ready( @@ -107,7 +107,7 @@ where &mut self, _cx: &mut Context<'_>, _worker: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { match self .queue .lock() @@ -137,7 +137,7 @@ where } } -impl Sink> for VecDequeBackend +impl Sink> for VecDequeBackend where T: Send + Unpin + 'static, { @@ -147,7 +147,7 @@ where Poll::Ready(Ok(())) } - fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { let this = self.get_mut(); let mut tasks = this diff --git a/apalis-core/src/backend/impls/memory.rs b/apalis-core/src/backend/impls/memory.rs index cd7b6cf5..a8d46423 100644 --- a/apalis-core/src/backend/impls/memory.rs +++ b/apalis-core/src/backend/impls/memory.rs @@ -62,7 +62,7 @@ use std::{ use tower_layer::Identity; /// A boxed in-memory task receiver stream -pub type BoxedReceiver = Pin> + Send>>; +pub type BoxedReceiver = Pin> + Send>>; /// In-memory queue that is based on channels /// @@ -88,7 +88,7 @@ pub type BoxedReceiver = Pin not_supported("Serialization support for arguments"), PipeExt => not_implemented("Allow other backends to pipe to this backend"), - MakeShared => not_supported("Share the same storage across multiple workers"), + BackendFactory => not_supported("Share the same storage across multiple workers"), Update => not_supported("Allow updating a task"), FetchById => not_supported("Allow fetching a task by its ID"), @@ -105,21 +105,17 @@ pub type BoxedReceiver = Pin not_supported("List all workers registered with the backend"), ListTasks => not_supported("List all tasks in the backend"), }] -pub struct MemoryStorage { - pub(super) sender: MemorySink, - pub(super) receiver: BoxedReceiver, +pub struct MemoryStorage { + pub(super) sender: MemorySink, + pub(super) receiver: BoxedReceiver, } -impl Default for MemoryStorage { +impl Default for MemoryStorage { fn default() -> Self { Self::new() } } -/// A context for the in-memory backend, which is a placeholder and does not hold any state. -#[derive(Debug, Clone, Default)] -pub struct MemoryContext; - /// Error type for MemoryStorage operations #[derive(Debug, thiserror::Error)] pub enum MemoryStorageError { @@ -131,17 +127,14 @@ pub enum MemoryStorageError { Other(BoxDynError), } -impl MemoryStorage { +impl MemoryStorage { /// Create a new in-memory storage #[must_use] pub fn new() -> Self { let (sender, receiver) = unbounded(); let sender = Box::new(sender.sink_map_err(|e| e.into())) as Box< - dyn Sink, Error = MemoryStorageError> - + Send - + Sync - + Unpin, + dyn Sink, Error = MemoryStorageError> + Send + Sync + Unpin, >; Self { sender: MemorySink { @@ -153,25 +146,22 @@ impl MemoryStorage { } } -impl MemoryStorage { +impl MemoryStorage { /// Create a storage given a sender and receiver #[must_use] - pub fn new_with(sender: MemorySink, receiver: BoxedReceiver) -> Self { + pub fn new_with(sender: MemorySink, receiver: BoxedReceiver) -> Self { Self { sender, receiver } } } -impl Sink> for MemoryStorage { +impl Sink> for MemoryStorage { type Error = MemoryStorageError; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.as_mut().sender.poll_ready_unpin(cx) } - fn start_send( - mut self: Pin<&mut Self>, - item: Task, - ) -> Result<(), Self::Error> { + fn start_send(mut self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { self.as_mut().sender.start_send_unpin(item) } @@ -184,10 +174,10 @@ impl Sink> for MemoryStorage } } -type ArcMemorySink = Arc< +type ArcMemorySink = Arc< Mutex< Box< - dyn Sink, Error = MemoryStorageError> + dyn Sink, Error = MemoryStorageError> + Send + Sync + Unpin @@ -199,14 +189,14 @@ type ArcMemorySink = Arc< type ArcIdempotencySet = Arc>>; /// Memory sink for sending tasks to the in-memory backend -pub struct MemorySink { - pub(super) inner: ArcMemorySink, +pub struct MemorySink { + pub(super) inner: ArcMemorySink, pub(super) idempotency_keys: ArcIdempotencySet, } -impl MemorySink { +impl MemorySink { /// Build a new memory sink given a sink - pub fn new(sink: ArcMemorySink) -> Self { + pub fn new(sink: ArcMemorySink) -> Self { Self { inner: sink, idempotency_keys: Arc::new(Mutex::new(HashSet::new())), @@ -214,7 +204,7 @@ impl MemorySink { } } -impl std::fmt::Debug for MemorySink { +impl std::fmt::Debug for MemorySink { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MemorySink") .field("inner", &"") @@ -223,7 +213,7 @@ impl std::fmt::Debug for MemorySink { } } -impl Clone for MemorySink { +impl Clone for MemorySink { fn clone(&self) -> Self { Self { inner: Arc::clone(&self.inner), @@ -232,7 +222,7 @@ impl Clone for MemorySink { } } -impl Sink> for MemorySink { +impl Sink> for MemorySink { type Error = MemoryStorageError; fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { @@ -240,10 +230,7 @@ impl Sink> for MemorySink { Pin::new(&mut *lock).poll_ready_unpin(cx) } - fn start_send( - self: Pin<&mut Self>, - item: Task, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { let this = self.get_mut(); if let Some(key) = item.ctx.idempotency_key.as_ref() { let mut keys = this.idempotency_keys.try_lock().unwrap(); @@ -275,7 +262,7 @@ impl Sink> for MemorySink { } } -impl std::fmt::Debug for MemoryStorage { +impl std::fmt::Debug for MemoryStorage { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("MemoryStorage") .field("sender", &self.sender) @@ -284,8 +271,8 @@ impl std::fmt::Debug for MemoryStorage { } } -impl Stream for MemoryStorage { - type Item = Task; +impl Stream for MemoryStorage { + type Item = Task; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.receiver.poll_next_unpin(cx) @@ -293,15 +280,14 @@ impl Stream for MemoryStorage { } // MemoryStorage as a Backend -impl Backend for MemoryStorage +impl Backend for MemoryStorage where Args: 'static + Clone + Send, - Conn: 'static, { type Args = Args; type Id = RandomId; - type Connection = Conn; + type Config = (); type Error = MemoryStorageError; type Layer = Identity; @@ -313,8 +299,8 @@ where &IdentityCodec } - fn queue(&self) -> crate::backend::queue::Queue { - std::any::type_name::().into() + fn config(&self) -> &Self::Config { + &() } fn poll_ready( @@ -333,7 +319,7 @@ where &mut self, cx: &mut Context<'_>, _: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.receiver.poll_next_unpin(cx).map(|item| item.map(Ok)) } diff --git a/apalis-core/src/backend/mod.rs b/apalis-core/src/backend/mod.rs index 6041cecd..9147a6eb 100644 --- a/apalis-core/src/backend/mod.rs +++ b/apalis-core/src/backend/mod.rs @@ -26,7 +26,7 @@ use std::{ }; use crate::{ - backend::{codec::Codec, queue::Queue}, + backend::codec::Codec, task::{Task, status::Status, task_id::TaskId}, worker::context::WorkerContext, }; @@ -34,9 +34,9 @@ use crate::{ pub mod codec; pub mod custom; pub mod ext; +pub mod factory; pub mod poll_strategy; pub mod queue; -pub mod shared; mod expose; mod impls; @@ -65,8 +65,9 @@ pub trait Backend: Sized { type Args; /// The type used to uniquely identify tasks. type Id: Clone + Send + Sync + 'static; - /// The type of connection used by the backend. - type Connection; + + /// The config for the backend + type Config; /// The error type returned by backend operations type Error: std::error::Error + Send + Sync + 'static; @@ -80,8 +81,8 @@ pub trait Backend: Sized { /// The encoding and decoding mechanism fn codec(&self) -> &Self::Codec; - /// Returns the queue associated with the backend. - fn queue(&self) -> Queue; + /// Returns the config associated with the backend. + fn config(&self) -> &Self::Config; /// Returns the backend's middleware layer. fn middleware(&self) -> Self::Layer; @@ -100,7 +101,7 @@ pub trait Backend: Sized { &mut self, cx: &mut Context<'_>, worker: &WorkerContext, - ) -> Poll, Self::Error>>>; + ) -> Poll, Self::Error>>>; /// Flushes/releases any resources the backend holds (pending acks, /// open subscriptions, connections) before the worker fully shuts down. @@ -118,9 +119,7 @@ pub trait FetchById: Backend { fn fetch_by_id( &mut self, task_id: &TaskId, - ) -> impl Future< - Output = Result>, Self::Error>, - > + Send; + ) -> impl Future>, Self::Error>> + Send; } /// Allows updating an existing task @@ -128,7 +127,7 @@ pub trait Update: Backend { /// Update the given task fn update( &mut self, - task: Task, + task: Task, ) -> impl Future> + Send; } @@ -137,7 +136,7 @@ pub trait Reschedule: Backend { /// Reschedule the task after a specified duration fn reschedule( &mut self, - task: Task, + task: Task, wait: Duration, ) -> impl Future> + Send; } diff --git a/apalis-core/src/backend/poll_strategy/mod.rs b/apalis-core/src/backend/poll_strategy/mod.rs index ccd07b02..7c02fdce 100644 --- a/apalis-core/src/backend/poll_strategy/mod.rs +++ b/apalis-core/src/backend/poll_strategy/mod.rs @@ -337,7 +337,7 @@ mod tests { Some((Ok::<_, BoxDynError>(Some(item)), (p, ctx))) } else { Some(( - Ok::>, BoxDynError>(None), + Ok::>, BoxDynError>(None), (p, ctx), )) } diff --git a/apalis-core/src/backend/queue.rs b/apalis-core/src/backend/queue.rs index 4755c93f..ebd8f373 100644 --- a/apalis-core/src/backend/queue.rs +++ b/apalis-core/src/backend/queue.rs @@ -71,15 +71,14 @@ impl<'de> serde::Deserialize<'de> for Queue { } } -impl FromRequest> for Queue +impl FromRequest> for Queue where Args: Sync, - Conn: Send + Sync, Id: Sync + Send, { type Error = QueueError; - async fn from_request(req: &Task) -> Result { + async fn from_request(req: &Task) -> Result { let queue = req.ctx.queue.clone().ok_or(QueueError::NotFound)?; Ok(queue) } diff --git a/apalis-core/src/backend/shared.rs b/apalis-core/src/backend/shared.rs deleted file mode 100644 index 64b08454..00000000 --- a/apalis-core/src/backend/shared.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! # Shared connection support for backends -//! -//! The [`MakeShared`] trait defines how to create shared backend instances, potentially with configuration options. -//! This allows for flexible and reusable backend implementations that can be easily integrated into different parts of an application. -//! -//! ## Features: -//! - `MakeShared` trait: Defines methods for creating shared backend instances, with or without configuration. -//! - Support for various backend types, enabling code reuse and consistency across workers. -//! - Performance optimizations by allowing backends to reuse connections and resources. - -/// Trait for creating shared backend instances -pub trait MakeShared { - /// The backend type to be shared - type Backend; - /// The Config for the backend - type Config; - /// The error returned if the backend cant be shared - type MakeError; - - /// Returns the backend to be shared - fn make_shared(&mut self) -> Result - where - Self::Config: Default, - { - self.make_shared_with_config(Default::default()) - } - - /// Returns the backend with config - fn make_shared_with_config( - &mut self, - config: Self::Config, - ) -> Result; -} diff --git a/apalis-core/src/backend/sink.rs b/apalis-core/src/backend/sink.rs index 4fd2f469..6b0a1430 100644 --- a/apalis-core/src/backend/sink.rs +++ b/apalis-core/src/backend/sink.rs @@ -43,25 +43,24 @@ pub trait TaskSink: Backend { /// Allows pushing a fully constructed task into the backend fn push_task( &mut self, - task: Task, + task: Task, ) -> impl Future>> + Send; /// Allows pushing a fully constructed task into the backend fn push_all( &mut self, - tasks: impl Stream> + Unpin + Send, + tasks: impl Stream> + Unpin + Send, ) -> impl Future>> + Send; } impl TaskSink for S where - S: Sink, Error = E> + S: Sink, Error = E> + Unpin + Backend + Send, Args: Send, C::Compact: Send, - S::Connection: Send + Sync, S::Id: Send + Sync + 'static, C: Codec + Clone + Send + Sync, E: Send, @@ -115,7 +114,7 @@ where async fn push_task( &mut self, - task: Task, + task: Task, ) -> Result<(), TaskSinkError> { use futures_util::SinkExt; let codec = self.codec().clone(); @@ -131,7 +130,7 @@ where async fn push_all( &mut self, - tasks: impl Stream> + Unpin + Send, + tasks: impl Stream> + Unpin + Send, ) -> Result<(), TaskSinkError> { use futures_util::SinkExt; let codec = self.codec().clone(); diff --git a/apalis-core/src/lib.rs b/apalis-core/src/lib.rs index e35a76b7..3d8677b1 100644 --- a/apalis-core/src/lib.rs +++ b/apalis-core/src/lib.rs @@ -76,12 +76,10 @@ //!
//! Associated Types: //! -//! - `Stream` - Defines the task stream type for polling operations //! - `Layer` - Specifies the middleware layer stack for the backend //! - `Codec` - Determines serialization format for task data persistence -//! - `Beat` - Heartbeat stream for worker liveness checks //! - `Id` - Type used for unique task identifiers -//! - `Conn` - Context associated with tasks +//! - `Config` - Config for the backend //! - `Error` - Error type for backend operations //! //!
@@ -228,10 +226,10 @@ //! inner: S, //! } //! -//! impl Service> for LoggingService +//! impl Service> for LoggingService //! where -//! S: Service, Response = Res, Error = Err>, -//! Req: std::fmt::Debug, +//! S: Service, Response = Res, Error = Err>, +//! Args: std::fmt::Debug, //! { //! type Response = Res; //! type Error = Err; @@ -241,7 +239,7 @@ //! self.inner.poll_ready(cx) //! } //! -//! fn call(&mut self, req: Task) -> Self::Future { +//! fn call(&mut self, req: Task) -> Self::Future { //! println!("Processing task: {:?}", req.args); //! self.inner.call(req) //! } @@ -324,7 +322,7 @@ //! [`Status`]: crate::task::status::Status //! [`TaskId`]: crate::task::task_id::TaskId //! [`Attempt`]: crate::task::attempt::Attempt -//! [`FromRequest`]: crate::task_fn::FromRequest +//! [`FromArgsuest`]: crate::task_fn::FromArgsuest //! [`TestWorker`]: crate::worker::test_worker::TestWorker //! [`Shutdown`]: crate::monitor::shutdown::Shutdown diff --git a/apalis-core/src/macros.rs b/apalis-core/src/macros.rs index 6d9d2ed0..8e8eea45 100644 --- a/apalis-core/src/macros.rs +++ b/apalis-core/src/macros.rs @@ -188,7 +188,7 @@ macro_rules! features_table { " worker.run().await.unwrap();\n", "}\n" ) }; - (@assert_function MakeShared) => { "fn assert_make_shared(t: T); assert_make_shared(backend);" }; + (@assert_function BackendFactory) => { "fn assert_make_shared(t: T); assert_make_shared(backend);" }; // Standardized assert function mapping for identifiers (@assert_function Workflow) => { concat!( " # use apalis_workflow::*;\n", diff --git a/apalis-core/src/monitor/mod.rs b/apalis-core/src/monitor/mod.rs index 9e5e5d79..9b3976d2 100644 --- a/apalis-core/src/monitor/mod.rs +++ b/apalis-core/src/monitor/mod.rs @@ -283,10 +283,10 @@ impl Debug for Monitor { impl Monitor { fn run_worker( mut ctx: WorkerContext, - worker: Worker, + worker: Worker, ) -> BoxFuture<'static, Result<(), WorkerError>> where - S: Service> + Send + 'static, + S: Service> + Send + 'static, S::Future: Send, S::Error: Send + Sync + 'static + Into, B: Backend + Send + Unpin + 'static, @@ -295,11 +295,10 @@ impl Monitor { M: Layer<<::Layer as Layer>>>::Service> + 'static, ::Layer as Layer>>>::Service, - >>::Service: Service> + Send + 'static, - <>>>::Service>>::Service as Service>>::Future: Send, - <>>>::Service>>::Service as Service>>::Error: Into + Send + Sync + 'static, + >>::Service: Service> + Send + 'static, + <>>>::Service>>::Service as Service>>::Future: Send, + <>>>::Service>>::Service as Service>>::Error: Into + Send + Sync + 'static, Args: Send + 'static, - B::Connection: Send + Sync + 'static, B::Id: Sync + Send + 'static, >::Error: Into, @@ -339,23 +338,22 @@ impl Monitor { #[must_use] pub fn register( mut self, - factory: impl Fn(usize) -> Worker + 'static + Send + Sync, + factory: impl Fn(usize) -> Worker + 'static + Send + Sync, ) -> Self where - S: Service> + Send + 'static, + S: Service> + Send + 'static, S::Future: Send, S::Error: Send + Sync + 'static + Into, B: Backend + Send + Unpin + 'static, B::Error: Into + Send + 'static, Args: Send + 'static, - B::Connection: Send + Sync + 'static, B::Layer: Layer>> + 'static, M: Layer<<::Layer as Layer>>>::Service> + 'static, ::Layer as Layer>>>::Service, - >>::Service: Service> + Send + 'static, - <>>>::Service>>::Service as Service>>::Future: Send, - <>>>::Service>>::Service as Service>>::Error: + >>::Service: Service> + Send + 'static, + <>>>::Service>>::Service as Service>>::Future: Send, + <>>>::Service>>::Service as Service>>::Error: Into + Send + Sync + 'static, B::Id: Send + Sync + 'static, >::Error: Into, diff --git a/apalis-core/src/task/attempt.rs b/apalis-core/src/task/attempt.rs index 08751ea9..4aa02d19 100644 --- a/apalis-core/src/task/attempt.rs +++ b/apalis-core/src/task/attempt.rs @@ -49,13 +49,13 @@ impl Attempt { } } -impl FromRequest> for Attempt +impl FromRequest> for Attempt where Args: Sync, Id: Sync + Send, { type Error = Infallible; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { Ok(task.ctx.attempt.clone()) } } diff --git a/apalis-core/src/task/builder.rs b/apalis-core/src/task/builder.rs index 8a5b6c11..8f55fe1b 100644 --- a/apalis-core/src/task/builder.rs +++ b/apalis-core/src/task/builder.rs @@ -45,14 +45,14 @@ use std::{ #[derive(Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[must_use = "TaskBuilder is used to construct a Task. Ensure to call `.build()` to create the Task instance."] -pub struct TaskBuilder { +pub struct TaskBuilder { /// The arguments for the task pub args: Args, /// Execution context for the task, including metadata and extensions - pub ctx: ExecutionContext, + pub ctx: ExecutionContext, } -impl TaskBuilder { +impl TaskBuilder { /// Create a new TaskBuilder with the required args pub fn new(args: Args) -> Self { Self { @@ -195,7 +195,7 @@ impl TaskBuilder { } /// Build the Task with default context - pub fn build(self) -> Task { + pub fn build(self) -> Task { Task { args: self.args, ctx: Arc::new(self.ctx), @@ -203,9 +203,9 @@ impl TaskBuilder { } } -impl TaskBuilder { +impl TaskBuilder { /// Maps the `args` field using the provided function, consuming the task. - pub fn try_map_args(self, f: F) -> Result, Err> + pub fn try_map_args(self, f: F) -> Result, Err> where F: FnOnce(Args) -> Result, { @@ -215,7 +215,7 @@ impl TaskBuilder { }) } /// Maps the `args` field using the provided function, consuming the task. - pub fn map_args(self, f: F) -> TaskBuilder + pub fn map_args(self, f: F) -> TaskBuilder where F: FnOnce(Args) -> NewArgs, { @@ -228,7 +228,7 @@ impl TaskBuilder { /// Maps only the `execution_context` field. pub fn map_context(self, f: F) -> Self where - F: FnOnce(ExecutionContext) -> ExecutionContext, + F: FnOnce(ExecutionContext) -> ExecutionContext, { Self { args: self.args, diff --git a/apalis-core/src/task/data.rs b/apalis-core/src/task/data.rs index adb53cad..45cbc7f4 100644 --- a/apalis-core/src/task/data.rs +++ b/apalis-core/src/task/data.rs @@ -116,9 +116,9 @@ pub struct AddExtension { value: T, } -impl Service> for AddExtension +impl Service> for AddExtension where - S: Service>, + S: Service>, T: Clone + Send + Sync + 'static, { type Response = S::Response; @@ -130,7 +130,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, mut task: Task) -> Self::Future { + fn call(&mut self, mut task: Task) -> Self::Future { if let Some(ctx) = Arc::get_mut(&mut task.ctx) { ctx.data.insert(self.value.clone()); } @@ -146,11 +146,11 @@ pub enum MissingDataError { NotFound(String), } -impl - FromRequest> for Data +impl FromRequest> + for Data { type Error = MissingDataError; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { task.ctx.data.get_checked().cloned().map(Self::new) } } diff --git a/apalis-core/src/task/metadata.rs b/apalis-core/src/task/metadata.rs index 8fa3d442..e7016fe9 100644 --- a/apalis-core/src/task/metadata.rs +++ b/apalis-core/src/task/metadata.rs @@ -296,24 +296,20 @@ pub trait Metadata: Sized { fn inject(&self, map: &mut MetadataStore) -> Result<(), Self::Error>; } -impl - FromRequest> for Meta -{ +impl FromRequest> for Meta { type Error = T::Error; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { let metadata = &task.ctx.metadata; let value = T::extract(metadata)?; Ok(Self(value)) } } -impl FromRequest> - for MetadataStore -{ +impl FromRequest> for MetadataStore { type Error = Infallible; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { Ok(task.ctx.metadata.clone()) } } @@ -545,11 +541,10 @@ mod tests { } } - impl - Service> for ExampleService + impl Service> + for ExampleService where - S: Service> + Clone + Send + 'static, - Conn: Send, + S: Service> + Clone + Send + 'static, S::Future: Send + 'static, { type Response = S::Response; @@ -560,7 +555,7 @@ mod tests { self.service.poll_ready(cx) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { let mut svc = self.service.clone(); // Do something with config diff --git a/apalis-core/src/task/mod.rs b/apalis-core/src/task/mod.rs index 07a4ee85..2475b4a2 100644 --- a/apalis-core/src/task/mod.rs +++ b/apalis-core/src/task/mod.rs @@ -14,7 +14,6 @@ //! //! The [`Task`] struct is generic over: //! - `Args`: The type of arguments or payload for the task. -//! - `Conn`: Backend-specific marker for a task. //! - `Id`: The type used for uniquely identifying the task (defaults to [`RandomId`]). //! //! ## [`ExecutionContext`] @@ -57,7 +56,7 @@ //! # use apalis_core::task::{Task, ExecutionContext}; //! # use apalis_core::task::builder::TaskBuilder; //! # use apalis_core::task::task_id::RandomId; -//! let task: Task = TaskBuilder::new("my work".to_string()).build(); +//! let task: Task = TaskBuilder::new("my work".to_string()).build(); //! ``` //! //! ## Creating a task with custom metadata @@ -68,7 +67,6 @@ //! # use apalis_core::task::task_id::RandomId; //! # use apalis_core::task::metadata::Metadata; //! # use apalis_core::task::metadata::MetadataStore; -//! # use apalis_core::backend::memory::MemoryContext; //! # //! #[derive(Debug, PartialEq)] //! struct RequestId(String); @@ -91,7 +89,7 @@ //! } //! } //! -//! let task: Task = TaskBuilder::new("important work".to_string()) +//! let task: Task = TaskBuilder::new("important work".to_string()) //! .metadata(&RequestId("user_id".to_string())) //! .build(); //! ``` @@ -101,9 +99,8 @@ //! ```rust //! # use apalis_core::task::builder::TaskBuilder; //! # use apalis_core::task::task_id::RandomId; -//! # use apalis_core::backend::memory::MemoryContext; //! use apalis_core::task::{Task, ExecutionContext, status::Status}; -//! let mut task: TaskBuilder<_, MemoryContext, RandomId> = TaskBuilder::new("work".to_string()); +//! let mut task: TaskBuilder<_, RandomId> = TaskBuilder::new("work".to_string()); //! task.ctx.status = Status::Running.into(); //! task.ctx.attempt.increment(); //! ``` @@ -118,7 +115,7 @@ //! pub struct TracingId(String); //! let mut extensions = Extensions::default(); //! extensions.insert(TracingId("abc123".to_owned())); -//! let task: Task = TaskBuilder::new("work".to_string()).with_data(extensions).build(); +//! let task: Task = TaskBuilder::new("work".to_string()).with_data(extensions).build(); //! assert_eq!(task.ctx.data.get::(), Some(&TracingId("abc123".to_owned()))); //! ``` //! @@ -141,7 +138,6 @@ use std::{ fmt::{Debug, Display}, - marker::PhantomData, sync::Arc, }; @@ -171,16 +167,16 @@ pub mod task_id; /// Represents a task which will be executed /// Should be considered a single unit of work #[derive(Debug, Clone, Default)] -pub struct Task { +pub struct Task { /// The argument task part pub args: Args, /// ExecutionContext of the task eg id, attempts and context - pub ctx: Arc>, + pub ctx: Arc>, } /// Execution context of a `Task` #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ExecutionContext { +pub struct ExecutionContext { /// The task's id if allocated pub task_id: Option>, @@ -224,12 +220,9 @@ pub struct ExecutionContext { /// A list of all runs for this task pub runs: Vec, - - /// A marker to indicate the type of connection used by the backend. - pub connection: PhantomData Connection>, } -impl Default for ExecutionContext { +impl Default for ExecutionContext { fn default() -> Self { Self { task_id: None, @@ -246,18 +239,16 @@ impl Default for ExecutionContext { priority: None, queue: None, runs: Vec::new(), - connection: PhantomData, } } } -impl Debug for ExecutionContext { +impl Debug for ExecutionContext { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ExecutionContext") .field("task_id", &self.task_id) .field("data", &"") .field("attempt", &self.attempt) - .field("connection", &self.connection) .field("status", &self.status.load()) .field("run_at", &self.run_at) .field("done_at", &self.done_at) @@ -273,13 +264,12 @@ impl Debug for ExecutionContext { } } -impl Clone for ExecutionContext { +impl Clone for ExecutionContext { fn clone(&self) -> Self { Self { task_id: self.task_id.clone(), data: self.data.clone(), attempt: self.attempt.clone(), - connection: self.connection, status: self.status.clone(), run_at: self.run_at, done_at: self.done_at, @@ -295,10 +285,10 @@ impl Clone for ExecutionContext { } } -impl Task { +impl Task { /// Take the task into its parts #[must_use] - pub fn take(self) -> (Args, Arc>) { + pub fn take(self) -> (Args, Arc>) { (self.args, self.ctx) } @@ -311,7 +301,7 @@ impl Task { } /// Maps the `args` field using the provided function, consuming the task. - pub fn map_args(self, f: F) -> Task + pub fn map_args(self, f: F) -> Task where F: FnOnce(Args) -> NewArgs, { @@ -323,7 +313,7 @@ impl Task { /// Maps the `args` field using the provided function, consuming the task. #[must_use = "A mapped task should be used or handled to avoid unused value warnings."] - pub fn try_map_args(self, f: F) -> Result, Err> + pub fn try_map_args(self, f: F) -> Result, Err> where F: FnOnce(Args) -> Result, { @@ -337,7 +327,7 @@ impl Task { #[must_use] pub fn map_context(self, f: F) -> Self where - F: FnOnce(Arc>) -> Arc>, + F: FnOnce(Arc>) -> Arc>, { Self { args: self.args, @@ -345,9 +335,12 @@ impl Task { } } - /// Modifies the relevant backend types, consuming the task + /// Modifies the id type of the task, consuming the task + /// + /// See [`crate::backend::ext::pipe`] #[must_use] - pub fn map_backend(self) -> Task + #[doc(hidden)] + pub fn map_id_type(self) -> Task where Id: Clone, Id: Display, @@ -374,14 +367,13 @@ impl Task { priority: ctx.priority, queue: ctx.queue, runs: ctx.runs, - connection: Default::default(), }), } } /// Converts the task into a [`TaskBuilder`] #[must_use = "Converting a task into a builder allows for further modifications before rebuilding the task."] - pub fn into_builder(self) -> TaskBuilder + pub fn into_builder(self) -> TaskBuilder where Id: Clone, { diff --git a/apalis-core/src/task/task_id.rs b/apalis-core/src/task/task_id.rs index 93dd98af..a4e98d1e 100644 --- a/apalis-core/src/task/task_id.rs +++ b/apalis-core/src/task/task_id.rs @@ -17,7 +17,7 @@ pub use random_id::RandomId; /// A wrapper type that defines a task id. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord, Default)] pub struct TaskId(Id); impl TaskId { @@ -60,11 +60,9 @@ impl Display for TaskId { } } -impl FromRequest> - for TaskId -{ +impl FromRequest> for TaskId { type Error = MissingDataError; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { task.ctx.task_id.clone().ok_or(MissingDataError::NotFound( std::any::type_name::().to_owned(), )) diff --git a/apalis-core/src/task_fn/from_request.rs b/apalis-core/src/task_fn/from_request.rs index 430120fb..5bc50a77 100644 --- a/apalis-core/src/task_fn/from_request.rs +++ b/apalis-core/src/task_fn/from_request.rs @@ -52,9 +52,9 @@ //! # } //! # } //! # struct Email { user_id: String }; -//! impl FromRequest> for User { +//! impl FromRequest> for User { //! type Error = BoxDynError; -//! async fn from_request(req: &Task) -> Result { +//! async fn from_request(req: &Task) -> Result { //! let user_id = &req.args.user_id; //! let user = User::find_by_id(user_id).await?; //! Ok(user) diff --git a/apalis-core/src/task_fn/guide.rs b/apalis-core/src/task_fn/guide.rs index b2f2e3ff..930a139b 100644 --- a/apalis-core/src/task_fn/guide.rs +++ b/apalis-core/src/task_fn/guide.rs @@ -105,9 +105,9 @@ //! # // other fields... //! # } //! -//! impl FromRequest> for User { +//! impl FromRequest> for User { //! type Error = BoxDynError; -//! async fn from_request(req: &Task) -> Result { +//! async fn from_request(req: &Task) -> Result { //! let user_id = req.args.user_id.clone(); //! // Simulate fetching user from DB //! Ok(User { id: user_id }) diff --git a/apalis-core/src/task_fn/mod.rs b/apalis-core/src/task_fn/mod.rs index 01d594c3..17156a82 100644 --- a/apalis-core/src/task_fn/mod.rs +++ b/apalis-core/src/task_fn/mod.rs @@ -79,7 +79,7 @@ pub use self::{from_request::FromRequest, into_response::IntoResponse}; /// /// - [`FromRequest`] /// - [`IntoResponse`] -pub fn task_fn(f: F) -> TaskFn { +pub fn task_fn(f: F) -> TaskFn { TaskFn { f, req: PhantomData, @@ -90,15 +90,15 @@ pub fn task_fn(f: F) -> TaskFn { /// An executable service implemented by a closure. /// /// See [`task_fn`] for more details. -pub struct TaskFn { +pub struct TaskFn { f: F, - req: PhantomData<(Args, Conn)>, + req: PhantomData, fn_args: PhantomData, } -impl Copy for TaskFn {} +impl Copy for TaskFn {} -impl Clone for TaskFn { +impl Clone for TaskFn { fn clone(&self) -> Self { Self { f: self.f.clone(), @@ -108,17 +108,13 @@ impl Clone for TaskFn { } } -impl fmt::Debug for TaskFn { +impl fmt::Debug for TaskFn { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TaskFn") .field("f", &std::any::type_name::()) .field( "req", - &format_args!( - "PhantomData>", - std::any::type_name::(), - std::any::type_name::() - ), + &format_args!("PhantomData>", std::any::type_name::(),), ) .field( "fn_args", @@ -134,14 +130,14 @@ type FnFuture = Map std::result::Result>; macro_rules! impl_service_fn { ($($K:ident),+) => { #[allow(unused_parens)] - impl Service> for TaskFn + impl Service> for TaskFn where T: FnMut(Args, $($K),+) -> F + Send + Clone + 'static, F: Future + Send, F::Output: IntoResponse, $( - $K: FromRequest> + Send, - < $K as FromRequest> >::Error: std::error::Error + 'static + Send + Sync, + $K: FromRequest> + Send, + < $K as FromRequest> >::Error: std::error::Error + 'static + Send + Sync, )+ { type Response = R; @@ -152,7 +148,7 @@ macro_rules! impl_service_fn { Poll::Ready(Ok(())) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let mut svc = self.f.clone(); #[allow(non_snake_case)] let fut = async move { @@ -171,23 +167,22 @@ macro_rules! impl_service_fn { } #[allow(unused_parens)] - impl - IntoWorkerService, Args, Conn> for T + impl + IntoWorkerService, Args> for T where - B: Backend, + B: Backend, T: FnMut(Args, $($K),+) -> F + Send + Clone + 'static, F: Future + Send, Args: Send + 'static, - Conn: Send + Sync + 'static, B::Id: Send + Sync + 'static, F::Output: IntoResponse, $( - $K: FromRequest> + Send, - < $K as FromRequest> >::Error: std::error::Error + 'static + Send + Sync, + $K: FromRequest> + Send, + < $K as FromRequest> >::Error: std::error::Error + 'static + Send + Sync, )+ { type Backend = B; - fn into_service(self, backend: B) -> WorkerService> { + fn into_service(self, backend: B) -> WorkerService> { WorkerService { backend, service: task_fn(self), @@ -197,7 +192,7 @@ macro_rules! impl_service_fn { }; } -impl Service> for TaskFn +impl Service> for TaskFn where T: FnMut(Args) -> F, F: Future, @@ -211,24 +206,23 @@ where Poll::Ready(Ok(())) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let fut = (self.f)(task.args); fut.map(F::Output::into_response) } } -impl IntoWorkerService, Args, Conn> - for T +impl IntoWorkerService, Args> for T where T: FnMut(Args) -> F, F: Future, F::Output: IntoResponse, - Backend: crate::backend::Backend, + Backend: crate::backend::Backend, Args: Send, { type Backend = Backend; - fn into_service(self, backend: Backend) -> WorkerService> { + fn into_service(self, backend: Backend) -> WorkerService> { WorkerService { backend, service: task_fn(self), @@ -236,10 +230,10 @@ where } } -impl IntoWorkerService for S +impl IntoWorkerService for S where - S: Service>, - B: Backend, + S: Service>, + B: Backend, { type Backend = B; fn into_service(self, backend: B) -> WorkerService { diff --git a/apalis-core/src/worker/builder.rs b/apalis-core/src/worker/builder.rs index 7e9e982a..187a5e7a 100644 --- a/apalis-core/src/worker/builder.rs +++ b/apalis-core/src/worker/builder.rs @@ -86,29 +86,27 @@ use crate::{ }; /// Declaratively builds a [`Worker`] -pub struct WorkerBuilder { +pub struct WorkerBuilder { pub(crate) name: String, - pub(crate) request: PhantomData<(Args, Conn)>, + pub(crate) request: PhantomData, pub(crate) layer: Middleware, pub(crate) source: Source, pub(crate) event_handler: EventHandlerBuilder, pub(crate) shutdown: Option, } -impl std::fmt::Debug - for WorkerBuilder -{ +impl std::fmt::Debug for WorkerBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("WorkerBuilder") .field("id", &self.name) - .field("job", &std::any::type_name::<(Args, Conn)>()) + .field("job", &std::any::type_name::()) .field("layer", &std::any::type_name::()) .field("source", &std::any::type_name::()) .finish() } } -impl WorkerBuilder<(), (), (), Identity> { +impl WorkerBuilder<(), (), Identity> { /// Build a new [`WorkerBuilder`] instance with a name for the worker to build pub fn new>(name: T) -> Self { Self { @@ -122,11 +120,11 @@ impl WorkerBuilder<(), (), (), Identity> { } } -impl WorkerBuilder<(), (), (), Identity> { +impl WorkerBuilder<(), (), Identity> { /// Set the source to a backend that implements [Backend] - pub fn backend(self, backend: NB) -> WorkerBuilder + pub fn backend(self, backend: NB) -> WorkerBuilder where - NB: Backend, + NB: Backend, { WorkerBuilder { request: PhantomData, @@ -139,7 +137,7 @@ impl WorkerBuilder<(), (), (), Identity> { } } -impl WorkerBuilder +impl WorkerBuilder where B: Backend, { @@ -148,7 +146,7 @@ where pub fn chain( self, f: impl FnOnce(M) -> NewLayer, - ) -> WorkerBuilder { + ) -> WorkerBuilder { let middleware = f(self.layer); WorkerBuilder { @@ -161,7 +159,7 @@ where } } /// Allows adding middleware to the layer stack - pub fn layer(self, layer: U) -> WorkerBuilder> { + pub fn layer(self, layer: U) -> WorkerBuilder> { WorkerBuilder { request: self.request, source: self.source, @@ -175,7 +173,7 @@ where /// Adds data to the context /// /// This will be shared by all requests - pub fn data(self, data: D) -> WorkerBuilder, M>> + pub fn data(self, data: D) -> WorkerBuilder, M>> where M: Layer>, { @@ -191,15 +189,15 @@ where } /// Finalizes the builder and constructs a [`Worker`] with the provided service -impl WorkerBuilder +impl WorkerBuilder where - B: Backend, + B: Backend, { /// Consumes the builder and a service to construct the final worker - pub fn build(self, service: W) -> Worker + pub fn build(self, service: W) -> Worker where - Svc: Service>, - W: IntoWorkerServiceExt, + Svc: Service>, + W: IntoWorkerServiceExt, { service.build_with(self) } @@ -215,10 +213,10 @@ pub struct WorkerService { } /// Trait for building a worker service provided a backend -pub trait IntoWorkerService +pub trait IntoWorkerService where - B: crate::backend::Backend, - Svc: Service>, + B: crate::backend::Backend, + Svc: Service>, { /// The backend type for the worker type Backend; @@ -227,33 +225,30 @@ where } /// Extension trait for building a worker from a builder -pub trait IntoWorkerServiceExt: Sized +pub trait IntoWorkerServiceExt: Sized where - Backend: crate::backend::Backend, - Svc: Service>, - Self: IntoWorkerService, + Backend: crate::backend::Backend, + Svc: Service>, + Self: IntoWorkerService, { /// Consumes the builder and returns a worker fn build_with( self, - builder: WorkerBuilder, - ) -> Worker; + builder: WorkerBuilder, + ) -> Worker; } /// Implementation of the IntoWorkerServiceExt trait for any type /// /// Rust doest offer specialization yet, the [`IntoWorkerServiceExt`] and [`IntoWorkerService`] /// traits are used to allow the [build](WorkerBuilder::build) method to be more flexible. -impl IntoWorkerServiceExt for T +impl IntoWorkerServiceExt for T where - T: IntoWorkerService, - B: Backend, - Svc: Service>, + T: IntoWorkerService, + B: Backend, + Svc: Service>, { - fn build_with( - self, - builder: WorkerBuilder, - ) -> Worker { + fn build_with(self, builder: WorkerBuilder) -> Worker { let svc = self.into_service(builder.source); let mut worker = Worker::new(builder.name, svc.backend, svc.service, builder.layer); worker.event_handler = builder @@ -287,12 +282,12 @@ pub mod task_fn_validator { #[inline] #[doc = concat!("A helper for checking that the builder can build a worker with the provided service (", stringify!($num), " arguments)")] pub fn $num< - F, B, Args, Conn, - $($arg: FromRequest>),+ + F, B, Args, + $($arg: FromRequest>),+ >( _: F, ) where - TaskFn: Service>, + TaskFn: Service>, B: Backend { } diff --git a/apalis-core/src/worker/call_all.rs b/apalis-core/src/worker/call_all.rs index a422f80c..070a80c2 100644 --- a/apalis-core/src/worker/call_all.rs +++ b/apalis-core/src/worker/call_all.rs @@ -25,7 +25,7 @@ use crate::{ #[pin_project::pin_project] pub(super) struct CallAllUnordered where - Svc: Service::Args, ::Connection, ::Id>>, + Svc: Service>, B: Backend, { #[pin] @@ -34,7 +34,7 @@ where impl CallAllUnordered where - Svc: Service>, + Svc: Service>, B: Backend + Unpin, { /// Create new [`CallAllUnordered`] combinator. @@ -47,7 +47,7 @@ where impl Stream for CallAllUnordered where - Svc: Service>, + Svc: Service>, B: Backend + Unpin, B::Error: Into, >::Error: Into, @@ -101,7 +101,7 @@ where worker: WorkerContext, queue: Q, eof: bool, - curr_req: Option>, + curr_req: Option>, } impl fmt::Debug for CallAll @@ -128,7 +128,7 @@ pub(crate) trait Drive { impl CallAll where - Svc: Service>, + Svc: Service>, B: Backend + Unpin, Q: Drive, { @@ -146,7 +146,7 @@ where impl Stream for CallAll where - Svc: Service>, + Svc: Service>, B: Backend + Unpin, Q: Drive, B::Error: Into, diff --git a/apalis-core/src/worker/context.rs b/apalis-core/src/worker/context.rs index 94d3efd0..dcb378d5 100644 --- a/apalis-core/src/worker/context.rs +++ b/apalis-core/src/worker/context.rs @@ -372,11 +372,9 @@ impl Future for WorkerHandle { } } -impl FromRequest> - for WorkerContext -{ +impl FromRequest> for WorkerContext { type Error = MissingDataError; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { task.ctx.data.get_checked().cloned() } } diff --git a/apalis-core/src/worker/ext/ack/mod.rs b/apalis-core/src/worker/ext/ack/mod.rs index e5df07dd..82595223 100644 --- a/apalis-core/src/worker/ext/ack/mod.rs +++ b/apalis-core/src/worker/ext/ack/mod.rs @@ -35,13 +35,13 @@ //! #[derive(Debug, Clone)] //! struct MyAcknowledger; //! -//! impl Acknowledge<(), Conn, Id> for MyAcknowledger { +//! impl Acknowledge<(), Id> for MyAcknowledger { //! type Error = SendError<()>; //! type Future = BoxFuture<'static, Result<(), Self::Error>>; //! fn ack( //! &mut self, //! res: &Result<(), BoxDynError>, -//! ctx: &ExecutionContext, +//! ctx: &ExecutionContext< Id>, //! ) -> Self::Future { //! println!("{res:?}, {ctx:?}"); //! ready(Ok(())).boxed() @@ -74,47 +74,39 @@ use crate::{ /// Extension trait for adding acknowledgment handling to workers /// /// See [module level documentation](self) for more details. -pub trait AcknowledgementExt: Sized +pub trait AcknowledgementExt: Sized where - Source: Backend, - Ack: Acknowledge, + Source: Backend, + Ack: Acknowledge, { /// Add an acknowledgment handler to the worker fn ack_with( self, ack: Ack, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; } /// Acknowledge the result of a task processing /// /// See [module level documentation](self) for more details. -pub trait Acknowledge { +pub trait Acknowledge { /// The error type returned by the acknowledgment process type Error; /// The future returned by the `ack` method type Future: Future>; /// Acknowledge the result of a task processing - fn ack( - &mut self, - res: &Result, - ctx: &ExecutionContext, - ) -> Self::Future; + fn ack(&mut self, res: &Result, ctx: &ExecutionContext) -> Self::Future; } -impl Acknowledge for F +impl Acknowledge for F where - F: FnMut(&Result, &ExecutionContext) -> Fut, + F: FnMut(&Result, &ExecutionContext) -> Fut, Fut: Future>, { type Error = E; type Future = Fut; - fn ack( - &mut self, - res: &Result, - ctx: &ExecutionContext, - ) -> Self::Future { + fn ack(&mut self, res: &Result, ctx: &ExecutionContext) -> Self::Future { (self)(res, ctx) } } @@ -158,15 +150,14 @@ pub struct AcknowledgeService { acknowledger: A, } -impl Service> for AcknowledgeService +impl Service> for AcknowledgeService where - S: Service, Response = Res>, - A: Acknowledge + Clone + Send + 'static, + S: Service, Response = Res>, + A: Acknowledge + Clone + Send + 'static, S::Error: Into, A::Error: std::error::Error + Send + Sync + 'static, S::Future: Send + 'static, A::Future: Send + 'static, - Conn: Clone + Send + Sync + 'static + Send, Res: Send, Id: Send + Sync + 'static, { @@ -178,7 +169,7 @@ where self.inner.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let ctx = task.ctx.clone(); let worker: WorkerContext = ctx.data.get().cloned().unwrap(); let future = self.inner.call(task); @@ -191,14 +182,13 @@ where } } -impl AcknowledgementExt - for WorkerBuilder +impl AcknowledgementExt for WorkerBuilder where M: Layer>, - Ack: Acknowledge, - B: Backend, + Ack: Acknowledge, + B: Backend, { - fn ack_with(self, ack: Ack) -> WorkerBuilder, M>> { + fn ack_with(self, ack: Ack) -> WorkerBuilder, M>> { let this = self.layer(AcknowledgeLayer::new(ack)); WorkerBuilder { name: this.name, diff --git a/apalis-core/src/worker/ext/circuit_breaker/mod.rs b/apalis-core/src/worker/ext/circuit_breaker/mod.rs index 7cda9f04..37639411 100644 --- a/apalis-core/src/worker/ext/circuit_breaker/mod.rs +++ b/apalis-core/src/worker/ext/circuit_breaker/mod.rs @@ -77,12 +77,10 @@ mod service; /// Allows breaking the circuit if an error threshold is hit /// /// See [module level documentation](self) for more details. -pub trait CircuitBreaker: Sized { +pub trait CircuitBreaker: Sized { /// Allows the worker to break the circuit in case of failures /// Uses default configuration - fn break_circuit( - self, - ) -> WorkerBuilder> { + fn break_circuit(self) -> WorkerBuilder> { self.break_circuit_with(CircuitBreakerConfig::default()) } @@ -91,18 +89,18 @@ pub trait CircuitBreaker: Sized { fn break_circuit_with( self, cfg: CircuitBreakerConfig, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; } -impl CircuitBreaker for WorkerBuilder +impl CircuitBreaker for WorkerBuilder where - P: Backend, + P: Backend, M: Layer, { fn break_circuit_with( self, config: CircuitBreakerConfig, - ) -> WorkerBuilder> { + ) -> WorkerBuilder> { let this = self.layer(CircuitBreakerLayer::new(config)); WorkerBuilder { name: this.name, diff --git a/apalis-core/src/worker/ext/event_listener/mod.rs b/apalis-core/src/worker/ext/event_listener/mod.rs index 192f8e7d..bb9aa12c 100644 --- a/apalis-core/src/worker/ext/event_listener/mod.rs +++ b/apalis-core/src/worker/ext/event_listener/mod.rs @@ -30,12 +30,12 @@ use crate::{ }; /// Worker extension for emitting events -pub trait EventListenerExt: Sized { +pub trait EventListenerExt: Sized { /// Register a callback for worker events fn on_event( self, f: F, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; } /// Middleware for emitting events @@ -64,9 +64,9 @@ pub struct EventListenerService { service: S, } -impl Service> for EventListenerService +impl Service> for EventListenerService where - S: Service>, + S: Service>, { type Response = S::Response; type Error = S::Error; @@ -79,20 +79,20 @@ where self.service.poll_ready(cx) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { self.service.call(request) } } -impl EventListenerExt for WorkerBuilder +impl EventListenerExt for WorkerBuilder where - P: Backend, + P: Backend, M: Layer, { fn on_event( self, f: F, - ) -> WorkerBuilder> { + ) -> WorkerBuilder> { let new_fn = self .event_handler .write() diff --git a/apalis-core/src/worker/ext/long_running/mod.rs b/apalis-core/src/worker/ext/long_running/mod.rs index e039329b..ac0cd853 100644 --- a/apalis-core/src/worker/ext/long_running/mod.rs +++ b/apalis-core/src/worker/ext/long_running/mod.rs @@ -216,9 +216,9 @@ impl RunnerContext { } } -impl FromRequest> for Runner { +impl FromRequest> for Runner { type Error = MissingDataError; - async fn from_request(task: &Task) -> Result { + async fn from_request(task: &Task) -> Result { let runner: &Self = task.ctx.data.get_checked()?; Ok(runner.clone()) } @@ -259,9 +259,9 @@ pub struct LongRunningService { config: LongRunningConfig, } -impl Service> for LongRunningService +impl Service> for LongRunningService where - S: Service>, + S: Service>, S::Future: Send + 'static, S::Response: Send, S::Error: Send, @@ -277,7 +277,7 @@ where self.service.poll_ready(cx) } - fn call(&mut self, mut task: Task) -> Self::Future { + fn call(&mut self, mut task: Task) -> Self::Future { let tracker = TaskTracker::new(); let worker: WorkerContext = task .ctx @@ -301,29 +301,27 @@ where /// Helper trait for building long running workers from [`WorkerBuilder`] /// /// See [module level documentation](self) for more details. -pub trait LongRunningExt: Sized { +pub trait LongRunningExt: Sized { /// Extension for executing long running jobs - fn long_running( - self, - ) -> WorkerBuilder> { + fn long_running(self) -> WorkerBuilder> { self.long_running_with_cfg(Default::default()) } /// Extension for executing long running jobs with a config fn long_running_with_cfg( self, cfg: LongRunningConfig, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; } -impl LongRunningExt for WorkerBuilder +impl LongRunningExt for WorkerBuilder where M: Layer, - B: Backend, + B: Backend, { fn long_running_with_cfg( self, cfg: LongRunningConfig, - ) -> WorkerBuilder> { + ) -> WorkerBuilder> { let this = self.layer(LongRunningLayer::new(cfg)); WorkerBuilder { name: this.name, diff --git a/apalis-core/src/worker/ext/mod.rs b/apalis-core/src/worker/ext/mod.rs index b9ab6569..2f5ef642 100644 --- a/apalis-core/src/worker/ext/mod.rs +++ b/apalis-core/src/worker/ext/mod.rs @@ -24,15 +24,15 @@ //! # use apalis_core::worker::builder::WorkerBuilder; //! # use apalis_core::backend::memory::MemoryStorage; //! /// Example extension trait for WorkerBuilder that adds a custom method. -//! pub trait MakeSuperFastExt: Sized { +//! pub trait MakeSuperFastExt: Sized { //! /// Adds custom behavior to the WorkerBuilder. -//! fn with_super_fast(self) -> WorkerBuilder; +//! fn with_super_fast(self) -> WorkerBuilder; //! } //! -//! impl MakeSuperFastExt -//! for WorkerBuilder +//! impl MakeSuperFastExt +//! for WorkerBuilder //! { -//! fn with_super_fast(self) -> WorkerBuilder { +//! fn with_super_fast(self) -> WorkerBuilder { //! // Insert your custom logic here //! // Do something with self, e.g., modify configuration, add middleware, etc. //! // The method can also accept parameters if needed, e.g., specific configuration options diff --git a/apalis-core/src/worker/ext/parallelize/mod.rs b/apalis-core/src/worker/ext/parallelize/mod.rs index d57fc6a9..c4949487 100644 --- a/apalis-core/src/worker/ext/parallelize/mod.rs +++ b/apalis-core/src/worker/ext/parallelize/mod.rs @@ -37,12 +37,12 @@ use tower_service::Service; use crate::{backend::Backend, error::BoxDynError, task::Task, worker::builder::WorkerBuilder}; /// Worker extension for parallel execution -pub trait ParallelizeExt: Sized { +pub trait ParallelizeExt: Sized { /// Register the executor for parallel task execution. fn parallelize( self, f: Executor, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; } /// Middleware for emitting events @@ -76,10 +76,10 @@ pub struct ParallelizeService { executor: Executor, } -impl Service> +impl Service> for ParallelizeService where - S: Service, Future = Fut>, + S: Service, Future = Fut>, Executor: Fn(Fut) -> T + Send + 'static, Fut: Future> + Send + 'static, T: Future, ExecErr>> + Send + 'static, @@ -98,7 +98,7 @@ where self.service.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { (self.executor)(self.service.call(request)) .map_err(|e| e.into()) .and_then(|s| ready(s.map_err(|e| e.into()))) @@ -106,16 +106,15 @@ where } } -impl ParallelizeExt - for WorkerBuilder +impl ParallelizeExt for WorkerBuilder where - P: Backend, + P: Backend, M: Layer>, { fn parallelize( self, f: Executor, - ) -> WorkerBuilder, M>> { + ) -> WorkerBuilder, M>> { self.layer(ParallelizeLayer::new(f)) } } diff --git a/apalis-core/src/worker/mod.rs b/apalis-core/src/worker/mod.rs index 9635eb24..e2a17b8a 100644 --- a/apalis-core/src/worker/mod.rs +++ b/apalis-core/src/worker/mod.rs @@ -145,17 +145,17 @@ pub mod test_worker; /// ``` /// See [module level documentation](self) for more details. #[must_use = "Workers must be run or streamed to execute tasks"] -pub struct Worker { +pub struct Worker { pub(crate) name: String, pub(crate) backend: Backend, pub(crate) service: Svc, pub(crate) middleware: Middleware, - pub(crate) task_marker: PhantomData<(Args, Conn)>, + pub(crate) task_marker: PhantomData, pub(crate) shutdown: Option, pub(crate) event_handler: RawEventListener, } -impl fmt::Debug for Worker +impl fmt::Debug for Worker where Svc: fmt::Debug, B: fmt::Debug, @@ -168,7 +168,7 @@ where } } -impl Worker { +impl Worker { /// Build a worker that is ready for execution pub fn new(name: String, backend: B, service: Svc, layers: M) -> Self { Self { @@ -183,19 +183,18 @@ impl Worker { } } -impl Worker +impl Worker where B: Backend + Send + Unpin + 'static, - S: Service> + Send + 'static, + S: Service> + Send + 'static, Args: Send + 'static, - B::Connection: Send + Sync + 'static, B::Error: Into + Send + 'static, B::Layer: Layer>>, M: Layer<>>>::Service>, >>>::Service>>::Service: - Service> + Send + 'static, - <>>>::Service>>::Service as Service>>::Future: Send, - <>>>::Service>>::Service as Service>>::Error: Into + Send + Sync + 'static, + Service> + Send + 'static, + <>>>::Service>>::Service as Service>>::Future: Send, + <>>>::Service>>::Service as Service>>::Error: Into + Send + Sync + 'static, B::Id: Send + Sync + 'static, >::Error: Into, @@ -452,10 +451,9 @@ where worker: WorkerContext, ) -> BoxStream<'static, Result> where - Svc: Service> + Send + 'static, + Svc: Service> + Send + 'static, Args: Send + 'static, Svc::Future: Send, - B::Connection: Send + Sync + 'static, Svc::Error: Into + Sync + Send, >::Error: Into, @@ -499,9 +497,9 @@ pub struct TrackerService { service: S, } -impl Service> for TrackerService +impl Service> for TrackerService where - S: Service>, + S: Service>, { type Response = S::Response; type Error = S::Error; @@ -511,7 +509,7 @@ where self.service.poll_ready(cx) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let attempt = task.ctx.attempt.clone(); self.ctx.track(AttemptOnPollFuture { attempt, @@ -679,13 +677,13 @@ mod tests { #[derive(Debug, Clone)] struct MyAcknowledger; - impl Acknowledge<(), Conn, Id> for MyAcknowledger { + impl Acknowledge<(), Id> for MyAcknowledger { type Error = SendError; type Future = BoxFuture<'static, Result<(), SendError>>; fn ack( &mut self, res: &Result<(), BoxDynError>, - ctx: &ExecutionContext, + ctx: &ExecutionContext, ) -> Self::Future { println!("{res:?}, {ctx:?}"); // Call webhook with the result and ctx? diff --git a/apalis-core/src/worker/test_worker.rs b/apalis-core/src/worker/test_worker.rs index 7511a955..faee2ba0 100644 --- a/apalis-core/src/worker/test_worker.rs +++ b/apalis-core/src/worker/test_worker.rs @@ -99,7 +99,7 @@ impl fmt::Debug for TestWorker { } /// Utility for executing the next item in the queue -pub trait ExecuteNext { +pub trait ExecuteNext { /// The expected result from the provided service type Result; /// Allows the test worker to step to the next task @@ -107,9 +107,9 @@ pub trait ExecuteNext { fn execute_next(&mut self) -> impl Future + Send; } -impl ExecuteNext for TestWorker +impl ExecuteNext for TestWorker where - S: Service, Response = Res> + Send + 'static, + S: Service, Response = Res> + Send + 'static, B: Send, Res: Send, { @@ -121,17 +121,13 @@ where impl TestWorker { /// Create a new test worker - pub fn new(backend: B, factory: W) -> TestWorker + pub fn new(backend: B, factory: W) -> TestWorker where - W: IntoWorkerService, - W::Backend: Backend - + Unpin - + Send - + 'static, - B: Backend + Send + Unpin + 'static, - S: Service, Response = Res> + Send + 'static, + W: IntoWorkerService, + W::Backend: Backend + Unpin + Send + 'static, + B: Backend + Send + Unpin + 'static, + S: Service, Response = Res> + Send + 'static, Args: Send + 'static, - Conn: Send + Sync + 'static, B::Error: Into + Send + 'static, B::Layer: Layer>>>, S::Future: Send, @@ -140,19 +136,20 @@ impl TestWorker { Res: 'static, <::Layer as Layer< ReadinessService>>, - >>::Service: Service>, + >>::Service: Service>, <<::Layer as Layer< ReadinessService>>, - >>::Service as Service>>::Error: Into + Sync + Send, + >>::Service as Service>>::Error: Into + Sync + Send, <<::Layer as Layer< ReadinessService>>, - >>::Service as Service>>::Future: Send, + >>::Service as Service>>::Future: Send, <::Layer as Layer< ReadinessService>>, >>::Service: std::marker::Send + 'static, B::Id: Send + Sync + 'static, >::Error: std::error::Error + Send + Sync + 'static, - <<>::Backend as Backend>::Codec as Codec>::Error: std::error::Error + Send + Sync + 'static + <<>::Backend as Backend>::Codec as Codec>::Error: + std::error::Error + Send + Sync + 'static, { let worker_service = factory.into_service(backend); TestWorker::::new_with_svc( @@ -164,12 +161,11 @@ impl TestWorker { impl TestWorker { /// Create a new test worker with a service - pub fn new_with_svc(backend: B, service: S) -> TestWorker + pub fn new_with_svc(backend: B, service: S) -> TestWorker where - B: Backend + Send + Unpin + 'static, - S: Service, Response = Res> + Send + 'static, + B: Backend + Send + Unpin + 'static, + S: Service, Response = Res> + Send + 'static, Args: Send + 'static, - Conn: Send + Sync + 'static, B::Error: Into + Send + 'static, B::Layer: Layer>>>, S::Future: Send, @@ -178,13 +174,13 @@ impl TestWorker { Res: 'static, <::Layer as Layer< ReadinessService>>, - >>::Service: Service>, + >>::Service: Service>, <<::Layer as Layer< ReadinessService>>, - >>::Service as Service>>::Error: Into + Sync + Send, + >>::Service as Service>>::Error: Into + Sync + Send, <<::Layer as Layer< ReadinessService>>, - >>::Service as Service>>::Future: Send, + >>::Service as Service>>::Future: Send, <::Layer as Layer< ReadinessService>>, >>::Service: std::marker::Send + 'static, @@ -245,12 +241,11 @@ pub struct TestEmitService { service: S, } -impl Service> for TestEmitService +impl Service> for TestEmitService where - S: Service, Response = Res> + Send + 'static, + S: Service, Response = Res> + Send + 'static, S::Future: Send + 'static, Args: Send + 'static, - Conn: Send + 'static, S::Response: Send + Clone + 'static, S::Error: Into + Send, Id: Send + 'static + Clone, @@ -265,7 +260,7 @@ where .map_err(|e| e.into().to_string()) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let task_id = task.ctx.task_id.clone().unwrap(); let mut tx = Clone::clone(&self.tx); let fut = self.service.call(task); diff --git a/apalis-sql/src/from_row.rs b/apalis-sql/src/from_row.rs index 03078b5c..8b471c55 100644 --- a/apalis-sql/src/from_row.rs +++ b/apalis-sql/src/from_row.rs @@ -62,10 +62,7 @@ pub struct TaskRow { impl TaskRow { /// Convert the TaskRow into a Task with decoded arguments - pub fn try_into_task( - self, - codec: &D, - ) -> Result, FromRowError> + pub fn try_into_task(self, codec: &D) -> Result, FromRowError> where D::Error: Into + Send + Sync + 'static, Id: FromStr, @@ -100,7 +97,7 @@ impl TaskRow { } /// Convert the TaskRow into a Task with compacted arguments - pub fn try_into_task_compact(self) -> Result, Conn, Id>, FromRowError> + pub fn try_into_task_compact(self) -> Result, Id>, FromRowError> where Id: FromStr, ::Err: std::error::Error + Send + Sync + 'static, diff --git a/apalis-workflow/Cargo.toml b/apalis-workflow/Cargo.toml index ee5f546a..c715258a 100644 --- a/apalis-workflow/Cargo.toml +++ b/apalis-workflow/Cargo.toml @@ -20,23 +20,23 @@ uuid = ["dep:uuid"] rand = ["dep:rand"] [dependencies] -petgraph = { version = "0.8.2", features = ["serde-1"] } +petgraph = { version = "0.8.3", features = ["serde-1"] } serde = { version = "1.0", features = ["derive"] } tower = { version = "0.5", features = ["util"], default-features = false } apalis-core = { path = "../apalis-core", version = "1.0.0-rc.9", default-features = false, features = [ "sleep", "serde", ] } -futures = "0.3.30" -thiserror = "2.0.0" +futures = "0.3.33" +thiserror = "2.0.19" # TODO: move to workspace dependencies -tracing = { version = "0.1.41", default-features = false, optional = true } -ulid = { version = "2.0.1", optional = true } -uuid = { version = "1.23.5", features = ["v4"], optional = true } -rand = { version = "0.9", features = ["std"], optional = true } +tracing = { version = "0.1.44", default-features = false, optional = true } +ulid = { version = "3", optional = true } +uuid = { version = "1.24.0", features = ["v4"], optional = true } +rand = { version = "0.10", features = ["std"], optional = true } [dev-dependencies] -tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread", "sync"] } +tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread", "sync"] } apalis-file-storage = { path = "../utils/apalis-file-storage" } serde_json = "1" diff --git a/apalis-workflow/src/dag/executor.rs b/apalis-workflow/src/dag/executor.rs index ed00c006..1f890879 100644 --- a/apalis-workflow/src/dag/executor.rs +++ b/apalis-workflow/src/dag/executor.rs @@ -32,7 +32,7 @@ pub struct DagExecutor where B: Backend, { - pub(super) graph: DiGraph, ()>, + pub(super) graph: DiGraph, ()>, pub(super) node_mapping: HashMap, pub(super) topological_order: Vec, pub(super) start_nodes: Vec, @@ -66,17 +66,16 @@ where pub fn get_node_by_name_mut( &mut self, name: &str, - ) -> Option<&mut DagService> { + ) -> Option<&mut DagService> { self.node_mapping .get(name) .and_then(|&idx| self.graph.node_weight_mut(idx)) } } -impl Service> for DagExecutor +impl Service> for DagExecutor where B: Backend, - B::Connection: Send + Sync + 'static, B::Id: Clone + Send + Sync + 'static + GenerateId + Debug + FromStr + Display, B::Compact: Send + Sync + 'static, ::Err: std::error::Error + Send + Sync + 'static, @@ -109,7 +108,7 @@ where } } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { let mut graph = self.graph.clone(); Box::pin(async move { @@ -133,15 +132,13 @@ where } } -impl IntoWorkerService, B::Compact, B::Connection> - for DagFlow +impl IntoWorkerService, B::Compact> for DagFlow where B: Backend + Clone, Err: std::error::Error + Send + Sync + 'static, - B::Connection: Send + Sync + 'static, B::Id: Send + Sync + 'static + Default + GenerateId + PartialEq + Debug, B::Compact: Send + Sync + 'static + Clone, - RootDagService: Service>, + RootDagService: Service>, { type Backend = RawDataBackend; fn into_service(self, b: B) -> WorkerService, RootDagService> { diff --git a/apalis-workflow/src/dag/mod.rs b/apalis-workflow/src/dag/mod.rs index 28a03a49..d5ac29b5 100644 --- a/apalis-workflow/src/dag/mod.rs +++ b/apalis-workflow/src/dag/mod.rs @@ -54,7 +54,7 @@ where B: Backend, { name: String, - graph: Mutex, ()>>, + graph: Mutex, ()>>, node_mapping: Mutex>, } @@ -91,7 +91,7 @@ where service: S, ) -> NodeBuilder<'_, Input, S::Response, B> where - S: Service> + Send + 'static + Sync + Clone, + S: Service> + Send + 'static + Sync + Clone, S::Future: Send + 'static, B::Codec: Codec + Codec @@ -126,15 +126,11 @@ where node: F, ) -> NodeBuilder<'_, Input, O, B> where - TaskFn: - Service, Response = O, Error = Err> + Clone, + TaskFn: Service, Response = O, Error = Err> + Clone, F: Send + 'static + Sync, Input: Send + 'static + Sync, FnArgs: Send + 'static + Sync, - B::Connection: Send + Sync + 'static, - as Service< - Task, - >>::Future: Send + 'static, + as Service>>::Future: Send + 'static, B::Codec: Codec + 'static, B::Codec: Codec + Send + Clone + 'static, CodecError: Into + Send + 'static, @@ -151,16 +147,12 @@ where router: F, ) -> NodeBuilder<'_, Input, O, B> where - TaskFn: - Service, Response = O, Error = Err> + Clone, + TaskFn: Service, Response = O, Error = Err> + Clone, F: Send + 'static + Sync, Input: Send + 'static + Sync, FnArgs: Send + 'static + Sync, - as Service< - Task, - >>::Future: Send + 'static, + as Service>>::Future: Send + 'static, O: Into, - B::Connection: Send + Sync + 'static, B::Codec: Codec + 'static, B::Codec: Codec + Send + Clone + 'static, CodecError: Into + Send + 'static, @@ -168,7 +160,7 @@ where B: Send + Sync + 'static, Input: DagCodec + Send + Sync + 'static, { - self.add_node::, Input, CodecError>( + self.add_node::, Input, CodecError>( std::any::type_name::(), task_fn(router), ) diff --git a/apalis-workflow/src/dag/node.rs b/apalis-workflow/src/dag/node.rs index c978c8da..abd90734 100644 --- a/apalis-workflow/src/dag/node.rs +++ b/apalis-workflow/src/dag/node.rs @@ -14,7 +14,7 @@ use crate::dag::decode::DagCodec; /// of task inputs and outputs using the backend's codec. pub struct NodeService where - S: Service>, + S: Service>, B: Backend, { inner: S, @@ -23,7 +23,7 @@ where impl std::fmt::Debug for NodeService where - S: Service>, + S: Service>, B: Backend, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -36,7 +36,7 @@ where impl Clone for NodeService where - S: Service> + Clone, + S: Service> + Clone, B: Backend, { fn clone(&self) -> Self { @@ -49,7 +49,7 @@ where impl NodeService where - S: Service>, + S: Service>, B: Backend, { /// Creates a new `NodeService` wrapping the provided service. @@ -61,10 +61,9 @@ where } } -impl Service> - for NodeService +impl Service> for NodeService where - S: Service>, + S: Service>, S::Error: Into, B: Backend + Send + Sync + 'static, B::Codec: Codec @@ -83,7 +82,7 @@ where self.inner.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { let executor = req .ctx .data diff --git a/apalis-workflow/src/dag/service.rs b/apalis-workflow/src/dag/service.rs index b81df45f..1d93d99c 100644 --- a/apalis-workflow/src/dag/service.rs +++ b/apalis-workflow/src/dag/service.rs @@ -73,7 +73,7 @@ fn find_designated_fan_in_handler( designated_handler.ok_or(DagFlowError::Service(DagServiceError::MissingFaninHandler)) } -impl Service> for RootDagService +impl Service> for RootDagService where B: Backend + Send @@ -83,9 +83,8 @@ where + WaitForCompletion, Id: GenerateId + Send + Sync + 'static + PartialEq + Debug + Clone + FromStr + Display, Compact: Send + Sync + 'static + Clone, - B::Connection: Send + Sync + Default + 'static, Err: std::error::Error + Send + Sync + 'static, - B: Sink, Error = Err> + Unpin, + B: Sink, Error = Err> + Unpin, B::Codec: Codec, Compact = Compact, Error = CdcErr> + Send + Clone @@ -105,7 +104,7 @@ where self.executor.poll_ready(cx) } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { let mut executor = self.executor.clone(); let codec = executor.backend.codec().clone(); let start_nodes = executor.start_nodes.clone(); @@ -344,8 +343,7 @@ async fn fan_out_next_nodes( where B::Id: GenerateId + Send + Sync + 'static + PartialEq, B::Compact: Send + Sync + 'static + Clone, - B::Connection: Send + Sync + Default + 'static, - B: Sink, Error = Err> + Unpin, + B: Sink, Error = Err> + Unpin, Err: std::error::Error + Send + Sync + 'static, B: Backend + Send + Sync + 'static + Clone, B::Codec: Codec, Compact = B::Compact, Error = CdcErr>, @@ -400,8 +398,7 @@ async fn fan_out_entry_nodes( where B::Id: GenerateId + Send + Sync + 'static + PartialEq + Debug, B::Compact: Send + Sync + 'static + Clone, - B::Connection: Send + Sync + Default + 'static, - B: Sink, Error = Err> + Unpin, + B: Sink, Error = Err> + Unpin, Err: std::error::Error + Send + Sync + 'static, B: Backend + Send + Sync + 'static + Clone, B::Codec: Codec, Compact = B::Compact, Error = CdcErr> + Clone, diff --git a/apalis-workflow/src/id_generator.rs b/apalis-workflow/src/id_generator.rs index 6a2d8957..693c208e 100644 --- a/apalis-workflow/src/id_generator.rs +++ b/apalis-workflow/src/id_generator.rs @@ -16,7 +16,7 @@ impl GenerateId for uuid::Uuid { #[cfg(feature = "ulid")] impl GenerateId for ulid::Ulid { fn generate() -> Self { - Self::r#gen() + Self::generate() } } diff --git a/apalis-workflow/src/lib.rs b/apalis-workflow/src/lib.rs index 17954ac2..55b1ea93 100644 --- a/apalis-workflow/src/lib.rs +++ b/apalis-workflow/src/lib.rs @@ -12,10 +12,9 @@ use apalis_core::{error::BoxDynError, task::Task}; use crate::sequential::router::{GoTo, StepResult}; type BoxedService = tower::util::BoxCloneSyncService; -type SteppedService = - BoxedService, GoTo>>; +type SteppedService = BoxedService, GoTo>>; -type DagService = BoxedService, Compact>; +type DagService = BoxedService, Compact>; /// combinator for chaining multiple workflows. pub mod composite; diff --git a/apalis-workflow/src/sequential/and_then/mod.rs b/apalis-workflow/src/sequential/and_then/mod.rs index df3e11c9..bee39a26 100644 --- a/apalis-workflow/src/sequential/and_then/mod.rs +++ b/apalis-workflow/src/sequential/and_then/mod.rs @@ -63,13 +63,9 @@ where + Sync + 'static + Clone - + Sink, Error = SinkError> + + Sink, Error = SinkError> + Unpin, - F: Service, Error = BoxDynError> - + Send - + Sync - + 'static - + Clone, + F: Service, Error = BoxDynError> + Send + Sync + 'static + Clone, S: Step, Input: Send + Sync + 'static, F::Future: Send + 'static, @@ -84,7 +80,6 @@ where B::Id: GenerateId + Send + Sync + 'static, S::Response: Send + 'static, B::Compact: Send + 'static, - B::Connection: Send + Sync + 'static, SinkError: std::error::Error + Send + Sync + 'static, F::Response: Send + 'static, { @@ -98,7 +93,7 @@ where })) .map_response(|res: F::Response| GoTo::Next(res)) .service(self.then_fn.clone()); - let svc = SteppedService::::new(svc); + let svc = SteppedService::::new(svc); let count = ctx.steps.len(); ctx.steps.insert(count, svc); self.step.register(ctx) @@ -131,17 +126,17 @@ impl AndThenService { } } -impl Service> +impl Service> for AndThenService where - S: Service, Response = GoTo>, + S: Service, Response = GoTo>, S::Future: Send + 'static, B: Backend + Sync + Send + 'static + Clone - + Sink, Error = SinkError> + + Sink, Error = SinkError> + Unpin, B::Codec: Codec + Codec @@ -154,7 +149,6 @@ where SinkError: std::error::Error + Send + Sync + 'static, Res: Send + 'static, B::Compact: Send + 'static, - B::Connection: Send + Sync + 'static, { type Response = GoTo>; type Error = BoxDynError; @@ -167,7 +161,7 @@ where self.service.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { let mut ctx = request.ctx.data.get::>().cloned().unwrap(); let codec = ctx.backend.codec().clone(); let compacted = request.try_map_args(|t| B::Codec::decode(&codec, &t)); @@ -205,10 +199,9 @@ where pub fn and_then( self, and_then: F, - ) -> Workflow>, L>> + ) -> Workflow>, L>> where - TaskFn: - Service, Response = O>, + TaskFn: Service, Response = O>, { self.add_step(AndThen { then_fn: task_fn(and_then), diff --git a/apalis-workflow/src/sequential/delay/mod.rs b/apalis-workflow/src/sequential/delay/mod.rs index 9898a528..56216453 100644 --- a/apalis-workflow/src/sequential/delay/mod.rs +++ b/apalis-workflow/src/sequential/delay/mod.rs @@ -48,12 +48,7 @@ impl Step for DelayForStep where B::Id: GenerateId + Send + Sync + 'static, B::Compact: Send + 'static, - B: Sink, Error = Err> - + Unpin - + Send - + Sync - + Clone - + 'static, + B: Sink, Error = Err> + Unpin + Send + Sync + Clone + 'static, Err: std::error::Error + Send + Sync + 'static, S: Clone + Send + Sync + 'static, S::Response: Send + 'static, @@ -63,7 +58,6 @@ where + Clone + 'static, >::Error: Into, - B::Connection: Send + Sync + 'static, Input: Send + Sync + 'static, >::Error: Into, B: Backend, @@ -123,15 +117,10 @@ impl Clone for DelayWithStep { impl Step for DelayWithStep where - F: FnMut(Task) -> Duration + Send + Sync + 'static + Clone, + F: FnMut(Task) -> Duration + Send + Sync + 'static + Clone, B::Id: GenerateId + Sync + Send + 'static, B::Compact: Send + 'static, - B: Sink, Error = Err> - + Unpin - + Send - + Sync - + Clone - + 'static, + B: Sink, Error = Err> + Unpin + Send + Sync + Clone + 'static, Err: std::error::Error + Send + Sync + 'static, S: Clone + Send + Sync + 'static, S::Response: Send + 'static, @@ -141,7 +130,6 @@ where + Clone + 'static, >::Error: Into, - B::Connection: Send + Sync + 'static, Input: Send + Sync + 'static, >::Error: Into, B: Backend, @@ -161,15 +149,15 @@ where } } -impl - Service> for DelayWithStep +impl Service> + for DelayWithStep where - F: FnMut(Task) -> Duration + Send + 'static + Clone, + F: FnMut(Task) -> Duration + Send + 'static + Clone, S: Step + Send + 'static, S::Response: Send + 'static, B::Id: GenerateId + Sync + Send + 'static, B::Compact: Send + 'static, - B: Sink, Error = Err> + Unpin + Send + Sync, + B: Sink, Error = Err> + Unpin + Send + Sync, Err: std::error::Error + Send + Sync + 'static, B::Codec: Codec + Codec @@ -178,7 +166,6 @@ where + 'static, >::Error: Into, >::Error: Into, - B::Connection: Send + Sync + 'static, { type Response = GoTo>; type Error = BoxDynError; @@ -191,7 +178,7 @@ where std::task::Poll::Ready(Ok(())) } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { let mut step_context: StepContext = req.ctx.data.get().cloned().unwrap(); let mut f = self.f.clone(); let codec = step_context.backend.codec().clone(); diff --git a/apalis-workflow/src/sequential/filter_map/mod.rs b/apalis-workflow/src/sequential/filter_map/mod.rs index c39d62e1..8eff3079 100644 --- a/apalis-workflow/src/sequential/filter_map/mod.rs +++ b/apalis-workflow/src/sequential/filter_map/mod.rs @@ -224,16 +224,16 @@ where } } -impl - Service> for FilterService +impl Service> + for FilterService where - F: Service, Response = Option>, + F: Service, Response = Option>, B: Backend + Send + Sync + 'static + Clone - + Sink, Error = Err> + + Sink, Error = Err> + WaitForCompletion + Unpin, B::Codec: Codec, Error = CodecError, Compact = B::Compact> @@ -246,7 +246,6 @@ where + Clone + 'static, Id: GenerateId + FromStr + Display + Send + 'static + Clone + Sync, - B::Connection: Send + Sync + 'static, Err: std::error::Error + Send + Sync + 'static, CodecError: std::error::Error + Send + Sync + 'static, F::Error: Into + Send + 'static, @@ -267,7 +266,7 @@ where self.service.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { let filter_state: FilterState = Metadata::extract(&request.ctx.metadata).unwrap_or(FilterState::Init); let mut ctx = request.ctx.data.get::>().cloned().unwrap(); @@ -278,7 +277,7 @@ where // Handle unknown state async move { let main_args: Vec = vec![]; - let steps: Task = + let steps: Task = request.try_map_args(|arg| B::Codec::decode(&codec, &arg))?; let steps = steps.args.into_iter().collect::>(); #[cfg(feature = "tracing")] @@ -321,7 +320,7 @@ where .boxed() } FilterState::SingleStep => { - let step: Task = request + let step: Task = request .try_map_args(|arg| B::Codec::decode(&codec, &arg)) .unwrap(); let fut = self.service.call(step); @@ -362,6 +361,7 @@ where _ => None, } } + _ => None, } }) @@ -392,10 +392,10 @@ where + Sync + 'static + Clone - + Sink, Error = SinkError> + + Sink, Error = SinkError> + WaitForCompletion + Unpin, - F: Service, Error = BoxDynError, Response = Option> + F: Service, Error = BoxDynError, Response = Option> + Send + Sync + 'static @@ -423,7 +423,6 @@ where + Codec>, Error = CodecError, Compact = B::Compact> + 'static, B::Id: GenerateId + Send + Sync + 'static, - B::Connection: Send + Sync + 'static, CodecError: std::error::Error + Send + Sync + 'static, F::Future: Send + 'static, B::Compact: Send + 'static, @@ -449,10 +448,9 @@ impl, B: Backend> Workflow( self, filter_map: F, - ) -> Workflow, B, Stack, I>, L>> + ) -> Workflow, B, Stack, I>, L>> where - TaskFn: - Service, Response = Option>, + TaskFn: Service, Response = Option>, { self.add_step(FilterMap { filter_map: task_fn(filter_map), diff --git a/apalis-workflow/src/sequential/fold/mod.rs b/apalis-workflow/src/sequential/fold/mod.rs index 36d62db1..0a7b2510 100644 --- a/apalis-workflow/src/sequential/fold/mod.rs +++ b/apalis-workflow/src/sequential/fold/mod.rs @@ -51,10 +51,9 @@ impl, B: Backend> Workflow( self, fold: F, - ) -> Workflow, Init>, L>> + ) -> Workflow, Init>, L>> where - TaskFn: - Service, Response = Output>, + TaskFn: Service, Response = Output>, { self.add_step(Fold { fold: task_fn(fold), @@ -74,21 +73,16 @@ pub struct FoldStep { impl, Init, B, Err, CodecError> Step for FoldStep where - F: Service, Response = Init> - + Send - + Sync - + 'static - + Clone, + F: Service, Response = Init> + Send + Sync + 'static + Clone, S: Step, B: Backend + Send + Sync + Clone - + Sink, Error = Err> + + Sink, Error = Err> + Unpin + 'static, I: IntoIterator + Send + Sync + 'static, - B::Connection: Send + Sync + 'static, B::Codec: Codec<(Init, Vec), Error = CodecError, Compact = B::Compact> + Codec + Codec @@ -144,19 +138,18 @@ impl FoldService { } } -impl Service> +impl Service> for FoldService where - F: Service, Response = Init> + Send + 'static + Clone, + F: Service, Response = Init> + Send + 'static + Clone, B: Backend + Send + Sync + Clone - + Sink, Error = Err> + + Sink, Error = Err> + Unpin + 'static, I: IntoIterator + Send + 'static, - B::Connection: Send + Sync + 'static, B::Codec: Codec<(Init, Vec), Error = CodecError, Compact = B::Compact> + Codec + Codec @@ -181,7 +174,7 @@ where self.fold.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let state = FoldState::extract(&task.ctx.metadata).unwrap_or(FoldState::Init); let mut ctx = task.ctx.data.get::>().cloned().unwrap(); let codec = ctx.backend.codec().clone(); @@ -190,8 +183,7 @@ where match state { FoldState::Init => async move { let task_id = TaskId::new(B::Id::generate()); - let steps: Task = - task.try_map_args(|arg| B::Codec::decode(&codec, &arg))?; + let steps: Task = task.try_map_args(|arg| B::Codec::decode(&codec, &arg))?; let steps = steps.args.into_iter().collect::>(); let task = TaskBuilder::new(B::Codec::encode(&codec, &(Init::default(), steps))?) .metadata(&WorkflowContext { diff --git a/apalis-workflow/src/sequential/repeat_until/mod.rs b/apalis-workflow/src/sequential/repeat_until/mod.rs index 96788790..159b7bc9 100644 --- a/apalis-workflow/src/sequential/repeat_until/mod.rs +++ b/apalis-workflow/src/sequential/repeat_until/mod.rs @@ -48,15 +48,9 @@ impl Workflow { pub fn repeat_until( self, repeater: F, - ) -> Workflow< - Start, - Output, - B, - Stack, Input, Output>, L>, - > + ) -> Workflow, Input, Output>, L>> where - TaskFn: - Service, Response = Option>, + TaskFn: Service, Response = Option>, { self.add_step(RepeatUntil { repeater: task_fn(repeater), @@ -92,18 +86,17 @@ where } } -impl Service> +impl Service> for RepeatUntilService where - F: Service, Response = Option> + Send + 'static + Clone, + F: Service, Response = Option> + Send + 'static + Clone, B: Backend + Send + Sync + Clone - + Sink, Error = Err> + + Sink, Error = Err> + Unpin + 'static, - B::Connection: Send + Sync + 'static, B::Codec: Codec + Codec + Codec, Error = CodecError, Compact = B::Compact> @@ -127,7 +120,7 @@ where self.repeater.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let state: RepeaterState = Metadata::extract(&task.ctx.metadata).unwrap_or_default(); let mut ctx = task.ctx.data.get::>().cloned().expect( @@ -286,19 +279,14 @@ where impl Step for RepeatUntilStep where - F: Service, Response = Option> - + Send - + Sync - + 'static - + Clone, + F: Service, Response = Option> + Send + Sync + 'static + Clone, B: Backend + Send + Sync + Clone - + Sink, Error = Err> + + Sink, Error = Err> + Unpin + 'static, - B::Connection: Send + Sync + 'static, B::Codec: Codec + Codec + Codec, Error = CodecError, Compact = B::Compact> diff --git a/apalis-workflow/src/sequential/router.rs b/apalis-workflow/src/sequential/router.rs index 3d387069..8f8b717a 100644 --- a/apalis-workflow/src/sequential/router.rs +++ b/apalis-workflow/src/sequential/router.rs @@ -11,7 +11,7 @@ pub struct WorkflowRouter where B: Backend, { - pub(super) steps: HashMap>, + pub(super) steps: HashMap>, } impl WorkflowRouter diff --git a/apalis-workflow/src/sequential/service.rs b/apalis-workflow/src/sequential/service.rs index 4dd268ef..e7300cc0 100644 --- a/apalis-workflow/src/sequential/service.rs +++ b/apalis-workflow/src/sequential/service.rs @@ -25,7 +25,7 @@ pub struct WorkflowService where B: Backend, { - services: HashMap>, + services: HashMap>, not_ready: VecDeque, backend: B, _marker: PhantomData, @@ -35,10 +35,7 @@ where B: Backend, { /// Creates a new `WorkflowService` with the given services and backend. - pub fn new( - services: HashMap>, - backend: B, - ) -> Self { + pub fn new(services: HashMap>, backend: B) -> Self { Self { services, not_ready: VecDeque::new(), @@ -48,14 +45,13 @@ where } } -impl Service> for WorkflowService +impl Service> for WorkflowService where B::Compact: Send + 'static, B: Sync, - B::Connection: Send, Err: std::error::Error + Send + Sync + 'static, B::Id: GenerateId + Send + 'static, - B: Sink, Error = Err> + Unpin, + B: Sink, Error = Err> + Unpin, B: Clone + Send + Sync + 'static + Backend, { type Response = GoTo>; @@ -84,7 +80,7 @@ where } } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { assert!( self.not_ready.is_empty(), "Workflow must wait for all services to be ready. Did you forget to call poll_ready()?" @@ -114,7 +110,7 @@ pub async fn handle_step_result( result: GoTo, ) -> Result>, TaskSinkError> where - B: Sink, Error = Err> + B: Sink, Error = Err> + Backend + Send + Unpin, diff --git a/apalis-workflow/src/sequential/workflow.rs b/apalis-workflow/src/sequential/workflow.rs index f3fb008f..9661aadd 100644 --- a/apalis-workflow/src/sequential/workflow.rs +++ b/apalis-workflow/src/sequential/workflow.rs @@ -102,18 +102,16 @@ impl Step for RootStep { } impl - IntoWorkerService, Compact, B::Connection> - for Workflow + IntoWorkerService, Compact> for Workflow where B: Backend + Send + Sync + 'static - + Sink, Error = Err> + + Sink, Error = Err> + Unpin + Clone, Err: std::error::Error + Send + Sync + 'static, - B::Connection: Send + Sync + 'static, B::Id: Send + 'static + Default + GenerateId, B: Sync + Backend, B::Compact: Send + Sync + 'static, diff --git a/apalis-workflow/src/sink.rs b/apalis-workflow/src/sink.rs index 5c3710de..9da89ed4 100644 --- a/apalis-workflow/src/sink.rs +++ b/apalis-workflow/src/sink.rs @@ -61,12 +61,9 @@ where impl WorkflowSink for S where - S: Sink, Error = Err> - + Backend - + Unpin, + S: Sink, Error = Err> + Backend + Unpin, S::Id: GenerateId + Send + Sync + FromStr + Display, S::Codec: Codec, - S::Connection: Send + Sync, Err: std::error::Error + Send + Sync + 'static, >::Error: Into + Send + Sync + 'static, Compact: Send + 'static, diff --git a/apalis/Cargo.toml b/apalis/Cargo.toml index 4ef8dbfb..9facfacb 100644 --- a/apalis/Cargo.toml +++ b/apalis/Cargo.toml @@ -71,30 +71,30 @@ version = "0.2" optional = true [dependencies] -tower = { version = "0.5.2", features = ["util"], default-features = false } -sentry-core = { version = "0.48.4", optional = true, default-features = false } -metrics = { version = "0.24.5", optional = true, default-features = false } -metrics-exporter-prometheus = { version = "0.18.1", optional = true, default-features = false } +tower = { version = "0.5.3", features = ["util"], default-features = false } +sentry-core = { version = "0.48.5", optional = true, default-features = false } +metrics = { version = "0.24.6", optional = true, default-features = false } +metrics-exporter-prometheus = { version = "0.18.3", optional = true, default-features = false } opentelemetry = { version = "0.32.0", optional = true, default-features = false, features = ["metrics"] } tracing-opentelemetry = { version = "0.33.0", optional = true, default-features = false } -futures-util = { version = "0.3.31", optional = true, default-features = false } -thiserror = "2.0.0" +futures-util = { version = "0.3.33", optional = true, default-features = false } +thiserror = "2.0.19" pin-project = "1" # Needed only for sentry reporting -uuid = { version = "1.23.5", optional = true } -ulid = { version = "2.0.1", optional = true } +uuid = { version = "1.24.0", optional = true } +ulid = { version = "3.0.0", optional = true } [dependencies.tracing] default-features = false -version = "0.1.40" +version = "0.1.44" optional = true [dev-dependencies] apalis-core = { path = "../apalis-core", version = "1.0.0-rc.9" } serde = "1" tokio = { version = "1", features = ["full"] } -tracing-subscriber = { version = "0.3.20", default-features = false, features = ["std"] } +tracing-subscriber = { version = "0.3.23", default-features = false, features = ["std"] } opentelemetry = { version = "0.32.0", default-features = false, features = ["trace"] } opentelemetry_sdk = { version = "0.32.1", default-features = false, features = ["trace"] } tracing-opentelemetry = { version = "0.33.0", default-features = false } diff --git a/apalis/src/layers/catch_panic/mod.rs b/apalis/src/layers/catch_panic/mod.rs index ecf45489..3dd933da 100644 --- a/apalis/src/layers/catch_panic/mod.rs +++ b/apalis/src/layers/catch_panic/mod.rs @@ -143,9 +143,9 @@ pub struct CatchPanicService { on_panic: F, } -impl Service> for CatchPanicService +impl Service> for CatchPanicService where - S: Service, Response = Res>, + S: Service, Response = Res>, F: FnMut(Box) -> PanicErr + Clone, S::Error: Into, PanicErr: Into, @@ -158,7 +158,7 @@ where self.service.poll_ready(cx).map_err(Into::into) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { match std::panic::catch_unwind(AssertUnwindSafe(|| self.service.call(task))) { Ok(future) => CatchPanicFuture { kind: Kind::Future { @@ -293,7 +293,7 @@ mod tests { #[derive(Clone)] struct TestService; - impl Service> for TestService { + impl Service> for TestService { type Response = usize; type Error = AbortError; type Future = Pin> + Send>>; @@ -302,7 +302,7 @@ mod tests { Poll::Ready(Ok(())) } - fn call(&mut self, _req: Task) -> Self::Future { + fn call(&mut self, _req: Task) -> Self::Future { Box::pin(async { Ok(42) }) } } @@ -322,7 +322,7 @@ mod tests { async fn test_catch_panic_layer_panics() { struct PanicService; - impl Service> for PanicService { + impl Service> for PanicService { type Response = usize; type Error = AbortError; type Future = Pin> + Send>>; @@ -331,7 +331,7 @@ mod tests { Poll::Ready(Ok(())) } - fn call(&mut self, _req: Task) -> Self::Future { + fn call(&mut self, _req: Task) -> Self::Future { Box::pin(async { None::<()>.unwrap(); todo!() diff --git a/apalis/src/layers/mod.rs b/apalis/src/layers/mod.rs index 386a9869..b7a795b6 100644 --- a/apalis/src/layers/mod.rs +++ b/apalis/src/layers/mod.rs @@ -44,25 +44,25 @@ pub use tower::timeout::TimeoutLayer; pub mod catch_panic; /// An extension trait that extends `WorkerBuilder` with additional middleware methods -pub trait WorkerBuilderExt { +pub trait WorkerBuilderExt { /// Optionally adds a new layer `T` into the [`WorkerBuilder`]. fn option_layer( self, layer: Option, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Adds a [`Layer`] built from a function that accepts a service and returns another service. fn layer_fn( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Limits the max number of in-flight requests. #[cfg(feature = "limit")] fn concurrency( self, max: usize, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; /// Limits requests to at most `num` per the given duration. #[cfg(feature = "limit")] @@ -70,41 +70,41 @@ pub trait WorkerBuilderExt { self, num: u64, per: std::time::Duration, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; /// Retries failed requests according to the given retry policy. #[cfg(feature = "retry")] fn retry

( self, policy: P, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Fails requests that take longer than `timeout`. #[cfg(feature = "timeout")] fn timeout( self, timeout: std::time::Duration, - ) -> WorkerBuilder>; + ) -> WorkerBuilder>; /// Conditionally rejects requests based on `predicate`. #[cfg(feature = "filter")] fn filter

( self, predicate: P, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Conditionally rejects requests based on an asynchronous `predicate`. #[cfg(feature = "filter")] fn filter_async

( self, predicate: P, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Maps one request type to another. fn map_request( self, f: F, - ) -> WorkerBuilder, Middleware>> + ) -> WorkerBuilder, Middleware>> where F: FnMut(R1) -> R2 + Clone; @@ -112,37 +112,37 @@ pub trait WorkerBuilderExt { fn map_response( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Maps one error type to another. fn map_err( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Composes a function that transforms futures produced by the service. fn map_future( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Applies an asynchronous function after the service, regardless of whether the future succeeds or fails. fn then( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Executes a new future after this service's future resolves. fn and_then( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Maps the service's result type to a different value, regardless of success or failure. fn map_result( self, f: F, - ) -> WorkerBuilder, Middleware>>; + ) -> WorkerBuilder, Middleware>>; /// Catch panics in execution and pipe them as errors #[cfg(feature = "catch-panic")] @@ -152,7 +152,6 @@ pub trait WorkerBuilderExt { self, ) -> WorkerBuilder< Args, - Conn, Source, Stack< CatchPanicLayer) -> AbortError, AbortError>, @@ -162,28 +161,25 @@ pub trait WorkerBuilderExt { /// Enable tracing via tracing crate #[cfg(feature = "tracing")] #[cfg_attr(docsrs, doc(cfg(feature = "tracing")))] - fn enable_tracing( - self, - ) -> WorkerBuilder>; + fn enable_tracing(self) -> WorkerBuilder>; } -impl WorkerBuilderExt - for WorkerBuilder +impl WorkerBuilderExt + for WorkerBuilder where - Source: Backend, + Source: Backend, { fn option_layer( self, layer: Option, - ) -> WorkerBuilder, Middleware>> - { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::option_layer(layer)) } fn layer_fn( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::layer::layer_fn(f)) } @@ -191,8 +187,7 @@ where fn concurrency( self, max: usize, - ) -> WorkerBuilder> - { + ) -> WorkerBuilder> { self.layer(tower::limit::ConcurrencyLimitLayer::new(max)) } @@ -201,7 +196,7 @@ where self, num: u64, per: std::time::Duration, - ) -> WorkerBuilder> { + ) -> WorkerBuilder> { self.layer(tower::limit::RateLimitLayer::new(num, per)) } @@ -209,7 +204,7 @@ where fn retry

( self, policy: P, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::retry::RetryLayer::new(policy)) } @@ -217,7 +212,7 @@ where fn timeout( self, timeout: std::time::Duration, - ) -> WorkerBuilder> { + ) -> WorkerBuilder> { self.layer(tower::timeout::TimeoutLayer::new(timeout)) } @@ -225,7 +220,7 @@ where fn filter

( self, predicate: P, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::filter::FilterLayer::new(predicate)) } @@ -233,15 +228,14 @@ where fn filter_async

( self, predicate: P, - ) -> WorkerBuilder, Middleware>> - { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::filter::AsyncFilterLayer::new(predicate)) } fn map_request( self, f: F, - ) -> WorkerBuilder, Middleware>> + ) -> WorkerBuilder, Middleware>> where F: FnMut(R1) -> R2 + Clone, { @@ -251,43 +245,42 @@ where fn map_response( self, f: F, - ) -> WorkerBuilder, Middleware>> - { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::MapResponseLayer::new(f)) } fn map_err( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::MapErrLayer::new(f)) } fn map_future( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::MapFutureLayer::new(f)) } fn then( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::ThenLayer::new(f)) } fn and_then( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::AndThenLayer::new(f)) } fn map_result( self, f: F, - ) -> WorkerBuilder, Middleware>> { + ) -> WorkerBuilder, Middleware>> { self.layer(tower::util::MapResultLayer::new(f)) } @@ -298,7 +291,6 @@ where self, ) -> WorkerBuilder< Args, - Conn, Source, Stack< CatchPanicLayer) -> AbortError, AbortError>, @@ -311,9 +303,7 @@ where /// Enable tracing via tracing crate #[cfg(feature = "tracing")] #[cfg_attr(docsrs, doc(cfg(feature = "tracing")))] - fn enable_tracing( - self, - ) -> WorkerBuilder> { + fn enable_tracing(self) -> WorkerBuilder> { use tracing::TraceLayer; self.layer(TraceLayer::new()) diff --git a/apalis/src/layers/opentelemetry/mod.rs b/apalis/src/layers/opentelemetry/mod.rs index 10097f64..f26caf6e 100644 --- a/apalis/src/layers/opentelemetry/mod.rs +++ b/apalis/src/layers/opentelemetry/mod.rs @@ -52,10 +52,9 @@ pub struct OpenTelemetryMetricsService { duration_histogram: Histogram, } -impl Service> - for OpenTelemetryMetricsService +impl Service> for OpenTelemetryMetricsService where - Svc: Service, Response = Res, Error = Err, Future = Fut>, + Svc: Service, Response = Res, Error = Err, Future = Fut>, Fut: Future> + 'static, { type Response = Svc::Response; @@ -66,7 +65,7 @@ where self.service.poll_ready(cx) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { let start = Instant::now(); let worker = request .ctx diff --git a/apalis/src/layers/prometheus/mod.rs b/apalis/src/layers/prometheus/mod.rs index de3fad59..a5b5ed87 100644 --- a/apalis/src/layers/prometheus/mod.rs +++ b/apalis/src/layers/prometheus/mod.rs @@ -27,9 +27,9 @@ pub struct PrometheusService { service: S, } -impl Service> for PrometheusService +impl Service> for PrometheusService where - Svc: Service, Response = Res, Error = Err, Future = Fut>, + Svc: Service, Response = Res, Error = Err, Future = Fut>, Fut: Future> + 'static, { type Response = Svc::Response; @@ -40,7 +40,7 @@ where self.service.poll_ready(cx) } - fn call(&mut self, request: Task) -> Self::Future { + fn call(&mut self, request: Task) -> Self::Future { let start = Instant::now(); let worker = request .ctx diff --git a/apalis/src/layers/retry/mod.rs b/apalis/src/layers/retry/mod.rs index 08747a0e..63baa428 100644 --- a/apalis/src/layers/retry/mod.rs +++ b/apalis/src/layers/retry/mod.rs @@ -122,10 +122,9 @@ impl BackoffRetryPolicy { } } -impl Policy, Res, Err> for BackoffRetryPolicy +impl Policy, Res, Err> for BackoffRetryPolicy where T: Clone, - Conn: Clone, Id: Clone, B: Backoff, B::Future: Send + 'static, @@ -134,7 +133,7 @@ where fn retry( &mut self, - req: &mut Task, + req: &mut Task, result: &mut Result, ) -> Option { let attempt = req.ctx.attempt.current(); @@ -159,7 +158,7 @@ where } } - fn clone_request(&mut self, req: &Task) -> Option> { + fn clone_request(&mut self, req: &Task) -> Option> { let req = req.clone(); Some(req) } @@ -205,17 +204,16 @@ impl RetryPolicy { } } -impl Policy, Res, Err> for RetryPolicy +impl Policy, Res, Err> for RetryPolicy where T: Clone, - Conn: Clone, Id: Clone, { type Future = std::future::Ready<()>; fn retry( &mut self, - req: &mut Task, + req: &mut Task, result: &mut Result, ) -> Option { let attempt = req.ctx.attempt.current(); @@ -238,7 +236,7 @@ where } } - fn clone_request(&mut self, req: &Task) -> Option> { + fn clone_request(&mut self, req: &Task) -> Option> { let req = req.clone(); Some(req) } @@ -264,18 +262,17 @@ impl RetryIfPolicy { FromTaskConfigPolicy::new(self) } } -impl Policy, Res, Err> for RetryIfPolicy +impl Policy, Res, Err> for RetryIfPolicy where T: Clone, - Conn: Clone, - P: Policy, Res, Err>, + P: Policy, Res, Err>, F: Fn(&Err) -> bool + Send + Sync + 'static, { type Future = P::Future; fn retry( &mut self, - req: &mut Task, + req: &mut Task, result: &mut Result, ) -> Option { let worker = req.ctx.data.get::()?; @@ -293,7 +290,7 @@ where } } - fn clone_request(&mut self, req: &Task) -> Option> { + fn clone_request(&mut self, req: &Task) -> Option> { self.inner.clone_request(req) } } @@ -370,17 +367,16 @@ impl Default for FromTaskConfigPolicy { } } -impl Policy, Res, Err> for FromTaskConfigPolicy

+impl Policy, Res, Err> for FromTaskConfigPolicy

where T: Clone, - Conn: Clone, - P: Policy, Res, Err>, + P: Policy, Res, Err>, { type Future = P::Future; fn retry( &mut self, - req: &mut Task, + req: &mut Task, result: &mut Result, ) -> Option { let worker = req.ctx.data.get::()?; @@ -403,7 +399,7 @@ where } } - fn clone_request(&mut self, req: &Task) -> Option> { + fn clone_request(&mut self, req: &Task) -> Option> { self.inner.clone_request(req) } } @@ -414,7 +410,7 @@ pub trait RetryMetadataExt { fn retries(self, retries: usize) -> Self; } -impl RetryMetadataExt for TaskBuilder { +impl RetryMetadataExt for TaskBuilder { /// Set number of retries in the metadata fn retries(self, retries: usize) -> Self { self.metadata(&RetryConfig { retries }) diff --git a/apalis/src/layers/sentry/mod.rs b/apalis/src/layers/sentry/mod.rs index 29d4898e..02504561 100644 --- a/apalis/src/layers/sentry/mod.rs +++ b/apalis/src/layers/sentry/mod.rs @@ -153,9 +153,9 @@ where } } -impl Service> for SentryTaskService +impl Service> for SentryTaskService where - Svc: Service, Response = Res, Error = Err, Future = Fut>, + Svc: Service, Response = Res, Error = Err, Future = Fut>, Fut: Future> + 'static, Id: ToUuid, Err: Into + 'static, @@ -168,7 +168,7 @@ where self.service.poll_ready(cx).map_err(|e| e.into()) } - fn call(&mut self, task: Task) -> Self::Future { + fn call(&mut self, task: Task) -> Self::Future { let task_type = std::any::type_name::().to_string(); let attempt = &task.ctx.attempt; let task_id = task diff --git a/apalis/src/layers/tracing/contextual_span.rs b/apalis/src/layers/tracing/contextual_span.rs index a3767f96..2bf21d0b 100644 --- a/apalis/src/layers/tracing/contextual_span.rs +++ b/apalis/src/layers/tracing/contextual_span.rs @@ -43,11 +43,11 @@ impl Default for ContextualTaskSpan { } } -impl MakeSpan for ContextualTaskSpan +impl MakeSpan for ContextualTaskSpan where Id: Display, { - fn make_span(&mut self, req: &Task) -> Span { + fn make_span(&mut self, req: &Task) -> Span { let task_id = req .ctx .task_id diff --git a/apalis/src/layers/tracing/make_span.rs b/apalis/src/layers/tracing/make_span.rs index 4ca9ee7f..46173b8c 100644 --- a/apalis/src/layers/tracing/make_span.rs +++ b/apalis/src/layers/tracing/make_span.rs @@ -10,22 +10,22 @@ use super::DEFAULT_MESSAGE_LEVEL; /// /// [`Span`]: tracing::Span /// [`Trace`]: super::Trace -pub trait MakeSpan { +pub trait MakeSpan { /// Make a span from a request. - fn make_span(&mut self, request: &Task) -> Span; + fn make_span(&mut self, request: &Task) -> Span; } -impl MakeSpan for Span { - fn make_span(&mut self, _request: &Task) -> Span { +impl MakeSpan for Span { + fn make_span(&mut self, _request: &Task) -> Span { self.clone() } } -impl MakeSpan for F +impl MakeSpan for F where - F: FnMut(&Task) -> Span, + F: FnMut(&Task) -> Span, { - fn make_span(&mut self, request: &Task) -> Span { + fn make_span(&mut self, request: &Task) -> Span { self(request) } } @@ -64,8 +64,8 @@ impl Default for DefaultMakeSpan { } } -impl MakeSpan for DefaultMakeSpan { - fn make_span(&mut self, req: &Task) -> Span { +impl MakeSpan for DefaultMakeSpan { + fn make_span(&mut self, req: &Task) -> Span { // This ugly macro is needed, unfortunately, because `tracing::span!` // required the level argument to be static. Meaning we can't just pass // `self.level`. diff --git a/apalis/src/layers/tracing/mod.rs b/apalis/src/layers/tracing/mod.rs index a244f9ac..979ef482 100644 --- a/apalis/src/layers/tracing/mod.rs +++ b/apalis/src/layers/tracing/mod.rs @@ -293,13 +293,13 @@ impl } } -impl - Service> for Trace +impl Service> + for Trace where - S: Service, Response = Res, Future = F> + Unpin + Send + 'static, + S: Service, Response = Res, Future = F> + Unpin + Send + 'static, S::Error: fmt::Display + 'static, - MakeSpanT: MakeSpan, - OnRequestT: OnRequest, + MakeSpanT: MakeSpan, + OnRequestT: OnRequest, OnResponseT: OnResponse + Clone + 'static, F: Future> + 'static, OnFailureT: OnFailure + Clone + 'static, @@ -312,7 +312,7 @@ where self.inner.poll_ready(cx) } - fn call(&mut self, req: Task) -> Self::Future { + fn call(&mut self, req: Task) -> Self::Future { let span = self.make_span.make_span(&req); let start = Instant::now(); let job = { @@ -382,10 +382,7 @@ mod tests { use super::*; use apalis_core::{ - backend::{ - TaskSink, - memory::{MemoryContext, MemoryStorage}, - }, + backend::{TaskSink, memory::MemoryStorage}, error::BoxDynError, task::task_id::RandomId, worker::{ @@ -433,14 +430,14 @@ mod tests { .backend(in_memory) .layer( TraceLayer::new() - .make_span_with(|req: &Task| { + .make_span_with(|req: &Task| { tracing::span!( tracing::Level::INFO, "custom_span", task_id = req.ctx.task_id.as_ref().unwrap().to_string() ) }) - .on_request(|task: &Task, span: &tracing::Span| { + .on_request(|task: &Task, span: &tracing::Span| { tracing::info!(parent: span, "Custom OnRequest: Received task: {:?}", task); }) .on_response(|_: &() , duration: Duration, span: &tracing::Span| { diff --git a/apalis/src/layers/tracing/on_request.rs b/apalis/src/layers/tracing/on_request.rs index 0b142710..d5ab09d3 100644 --- a/apalis/src/layers/tracing/on_request.rs +++ b/apalis/src/layers/tracing/on_request.rs @@ -10,7 +10,7 @@ use tracing::Span; /// `on_request` callback is called. /// /// [`Trace`]: super::Trace -pub trait OnRequest { +pub trait OnRequest { /// Do the thing. /// /// `span` is the `tracing` [`Span`], corresponding to this request, produced by the closure @@ -20,14 +20,14 @@ pub trait OnRequest { /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/index.html /// [record]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html#method.record /// [`TraceLayer::make_span_with`]: crate::layers::tracing::TraceLayer::make_span_with - fn on_request(&mut self, request: &Task, span: &Span); + fn on_request(&mut self, request: &Task, span: &Span); } -impl OnRequest for F +impl OnRequest for F where - F: for<'a> FnMut(&'a Task, &'a Span), + F: for<'a> FnMut(&'a Task, &'a Span), { - fn on_request(&mut self, request: &Task, span: &Span) { + fn on_request(&mut self, request: &Task, span: &Span) { self(request, span) } } @@ -71,8 +71,8 @@ impl DefaultOnRequest { } } -impl OnRequest for DefaultOnRequest { - fn on_request(&mut self, _: &Task, _: &Span) { +impl OnRequest for DefaultOnRequest { + fn on_request(&mut self, _: &Task, _: &Span) { match self.level { Level::ERROR => { tracing::event!(Level::ERROR, "task.start",); diff --git a/apalis/src/lib.rs b/apalis/src/lib.rs index bb6af215..f59d863f 100644 --- a/apalis/src/lib.rs +++ b/apalis/src/lib.rs @@ -34,7 +34,7 @@ pub mod prelude { RunningWorker, StatType, Statistic, TaskResult, TaskSink, TaskSinkError, Update, WaitForCompletion, }, - backend::{codec::*, custom::*, ext::pipe::*, memory::*, poll_strategy::*, shared::*}, + backend::{codec::*, custom::*, ext::pipe::*, factory::*, memory::*, poll_strategy::*}, error::*, layers::*, monitor::{ExitError, Monitor, MonitorError, MonitoredWorkerError, shutdown::Shutdown}, diff --git a/examples/basics/Cargo.toml b/examples/basics/Cargo.toml index f7383f2f..9e4da804 100644 --- a/examples/basics/Cargo.toml +++ b/examples/basics/Cargo.toml @@ -6,13 +6,13 @@ edition = "2024" license = "MIT OR Apache-2.0" [dependencies] -thiserror = "2.0.0" +thiserror = "2.0.19" tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["limit", "catch-panic", "tracing"] } apalis-core = { path = "../../apalis-core" , features = ["serde"]} serde = "1" serde_json = "1" -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" email-service = { path = "../email-service" } futures = "0.3" tower = "0.5" diff --git a/examples/catch-panic/Cargo.toml b/examples/catch-panic/Cargo.toml index b06335db..55abf877 100644 --- a/examples/catch-panic/Cargo.toml +++ b/examples/catch-panic/Cargo.toml @@ -11,7 +11,7 @@ anyhow = "1" tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["limit", "catch-panic", "tracing"] } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" email-service = { path = "../email-service" } diff --git a/examples/dag-workflow/Cargo.toml b/examples/dag-workflow/Cargo.toml index ffa87fa8..d78857fc 100644 --- a/examples/dag-workflow/Cargo.toml +++ b/examples/dag-workflow/Cargo.toml @@ -13,7 +13,7 @@ apalis = { path = "../../apalis", features = ["limit", "catch-panic", "retry"] } apalis-workflow = { path = "../../apalis-workflow" } apalis-file-storage = { path = "../../utils/apalis-file-storage" } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" serde_json = "1" diff --git a/examples/dynamic-workers/Cargo.toml b/examples/dynamic-workers/Cargo.toml index 10eac446..a6a606d4 100644 --- a/examples/dynamic-workers/Cargo.toml +++ b/examples/dynamic-workers/Cargo.toml @@ -12,7 +12,7 @@ apalis = { path = "../../apalis" } serde = "1" tokio = { version = "1", features = ["full"] } env_logger = "0.11" -tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json"] } +tracing-subscriber = { version = "0.3.23", features = ["env-filter", "json"] } chrono = { version = "0.4", default-features = false, features = ["clock"] } email-service = { path = "../email-service" } futures = "0.3" diff --git a/examples/email-service/Cargo.toml b/examples/email-service/Cargo.toml index 22bd8e7d..786ac3bf 100644 --- a/examples/email-service/Cargo.toml +++ b/examples/email-service/Cargo.toml @@ -7,8 +7,8 @@ publish = false [dependencies] apalis = { path = "../../apalis", default-features = false } -futures-util = "0.3.0" +futures-util = "0.3.33" serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } log = "0.4" -email_address = "0.2.5" +email_address = "0.2.9" diff --git a/examples/fn-args/Cargo.toml b/examples/fn-args/Cargo.toml index dea49e3c..8ccce7c3 100644 --- a/examples/fn-args/Cargo.toml +++ b/examples/fn-args/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["tracing"] } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" tower = "0.5" diff --git a/examples/graceful-shutdown/Cargo.toml b/examples/graceful-shutdown/Cargo.toml index 84f32287..be91a9e3 100644 --- a/examples/graceful-shutdown/Cargo.toml +++ b/examples/graceful-shutdown/Cargo.toml @@ -7,12 +7,12 @@ edition.workspace = true repository.workspace = true [dependencies] -thiserror = "2.0.0" +thiserror = "2.0.19" tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["limit", "catch-panic"] } apalis-core = { path = "../../apalis-core", features = ["serde"] } serde = "1" -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" tower = "0.5" diff --git a/examples/long-running/Cargo.toml b/examples/long-running/Cargo.toml index d14322ff..72374fc5 100644 --- a/examples/long-running/Cargo.toml +++ b/examples/long-running/Cargo.toml @@ -11,7 +11,7 @@ anyhow = "1" tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["limit", "catch-panic", "tracing"] } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" [dependencies.tracing] diff --git a/examples/monitor/Cargo.toml b/examples/monitor/Cargo.toml index d013f237..964935f2 100644 --- a/examples/monitor/Cargo.toml +++ b/examples/monitor/Cargo.toml @@ -12,7 +12,7 @@ apalis = { path = "../../apalis", features = ["opentelemetry"] } serde = "1" tokio = { version = "1", features = ["full"] } env_logger = "0.11" -tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json"] } +tracing-subscriber = { version = "0.3.23", features = ["env-filter", "json"] } chrono = { version = "0.4", default-features = false, features = ["clock"] } email-service = { path = "../email-service" } futures = "0.3" diff --git a/examples/opentelemetry/Cargo.toml b/examples/opentelemetry/Cargo.toml index f5ec2002..c7c67bc3 100644 --- a/examples/opentelemetry/Cargo.toml +++ b/examples/opentelemetry/Cargo.toml @@ -7,8 +7,8 @@ publish = false [dependencies] anyhow = "1" -axum = { version = "0.8.8", features = [ "macros" ] } -tokio = { version = "1.0", features = ["full"] } +axum = { version = "0.8.9", features = [ "macros" ] } +tokio = { version = "1.53", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } serde = { version = "1.0", features = ["derive"] } diff --git a/examples/prometheus/Cargo.toml b/examples/prometheus/Cargo.toml index 59f6aa4d..d99a17a7 100644 --- a/examples/prometheus/Cargo.toml +++ b/examples/prometheus/Cargo.toml @@ -7,14 +7,14 @@ publish = false [dependencies] anyhow = "1" -axum = "0.8.8" -tokio = { version = "1.0", features = ["full"] } -tracing = "0.1.41" -tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } +axum = "0.8.9" +tokio = { version = "1.53", features = ["full"] } +tracing = "0.1.44" +tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } serde = { version = "1.0", features = ["derive"] } apalis = { path = "../../apalis", features = ["prometheus"] } apalis-core = { path = "../../apalis-core", features = ["serde"] } futures = "0.3" -metrics-exporter-prometheus = "0.18.1" +metrics-exporter-prometheus = "0.18.3" email-service = { path = "../email-service" } apalis-file-storage = { path = "../../utils/apalis-file-storage" } diff --git a/examples/retries/Cargo.toml b/examples/retries/Cargo.toml index b42ad1d3..be8f3aa3 100644 --- a/examples/retries/Cargo.toml +++ b/examples/retries/Cargo.toml @@ -10,7 +10,7 @@ publish = false anyhow = "1" apalis = { path = "../../apalis", features = ["retry", "limit"] } serde = "1" -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" chrono = { version = "0.4", default-features = false, features = ["clock"] } tokio = { version = "1", features = ["full"] } email-service = { path = "../email-service" } diff --git a/examples/sentry/Cargo.toml b/examples/sentry/Cargo.toml index 4c7b9582..d3390d9b 100644 --- a/examples/sentry/Cargo.toml +++ b/examples/sentry/Cargo.toml @@ -10,10 +10,10 @@ anyhow = "1" apalis = { path = "../../apalis", features = ["sentry"] } serde = "1" env_logger = "0.11" -tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } -sentry = "0.48.4" -sentry-tower = "0.48.4" -sentry-tracing = "0.48.4" +tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } +sentry = "0.48.5" +sentry-tower = "0.48.5" +sentry-tracing = "0.48.5" chrono = { version = "0.4", default-features = false, features = ["clock"] } tokio = { version = "1", features = ["full"] } email-service = { path = "../email-service" } diff --git a/examples/stepped-workflow/Cargo.toml b/examples/stepped-workflow/Cargo.toml index 65295e91..a7ad6cb4 100644 --- a/examples/stepped-workflow/Cargo.toml +++ b/examples/stepped-workflow/Cargo.toml @@ -12,7 +12,7 @@ apalis = { path = "../../apalis", features = ["limit", "catch-panic", "retry"] } apalis-workflow = { path = "../../apalis-workflow" } apalis-file-storage = { path = "../../utils/apalis-file-storage" } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" [dependencies.tracing] diff --git a/examples/tracing/Cargo.toml b/examples/tracing/Cargo.toml index 74658ec6..3403a1f3 100644 --- a/examples/tracing/Cargo.toml +++ b/examples/tracing/Cargo.toml @@ -11,7 +11,7 @@ apalis = { path = "../../apalis", features = ["opentelemetry"] } serde = "1" tokio = { version = "1", features = ["full"] } env_logger = "0.11" -tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json"] } +tracing-subscriber = { version = "0.3.23", features = ["env-filter", "json"] } chrono = { version = "0.4", default-features = false, features = ["clock"] } email-service = { path = "../email-service" } futures = "0.3" diff --git a/examples/unique-jobs/Cargo.toml b/examples/unique-jobs/Cargo.toml index 7f49e0a0..4bcfcd86 100644 --- a/examples/unique-jobs/Cargo.toml +++ b/examples/unique-jobs/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true anyhow = "1" apalis = { path = "../../apalis", features = ["retry", "limit"] } serde = "1" -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" chrono = { version = "0.4", default-features = false, features = ["clock"] } tokio = { version = "1", features = ["full"] } email-service = { path = "../email-service" } diff --git a/examples/unmonitored-worker/Cargo.toml b/examples/unmonitored-worker/Cargo.toml index 6dfeb5ba..c1df7d2f 100644 --- a/examples/unmonitored-worker/Cargo.toml +++ b/examples/unmonitored-worker/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true tokio = { version = "1", features = ["full"] } apalis = { path = "../../apalis", features = ["limit", "catch-panic"] } serde = { version = "1", features = ["derive"] } -tracing-subscriber = "0.3.20" +tracing-subscriber = "0.3.23" futures = "0.3" tower = "0.5" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 3310ae1a..580560e4 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -85,7 +85,7 @@ version = "3.0.11" criteria = "safe-to-deploy" [[exemptions.anyhow]] -version = "1.0.103" +version = "1.0.104" criteria = "safe-to-deploy" [[exemptions.apalis]] @@ -105,7 +105,7 @@ version = "0.1.0-rc.3" criteria = "safe-to-deploy" [[exemptions.async-trait]] -version = "0.1.89" +version = "0.1.91" criteria = "safe-to-deploy" [[exemptions.atomic-waker]] @@ -117,11 +117,11 @@ version = "1.5.1" criteria = "safe-to-deploy" [[exemptions.aws-lc-rs]] -version = "1.17.1" +version = "1.17.3" criteria = "safe-to-deploy" [[exemptions.aws-lc-sys]] -version = "0.42.0" +version = "0.43.0" criteria = "safe-to-deploy" [[exemptions.axum]] @@ -185,7 +185,7 @@ version = "1.5.1" criteria = "safe-to-deploy" [[exemptions.cc]] -version = "1.2.67" +version = "1.4.0" criteria = "safe-to-deploy" [[exemptions.cfg-if]] @@ -285,7 +285,7 @@ version = "1.0.5" criteria = "safe-to-deploy" [[exemptions.either]] -version = "1.16.0" +version = "1.17.0" criteria = "safe-to-deploy" [[exemptions.email_address]] @@ -321,7 +321,7 @@ version = "11.0.0" criteria = "safe-to-deploy" [[exemptions.fastrand]] -version = "2.4.1" +version = "2.5.0" criteria = "safe-to-deploy" [[exemptions.fd-lock]] @@ -369,35 +369,35 @@ version = "1.3.0" criteria = "safe-to-deploy" [[exemptions.futures]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-channel]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-core]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-executor]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-io]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-macro]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-sink]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-task]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.futures-timer]] @@ -405,7 +405,7 @@ version = "3.0.4" criteria = "safe-to-deploy" [[exemptions.futures-util]] -version = "0.3.32" +version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.generator]] @@ -449,7 +449,7 @@ version = "0.17.1" criteria = "safe-to-deploy" [[exemptions.hdrhistogram]] -version = "7.5.4" +version = "7.6.0" criteria = "safe-to-deploy" [[exemptions.hex]] @@ -485,7 +485,7 @@ version = "1.0.3" criteria = "safe-to-deploy" [[exemptions.hyper]] -version = "1.10.1" +version = "1.11.0" criteria = "safe-to-deploy" [[exemptions.hyper-rustls]] @@ -545,7 +545,7 @@ version = "1.2.2" criteria = "safe-to-deploy" [[exemptions.impl-more]] -version = "0.3.1" +version = "0.3.5" criteria = "safe-to-deploy" [[exemptions.indexmap]] @@ -569,11 +569,15 @@ version = "1.0.18" criteria = "safe-to-deploy" [[exemptions.jiff]] -version = "0.2.32" +version = "0.2.34" +criteria = "safe-to-deploy" + +[[exemptions.jiff-core]] +version = "0.1.0" criteria = "safe-to-deploy" [[exemptions.jiff-static]] -version = "0.2.32" +version = "0.2.34" criteria = "safe-to-deploy" [[exemptions.jobserver]] @@ -593,11 +597,11 @@ version = "1.5.0" criteria = "safe-to-deploy" [[exemptions.left-right]] -version = "0.11.7" +version = "0.11.8" criteria = "safe-to-deploy" [[exemptions.libc]] -version = "0.2.186" +version = "0.2.189" criteria = "safe-to-deploy" [[exemptions.linux-raw-sys]] @@ -833,7 +837,7 @@ version = "0.3.33" criteria = "safe-to-deploy" [[exemptions.portable-atomic]] -version = "1.13.1" +version = "1.14.0" criteria = "safe-to-deploy" [[exemptions.portable-atomic-util]] @@ -853,7 +857,7 @@ version = "0.2.21" criteria = "safe-to-deploy" [[exemptions.proc-macro2]] -version = "1.0.106" +version = "1.0.107" criteria = "safe-to-deploy" [[exemptions.prometheus]] @@ -873,7 +877,7 @@ version = "0.12.6" criteria = "safe-to-deploy" [[exemptions.quote]] -version = "1.0.46" +version = "1.0.47" criteria = "safe-to-deploy" [[exemptions.r-efi]] @@ -973,7 +977,7 @@ version = "0.8.4" criteria = "safe-to-deploy" [[exemptions.rustls-pki-types]] -version = "1.15.0" +version = "1.15.1" criteria = "safe-to-deploy" [[exemptions.rustls-webpki]] @@ -1053,19 +1057,19 @@ version = "0.48.5" criteria = "safe-to-deploy" [[exemptions.serde]] -version = "1.0.228" +version = "1.0.229" criteria = "safe-to-deploy" [[exemptions.serde_core]] -version = "1.0.228" +version = "1.0.229" criteria = "safe-to-deploy" [[exemptions.serde_derive]] -version = "1.0.228" +version = "1.0.229" criteria = "safe-to-deploy" [[exemptions.serde_json]] -version = "1.0.150" +version = "1.0.151" criteria = "safe-to-deploy" [[exemptions.serde_path_to_error]] @@ -1120,6 +1124,10 @@ criteria = "safe-to-deploy" version = "2.0.119" criteria = "safe-to-deploy" +[[exemptions.syn]] +version = "3.0.3" +criteria = "safe-to-deploy" + [[exemptions.sync_wrapper]] version = "1.0.2" criteria = "safe-to-deploy" @@ -1133,11 +1141,11 @@ version = "3.27.0" criteria = "safe-to-deploy" [[exemptions.thiserror]] -version = "2.0.18" +version = "2.0.19" criteria = "safe-to-deploy" [[exemptions.thiserror-impl]] -version = "2.0.18" +version = "2.0.19" criteria = "safe-to-deploy" [[exemptions.thread_local]] @@ -1145,7 +1153,7 @@ version = "1.1.10" criteria = "safe-to-deploy" [[exemptions.time]] -version = "0.3.53" +version = "0.3.54" criteria = "safe-to-deploy" [[exemptions.time-core]] @@ -1153,7 +1161,7 @@ version = "0.1.9" criteria = "safe-to-deploy" [[exemptions.time-macros]] -version = "0.2.31" +version = "0.2.32" criteria = "safe-to-deploy" [[exemptions.tinystr]] @@ -1161,7 +1169,7 @@ version = "0.8.3" criteria = "safe-to-deploy" [[exemptions.tokio]] -version = "1.53.0" +version = "1.53.1" criteria = "safe-to-deploy" [[exemptions.tokio-macros]] @@ -1177,7 +1185,7 @@ version = "0.26.4" criteria = "safe-to-deploy" [[exemptions.tokio-util]] -version = "0.7.18" +version = "0.7.19" criteria = "safe-to-deploy" [[exemptions.tower]] @@ -1229,7 +1237,7 @@ version = "0.2.5" criteria = "safe-to-deploy" [[exemptions.ulid]] -version = "2.0.1" +version = "3.0.0" criteria = "safe-to-deploy" [[exemptions.uname]] @@ -1337,7 +1345,7 @@ version = "1.1.0" criteria = "safe-to-deploy" [[exemptions.webpki-root-certs]] -version = "1.0.8" +version = "1.0.9" criteria = "safe-to-deploy" [[exemptions.winapi]] @@ -1441,11 +1449,11 @@ version = "0.8.2" criteria = "safe-to-deploy" [[exemptions.zerocopy]] -version = "0.8.54" +version = "0.8.55" criteria = "safe-to-deploy" [[exemptions.zerocopy-derive]] -version = "0.8.54" +version = "0.8.55" criteria = "safe-to-deploy" [[exemptions.zerofrom]] diff --git a/utils/apalis-codec/Cargo.toml b/utils/apalis-codec/Cargo.toml index aa71c239..6f2b529f 100644 --- a/utils/apalis-codec/Cargo.toml +++ b/utils/apalis-codec/Cargo.toml @@ -28,7 +28,7 @@ serde = { version = "1.0", features = ["derive"], optional = true } serde_json = { version = "1", optional = true } bincode = { version = "2.0.1", optional = true } rmp-serde = { version = "1.3.1", optional = true } -thiserror = { version = "2.0.0", optional = true } +thiserror = { version = "2.0.19", optional = true } [lints] workspace = true diff --git a/utils/apalis-file-storage/Cargo.toml b/utils/apalis-file-storage/Cargo.toml index 67f081d4..0a40b5b5 100644 --- a/utils/apalis-file-storage/Cargo.toml +++ b/utils/apalis-file-storage/Cargo.toml @@ -17,24 +17,24 @@ categories = ["database", "filesystem", "asynchronous", "data-structures"] [lib] [dependencies] -serde = { version = "1.0.228", features = ["derive"] } +serde = { version = "1.0.229", features = ["derive"] } apalis-core = { path = "../../apalis-core", version = "1.0.0-rc.9", default-features = false, features = [ "sleep", "serde", ] } serde_json = "1" -futures-channel = { version = "0.3.30", features = [ +futures-channel = { version = "0.3.33", features = [ "sink", "std", ], default-features = false } -futures-sink = { version = "0.3.30", default-features = false } -futures-util = { version = "0.3.30", features = [ +futures-sink = { version = "0.3.33", default-features = false } +futures-util = { version = "0.3.33", features = [ "sink", "async-await", "async-await-macro", "std", ], default-features = false } -futures-core = { version = "0.3.30", default-features = false } +futures-core = { version = "0.3.33", default-features = false } apalis-codec = { path = "../apalis-codec", version = "0.1.0-rc.9", default-features = false, features = [ "json", ] } @@ -43,7 +43,7 @@ thiserror = "2" fd-lock = "4.0.4" [dev-dependencies] -tokio = { version = "1.37.0", features = ["full"] } +tokio = { version = "1.53.1", features = ["full"] } apalis-workflow = { path = "../../apalis-workflow" } # For json backend tests [lints] diff --git a/utils/apalis-file-storage/src/lib.rs b/utils/apalis-file-storage/src/lib.rs index 45a749eb..2fb6185a 100644 --- a/utils/apalis-file-storage/src/lib.rs +++ b/utils/apalis-file-storage/src/lib.rs @@ -28,7 +28,7 @@ use crate::error::FileStorageError; use self::util::RawTask; use apalis_core::{ - backend::{Backend, TaskResult, WaitForCompletion, queue::Queue}, + backend::{Backend, TaskResult, WaitForCompletion}, error::BoxDynError, features_table, task::{ @@ -108,7 +108,7 @@ enum PendingChange { FetchById => not_implemented("Allow fetching a task by its ID"), RegisterWorker => not_supported("Allow registering a worker with the backend"), "[`PipeExt`]" => supported("Allow other backends to pipe to this backend", false), - MakeShared => supported("Share the same storage across multiple workers via [`SharedJsonStore`]", false), + BackendFactory => supported("Share the same storage across multiple workers via [`SharedJsonStore`]", false), Workflow => supported("Flexible enough to support workflows", true), WaitForCompletion => supported("Wait for tasks to complete without blocking", true), ResumeById => not_implemented("Resume a task by its ID"), @@ -455,7 +455,7 @@ impl Stream for FileStorage { this.read_cursor += 1; Poll::Ready(Some(Ok((line_id, job)))) } else { - Poll::Ready(None) + Poll::Pending } } } @@ -469,7 +469,7 @@ where type Args = Args; type Id = RandomId; type Error = FileStorageError; - type Connection = MetadataStore; + type Config = PathBuf; type Layer = AcknowledgeLayer; type Codec = JsonCodec; type Compact = Value; @@ -479,8 +479,8 @@ where fn codec(&self) -> &Self::Codec { &self.codec } - fn queue(&self) -> Queue { - std::any::type_name::().into() + fn config(&self) -> &Self::Config { + &self.path } fn poll_ready( &mut self, @@ -499,14 +499,12 @@ where &mut self, cx: &mut Context<'_>, _: &WorkerContext, - ) -> Poll, Self::Error>>> { + ) -> Poll, Self::Error>>> { self.poll_next_unpin(cx).map_ok(|(line_id, mut job)| { job.ctx.insert("line_id", line_id.to_string()).unwrap(); - let mut task = TaskBuilder::new(job.args).with_metadata(job.ctx); - - if let Some(task_id) = job.task_id { - task = task.task_id(task_id); - } + let task = TaskBuilder::new(job.args) + .with_metadata(job.ctx) + .task_id(job.task_id); task.build() }) } @@ -599,7 +597,10 @@ impl Adapter for CsvAdapter { let idempotency_key = line.get("idempotency_key").cloned(); - let task_id = line.get("task_id").and_then(|s| FromStr::from_str(s).ok()); + let task_id = line + .get("task_id") + .and_then(|s| FromStr::from_str(s).ok()) + .unwrap_or_default(); let ctx = line .iter() @@ -621,14 +622,7 @@ impl Adapter for CsvAdapter { fn from_entry(entry: &RawTask) -> Result { let mut line = BTreeMap::new(); - line.insert( - "task_id".to_owned(), - entry - .task_id - .as_ref() - .map(|t| t.to_string()) - .unwrap_or_default(), - ); + line.insert("task_id".to_owned(), entry.task_id.to_string()); let args = util::from_value(Some("args"), &entry.args); @@ -685,7 +679,7 @@ impl Adapter for CsvAdapter { } } -impl Acknowledge for FileStorage +impl Acknowledge for FileStorage where Args: Send + 'static + Debug, Res: Serialize, @@ -698,7 +692,7 @@ where fn ack( &mut self, res: &Result, - ctx: &ExecutionContext, + ctx: &ExecutionContext, ) -> Self::Future { let res = |this: &mut Self| { let val = serde_json::to_value(res.as_ref().map_err(|e| e.to_string()))?; @@ -754,7 +748,7 @@ where let completed_task = { let vault = vault.entries.try_read().ok()?; vault.iter().find_map(|value| { - let task_id = value.task_id.clone()?; + let task_id = value.task_id.clone(); if state.pending_tasks.contains(&task_id) { Some((task_id, value.result.clone()?)) } else { @@ -798,7 +792,7 @@ where .try_read() .unwrap() .iter() - .find(|s| s.task_id.as_ref().unwrap() == &task_id) + .find(|s| s.task_id == task_id) { if value.result.is_none() { results.push(TaskResult { diff --git a/utils/apalis-file-storage/src/shared.rs b/utils/apalis-file-storage/src/shared.rs index 4a5667ab..659b756f 100644 --- a/utils/apalis-file-storage/src/shared.rs +++ b/utils/apalis-file-storage/src/shared.rs @@ -13,7 +13,7 @@ use serde_json::Value; /// # Example /// /// ```rust,no_run -/// # use apalis_core::backend::shared::MakeShared; +/// # use apalis_core::backend::factory::BackendFactory; /// # use apalis_core::task::Task; /// # use apalis_core::worker::context::WorkerContext; /// # use apalis_core::worker::builder::WorkerBuilder; @@ -25,7 +25,7 @@ use serde_json::Value; /// #[tokio::main] /// async fn main() { /// let mut store = SharedJsonStore::new(); -/// let mut int_store = store.make_shared().unwrap(); +/// let mut int_store = store.create().unwrap(); /// int_store.push(42).await.unwrap(); /// /// async fn task( @@ -51,10 +51,10 @@ use std::{fmt::Debug, sync::Arc}; use apalis_core::{ backend::{ + factory::BackendFactory, memory::{MemorySink, MemoryStorage, MemoryStorageError}, - shared::MakeShared, }, - task::{Task, builder::TaskBuilder, metadata::MetadataStore, task_id::RandomId}, + task::{Task, builder::TaskBuilder, task_id::RandomId}, }; use crate::JsonStorage; @@ -86,52 +86,35 @@ impl SharedJsonStore { } } -impl Deserialize<'de> + Unpin + 'static> MakeShared - for SharedJsonStore +impl Deserialize<'de> + Unpin + 'static + Clone> + BackendFactory for SharedJsonStore { - type Backend = MemoryStorage; + type Backend = MemoryStorage; - type Config = String; + type Error = MemoryStorageError; - type MakeError = MemoryStorageError; - - fn make_shared(&mut self) -> Result - where - Self::Config: Default, - { - self.make_shared_with_config(std::any::type_name::().to_owned()) + fn create(&mut self) -> Result { + self.create_with_config(()) } - fn make_shared_with_config( - &mut self, - queue: Self::Config, - ) -> Result { - let (sender, receiver) = self.create_channel::(&queue); + fn create_with_config(&mut self, _: ()) -> Result { + let (sender, receiver) = self.create_channel::(); let sender = MemorySink::new(Arc::new(futures_util::lock::Mutex::new(sender))); Ok(MemoryStorage::new_with(sender, receiver)) } } -type BoxSink = Box< - dyn Sink, Error = MemoryStorageError> - + Send - + Sync - + Unpin - + 'static, ->; +type BoxSink = + Box, Error = MemoryStorageError> + Send + Sync + Unpin + 'static>; impl SharedJsonStore { fn create_channel Deserialize<'de> + Serialize + Send + Unpin>( &self, - queue: &str, - ) -> ( - BoxSink, - BoxStream<'static, Task>, - ) { + ) -> (BoxSink, BoxStream<'static, Task>) { // Create a channel for communication let sender = self.inner.clone(); - let queue_config = queue.to_owned(); + let queue_config = std::any::type_name::(); // Create a wrapped sender that will insert into the in-memory store let wrapped_sender = { @@ -139,12 +122,9 @@ impl SharedJsonStore { sender .sink_map_err(|e| MemoryStorageError::Other(e.into())) - .with_flat_map(move |task: Task| { + .with_flat_map(move |task: Task| { let mut task = task.into_builder(); - task.ctx - .metadata - .insert("queue", queue_config.clone()) - .unwrap(); + task.ctx.metadata.insert("queue", queue_config).unwrap(); let res = task .try_map_args(|s| { @@ -158,7 +138,7 @@ impl SharedJsonStore { // Create a stream that filters by type T let filtered_stream = { - let queue_config = queue.to_owned(); + let queue_config = std::any::type_name::().to_owned(); sender.map(|s| s.unwrap()).filter_map(move |(_, job)| { let queue_config = queue_config.clone(); async move { @@ -167,7 +147,7 @@ impl SharedJsonStore { let args = Args::deserialize(&job.args).ok()?; let task = TaskBuilder::new(args) .with_metadata(job.ctx) - .task_id(job.task_id.unwrap()) + .task_id(job.task_id) .build(); Some(task) } else { @@ -180,10 +160,7 @@ impl SharedJsonStore { // Combine the sender and receiver let sender = Box::new(wrapped_sender) as Box< - dyn Sink, Error = MemoryStorageError> - + Send - + Sync - + Unpin, + dyn Sink, Error = MemoryStorageError> + Send + Sync + Unpin, >; let receiver = filtered_stream.boxed(); @@ -198,7 +175,7 @@ mod tests { use apalis_core::worker::context::WorkerContext; use apalis_core::{ - backend::{TaskSink, shared::MakeShared}, + backend::{TaskSink, factory::BackendFactory}, worker::{builder::WorkerBuilder, ext::event_listener::EventListenerExt}, }; @@ -209,8 +186,8 @@ mod tests { #[tokio::test] async fn basic_shared() { let mut store = SharedJsonStore::new(); - let mut string_store = store.make_shared().unwrap(); - let mut int_store = store.make_shared_with_config("int".into()).unwrap(); + let mut string_store = store.create().unwrap(); + let mut int_store = store.create_with_config(()).unwrap(); for i in 0..ITEMS { string_store.push(format!("ITEM: {i}")).await.unwrap(); int_store.push(i).await.unwrap(); diff --git a/utils/apalis-file-storage/src/sink.rs b/utils/apalis-file-storage/src/sink.rs index bec62531..f659824e 100644 --- a/utils/apalis-file-storage/src/sink.rs +++ b/utils/apalis-file-storage/src/sink.rs @@ -4,7 +4,7 @@ use std::{ task::{Context, Poll}, }; -use apalis_core::task::{Task, metadata::MetadataStore, task_id::RandomId}; +use apalis_core::task::{Task, task_id::RandomId}; use futures_sink::Sink; use serde_json::Value; @@ -12,23 +12,18 @@ use crate::{ Adapter, FileStorage, PendingChange, SyncPolicy, error::FileStorageError, util::RawTask, }; -impl Sink> - for FileStorage -{ +impl Sink> for FileStorage { type Error = FileStorageError; fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } - fn start_send( - self: Pin<&mut Self>, - item: Task, - ) -> Result<(), Self::Error> { + fn start_send(self: Pin<&mut Self>, item: Task) -> Result<(), Self::Error> { let ctx = Arc::try_unwrap(item.ctx).map_err(|_| FileStorageError::WouldBlockLock)?; let idempotency_key = ctx.idempotency_key; let entry = RawTask { - task_id: ctx.task_id, + task_id: ctx.task_id.unwrap_or_default(), args: item.args, ctx: ctx.metadata, result: None, @@ -63,13 +58,11 @@ impl Sink> .try_write() .map_err(|_| FileStorageError::WouldBlockLock)? .push(PendingChange::Append(bytes)); + Ok(()) } - fn poll_flush( - mut self: Pin<&mut Self>, - _cx: &mut Context<'_>, - ) -> Poll> { + fn poll_flush(mut self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { match self.sync_policy.clone() { SyncPolicy::Instant | SyncPolicy::Periodic(_) => self.flush()?, SyncPolicy::Manual => {} diff --git a/utils/apalis-file-storage/src/util.rs b/utils/apalis-file-storage/src/util.rs index d2393f48..d8cbcdca 100644 --- a/utils/apalis-file-storage/src/util.rs +++ b/utils/apalis-file-storage/src/util.rs @@ -9,7 +9,7 @@ use apalis_core::task::{ #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RawTask { - pub(super) task_id: Option>, + pub(super) task_id: TaskId, pub(super) args: serde_json::Value, pub(super) ctx: MetadataStore, pub(super) result: Option,