From 6fed1c3e7dfdda27b8809d6a1fd1e83d260cbf39 Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Mon, 11 Oct 2021 09:58:11 +0800 Subject: [PATCH 1/7] add support for io-uring (#374) Co-authored-by: Rob Ede --- .cargo/config.toml | 20 ++++++++++- .github/workflows/ci.yml | 58 +++++++++++++++++------------- actix-rt/CHANGES.md | 2 ++ actix-rt/Cargo.toml | 4 +++ actix-rt/src/arbiter.rs | 72 ++++++++++++++++++++++++++++++++------ actix-rt/src/lib.rs | 7 ++++ actix-rt/src/runtime.rs | 5 --- actix-rt/src/system.rs | 2 +- actix-rt/tests/tests.rs | 46 ++++++++++++++++++++---- actix-server/CHANGES.md | 2 ++ actix-server/Cargo.toml | 1 + actix-server/src/worker.rs | 16 +++++++-- actix-tls/src/lib.rs | 1 + 13 files changed, 185 insertions(+), 51 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 16d75ced..0e5de486 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,23 @@ [alias] chk = "check --workspace --all-features --tests --examples --bins" lint = "clippy --workspace --all-features --tests --examples --bins -- -Dclippy::todo" -ci-test = "test --workspace --all-features --lib --tests --no-fail-fast -- --nocapture" + ci-doctest = "test --workspace --all-features --doc --no-fail-fast -- --nocapture" + +# just check the library (without dev deps) +ci-check-min = "hack --workspace check --no-default-features" +ci-check-lib = "hack --workspace --feature-powerset --exclude-features io-uring check" +ci-check-lib-linux = "hack --workspace --feature-powerset check" + +# check everything +ci-check = "hack --workspace --feature-powerset --exclude-features io-uring check --tests --examples" +ci-check-linux = "hack --workspace --feature-powerset check --tests --examples" + +# tests avoiding io-uring feature +ci-test = "hack test --workspace --exclude=actix-rt --exclude=actix-server --all-features --lib --tests --no-fail-fast -- --nocapture" +ci-test-rt = " hack --feature-powerset --exclude-features io-uring test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture" +ci-test-server = "hack --feature-powerset --exclude-features io-uring test --package=actix-server --lib --tests --no-fail-fast -- --nocapture" + +# test with io-uring feature +ci-test-rt-linux = " hack --feature-powerset test --package=actix-rt --lib --tests --no-fail-fast -- --nocapture" +ci-test-server-linux = "hack --feature-powerset test --package=actix-server --lib --tests --no-fail-fast -- --nocapture" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0f62910..45841fb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,36 +75,47 @@ jobs: command: install args: cargo-hack - - name: check minimal + - name: check lib + if: > + matrix.target.os != 'ubuntu-latest' + && matrix.target.triple != 'x86_64-pc-windows-gnu' uses: actions-rs/cargo@v1 - with: - command: hack - args: check --workspace --no-default-features - - - name: check minimal + tests + with: { command: ci-check-lib } + - name: check lib + if: matrix.target.os == 'ubuntu-latest' uses: actions-rs/cargo@v1 - with: - command: hack - args: check --workspace --no-default-features --tests --examples - - - name: check default + with: { command: ci-check-lib-linux } + - name: check lib + if: matrix.target.triple == 'x86_64-pc-windows-gnu' uses: actions-rs/cargo@v1 - with: - command: check - args: --workspace --tests --examples - + with: { command: ci-check-min } + - name: check full # TODO: compile OpenSSL and run tests on MinGW - if: matrix.target.triple != 'x86_64-pc-windows-gnu' + if: > + matrix.target.os != 'ubuntu-latest' + && matrix.target.triple != 'x86_64-pc-windows-gnu' uses: actions-rs/cargo@v1 - with: - command: check - args: --workspace --all-features --tests --examples + with: { command: ci-check } + - name: check all + if: matrix.target.os == 'ubuntu-latest' + uses: actions-rs/cargo@v1 + with: { command: ci-check-linux } - name: tests - if: matrix.target.triple != 'x86_64-pc-windows-gnu' - uses: actions-rs/cargo@v1 - with: { command: ci-test } + if: > + matrix.target.os != 'ubuntu-latest' + && matrix.target.triple != 'x86_64-pc-windows-gnu' + run: | + cargo ci-test + cargo ci-test-rt + cargo ci-test-server + - name: tests + if: matrix.target.os == 'ubuntu-latest' + run: | + cargo ci-test + cargo ci-test-rt-linux + cargo ci-test-server-linux - name: Generate coverage file if: > @@ -120,8 +131,7 @@ jobs: && matrix.version == 'stable' && github.ref == 'refs/heads/master' uses: codecov/codecov-action@v1 - with: - file: cobertura.xml + with: { file: cobertura.xml } - name: Clear the cargo caches run: | diff --git a/actix-rt/CHANGES.md b/actix-rt/CHANGES.md index 42879e12..373640d3 100644 --- a/actix-rt/CHANGES.md +++ b/actix-rt/CHANGES.md @@ -1,9 +1,11 @@ # Changes ## Unreleased - 2021-xx-xx +* Add `io-uring` feature for enabling async file I/O on linux. [#374] * The `spawn` method can now resolve with non-unit outputs. [#369] [#369]: https://github.com/actix/actix-net/pull/369 +[#374]: https://github.com/actix/actix-net/pull/374 ## 2.2.0 - 2021-03-29 diff --git a/actix-rt/Cargo.toml b/actix-rt/Cargo.toml index f4a90d2c..b466bb76 100644 --- a/actix-rt/Cargo.toml +++ b/actix-rt/Cargo.toml @@ -21,6 +21,7 @@ path = "src/lib.rs" [features] default = ["macros"] macros = ["actix-macros"] +io-uring = ["tokio-uring"] [dependencies] actix-macros = { version = "0.2.0", optional = true } @@ -28,6 +29,9 @@ actix-macros = { version = "0.2.0", optional = true } futures-core = { version = "0.3", default-features = false } tokio = { version = "1.3", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } +[target.'cfg(target_os = "linux")'.dependencies] +tokio-uring = { version = "0.1", optional = true } + [dev-dependencies] tokio = { version = "1.2", features = ["full"] } hyper = { version = "0.14", default-features = false, features = ["server", "tcp", "http1"] } diff --git a/actix-rt/src/arbiter.rs b/actix-rt/src/arbiter.rs index 9ff1419d..97084f05 100644 --- a/actix-rt/src/arbiter.rs +++ b/actix-rt/src/arbiter.rs @@ -9,12 +9,9 @@ use std::{ }; use futures_core::ready; -use tokio::{sync::mpsc, task::LocalSet}; +use tokio::sync::mpsc; -use crate::{ - runtime::{default_tokio_runtime, Runtime}, - system::{System, SystemCommand}, -}; +use crate::system::{System, SystemCommand}; pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0); @@ -98,16 +95,19 @@ impl Arbiter { /// /// # Panics /// Panics if a [System] is not registered on the current thread. + #[cfg(not(all(target_os = "linux", feature = "io-uring")))] #[allow(clippy::new_without_default)] pub fn new() -> Arbiter { Self::with_tokio_rt(|| { - default_tokio_runtime().expect("Cannot create new Arbiter's Runtime.") + crate::runtime::default_tokio_runtime() + .expect("Cannot create new Arbiter's Runtime.") }) } /// Spawn a new Arbiter using the [Tokio Runtime](tokio-runtime) returned from a closure. /// /// [tokio-runtime]: tokio::runtime::Runtime + #[cfg(not(all(target_os = "linux", feature = "io-uring")))] #[doc(hidden)] pub fn with_tokio_rt(runtime_factory: F) -> Arbiter where @@ -127,7 +127,7 @@ impl Arbiter { .spawn({ let tx = tx.clone(); move || { - let rt = Runtime::from(runtime_factory()); + let rt = crate::runtime::Runtime::from(runtime_factory()); let hnd = ArbiterHandle::new(tx); System::set_current(sys); @@ -159,15 +159,67 @@ impl Arbiter { Arbiter { tx, thread_handle } } - /// Sets up an Arbiter runner in a new System using the provided runtime local task set. - pub(crate) fn in_new_system(local: &LocalSet) -> ArbiterHandle { + /// Spawn a new Arbiter thread and start its event loop with `tokio-uring` runtime. + /// + /// # Panics + /// Panics if a [System] is not registered on the current thread. + #[cfg(all(target_os = "linux", feature = "io-uring"))] + #[allow(clippy::new_without_default)] + pub fn new() -> Arbiter { + let sys = System::current(); + let system_id = sys.id(); + let arb_id = COUNT.fetch_add(1, Ordering::Relaxed); + + let name = format!("actix-rt|system:{}|arbiter:{}", system_id, arb_id); + let (tx, rx) = mpsc::unbounded_channel(); + + let (ready_tx, ready_rx) = std::sync::mpsc::channel::<()>(); + + let thread_handle = thread::Builder::new() + .name(name.clone()) + .spawn({ + let tx = tx.clone(); + move || { + let hnd = ArbiterHandle::new(tx); + + System::set_current(sys); + + HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone())); + + // register arbiter + let _ = System::current() + .tx() + .send(SystemCommand::RegisterArbiter(arb_id, hnd)); + + ready_tx.send(()).unwrap(); + + // run arbiter event processing loop + tokio_uring::start(ArbiterRunner { rx }); + + // deregister arbiter + let _ = System::current() + .tx() + .send(SystemCommand::DeregisterArbiter(arb_id)); + } + }) + .unwrap_or_else(|err| { + panic!("Cannot spawn Arbiter's thread: {:?}. {:?}", &name, err) + }); + + ready_rx.recv().unwrap(); + + Arbiter { tx, thread_handle } + } + + /// Sets up an Arbiter runner in a new System using the environment's local set. + pub(crate) fn in_new_system() -> ArbiterHandle { let (tx, rx) = mpsc::unbounded_channel(); let hnd = ArbiterHandle::new(tx); HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone())); - local.spawn_local(ArbiterRunner { rx }); + crate::spawn(ArbiterRunner { rx }); hnd } diff --git a/actix-rt/src/lib.rs b/actix-rt/src/lib.rs index 95afcac9..e078dd06 100644 --- a/actix-rt/src/lib.rs +++ b/actix-rt/src/lib.rs @@ -32,6 +32,10 @@ //! arbiter.stop(); //! arbiter.join().unwrap(); //! ``` +//! +//! # `io-uring` Support +//! There is experimental support for using io-uring with this crate by enabling the +//! `io-uring` feature. For now, it is semver exempt. #![deny(rust_2018_idioms, nonstandard_style)] #![allow(clippy::type_complexity)] @@ -39,6 +43,9 @@ #![doc(html_logo_url = "https://actix.rs/img/logo.png")] #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] +#[cfg(all(not(target_os = "linux"), feature = "io-uring"))] +compile_error!("io_uring is a linux only feature."); + use std::future::Future; use tokio::task::JoinHandle; diff --git a/actix-rt/src/runtime.rs b/actix-rt/src/runtime.rs index 1adbf6c0..25937003 100644 --- a/actix-rt/src/runtime.rs +++ b/actix-rt/src/runtime.rs @@ -31,11 +31,6 @@ impl Runtime { }) } - /// Reference to local task set. - pub(crate) fn local_set(&self) -> &LocalSet { - &self.local - } - /// Offload a future onto the single-threaded runtime. /// /// The returned join handle can be used to await the future's result. diff --git a/actix-rt/src/system.rs b/actix-rt/src/system.rs index 3bc8a6e3..4f262ede 100644 --- a/actix-rt/src/system.rs +++ b/actix-rt/src/system.rs @@ -54,7 +54,7 @@ impl System { let (sys_tx, sys_rx) = mpsc::unbounded_channel(); let rt = Runtime::from(runtime_factory()); - let sys_arbiter = Arbiter::in_new_system(rt.local_set()); + let sys_arbiter = rt.block_on(async { Arbiter::in_new_system() }); let system = System::construct(sys_tx, sys_arbiter.clone()); system diff --git a/actix-rt/tests/tests.rs b/actix-rt/tests/tests.rs index e66696bf..5fe1e894 100644 --- a/actix-rt/tests/tests.rs +++ b/actix-rt/tests/tests.rs @@ -1,10 +1,6 @@ use std::{ future::Future, - sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::channel, - Arc, - }, + sync::mpsc::channel, thread, time::{Duration, Instant}, }; @@ -221,8 +217,8 @@ fn system_stop_stops_arbiters() { System::current().stop(); sys.run().unwrap(); - // account for slightly slow thread de-spawns (only observed on windows) - thread::sleep(Duration::from_millis(100)); + // account for slightly slow thread de-spawns + thread::sleep(Duration::from_millis(500)); // arbiter should be dead and return false assert!(!Arbiter::current().spawn_fn(|| {})); @@ -231,6 +227,7 @@ fn system_stop_stops_arbiters() { arb.join().unwrap(); } +#[cfg(not(feature = "io-uring"))] #[test] fn new_system_with_tokio() { let (tx, rx) = channel(); @@ -263,8 +260,14 @@ fn new_system_with_tokio() { assert_eq!(rx.recv().unwrap(), 42); } +#[cfg(not(feature = "io-uring"))] #[test] fn new_arbiter_with_tokio() { + use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }; + let _ = System::new(); let arb = Arbiter::with_tokio_rt(|| { @@ -323,3 +326,32 @@ fn spawn_local() { h(actix_rt::spawn(async { 1 })); }) } + +#[cfg(all(target_os = "linux", feature = "io-uring"))] +#[test] +fn tokio_uring_arbiter() { + let system = System::new(); + let (tx, rx) = std::sync::mpsc::channel(); + + Arbiter::new().spawn(async move { + let handle = actix_rt::spawn(async move { + let f = tokio_uring::fs::File::create("test.txt").await.unwrap(); + let buf = b"Hello World!"; + + let (res, _) = f.write_at(&buf[..], 0).await; + assert!(res.is_ok()); + + f.sync_all().await.unwrap(); + f.close().await.unwrap(); + + std::fs::remove_file("test.txt").unwrap(); + }); + + handle.await.unwrap(); + tx.send(true).unwrap(); + }); + + assert!(rx.recv().unwrap()); + + drop(system); +} diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 86cde4f0..69f5b08c 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -3,11 +3,13 @@ ## Unreleased - 2021-xx-xx * Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to this change. [#349] * Remove `ServerBuilder::configure` [#349] +* Add `io-uring` feature for enabling async file I/O on linux. [#374] * Server no long listens to SIGHUP signal. It actually did not take any action when receiving SIGHUP, the only thing SIGHUP did was to stop the Server from receiving any future signal, because the `Signals` future stops on the first signal received [#389] +[#374]: https://github.com/actix/actix-net/pull/374 [#349]: https://github.com/actix/actix-net/pull/349 [#389]: https://github.com/actix/actix-net/pull/389 diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index 58471cf9..89e1d4e2 100755 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -18,6 +18,7 @@ path = "src/lib.rs" [features] default = [] +io-uring = ["actix-rt/io-uring"] [dependencies] actix-rt = { version = "2.0.0", default-features = false } diff --git a/actix-server/src/worker.rs b/actix-server/src/worker.rs index a974522a..21f98027 100644 --- a/actix-server/src/worker.rs +++ b/actix-server/src/worker.rs @@ -280,14 +280,24 @@ impl ServerWorker { let counter_clone = counter.clone(); // every worker runs in it's own arbiter. // use a custom tokio runtime builder to change the settings of runtime. - Arbiter::with_tokio_rt(move || { + #[cfg(all(target_os = "linux", feature = "io-uring"))] + let arbiter = { + // TODO: pass max blocking thread config when tokio-uring enable configuration + // on building runtime. + let _ = config.max_blocking_threads; + Arbiter::new() + }; + + #[cfg(not(all(target_os = "linux", feature = "io-uring")))] + let arbiter = Arbiter::with_tokio_rt(move || { tokio::runtime::Builder::new_current_thread() .enable_all() .max_blocking_threads(config.max_blocking_threads) .build() .unwrap() - }) - .spawn(async move { + }); + + arbiter.spawn(async move { let fut = factories .iter() .enumerate() diff --git a/actix-tls/src/lib.rs b/actix-tls/src/lib.rs index 83e18d58..dbda8834 100644 --- a/actix-tls/src/lib.rs +++ b/actix-tls/src/lib.rs @@ -5,6 +5,7 @@ #![doc(html_favicon_url = "https://actix.rs/favicon.ico")] #[cfg(feature = "openssl")] +#[allow(unused_extern_crates)] extern crate tls_openssl as openssl; #[cfg(feature = "accept")] From b03fe7c5b6c34f2338b75c7ceaae1de5b4b8896b Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 11 Oct 2021 04:20:37 +0100 Subject: [PATCH 2/7] prepare actix-service release v2.0.1 --- actix-service/CHANGES.md | 4 ++++ actix-service/Cargo.toml | 4 ++-- actix-service/README.md | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/actix-service/CHANGES.md b/actix-service/CHANGES.md index a0130dbc..c01fd8dd 100644 --- a/actix-service/CHANGES.md +++ b/actix-service/CHANGES.md @@ -3,6 +3,10 @@ ## Unreleased - 2021-xx-xx +## 2.0.1 - 2021-10-11 +* Documentation fix. + + ## 2.0.0 - 2021-04-16 * Removed pipeline and related structs/functions. [#335] diff --git a/actix-service/Cargo.toml b/actix-service/Cargo.toml index 7865cd86..f30768fb 100644 --- a/actix-service/Cargo.toml +++ b/actix-service/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-service" -version = "2.0.0" +version = "2.0.1" authors = [ "Nikolay Kim ", "Rob Ede ", @@ -8,7 +8,7 @@ authors = [ ] description = "Service trait and combinators for representing asynchronous request/response operations." keywords = ["network", "framework", "async", "futures", "service"] -categories = ["network-programming", "asynchronous"] +categories = ["network-programming", "asynchronous", "no-std"] repository = "https://github.com/actix/actix-net" license = "MIT OR Apache-2.0" edition = "2018" diff --git a/actix-service/README.md b/actix-service/README.md index 913ac199..d9afdb9c 100644 --- a/actix-service/README.md +++ b/actix-service/README.md @@ -3,10 +3,10 @@ > Service trait and combinators for representing asynchronous request/response operations. [![crates.io](https://img.shields.io/crates/v/actix-service?label=latest)](https://crates.io/crates/actix-service) -[![Documentation](https://docs.rs/actix-service/badge.svg?version=2.0.0)](https://docs.rs/actix-service/2.0.0) +[![Documentation](https://docs.rs/actix-service/badge.svg?version=2.0.1)](https://docs.rs/actix-service/2.0.1) [![Version](https://img.shields.io/badge/rustc-1.46+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html) ![License](https://img.shields.io/crates/l/actix-service.svg) -[![Dependency Status](https://deps.rs/crate/actix-service/2.0.0/status.svg)](https://deps.rs/crate/actix-service/2.0.0) +[![Dependency Status](https://deps.rs/crate/actix-service/2.0.1/status.svg)](https://deps.rs/crate/actix-service/2.0.1) ![Download](https://img.shields.io/crates/d/actix-service.svg) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) From 9fa8d7fc5abb98efc7f0e36f9a4a8c5fc87d92f2 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 11 Oct 2021 05:12:57 +0100 Subject: [PATCH 3/7] avoid dependency on older tokios --- .cargo/config.toml | 1 - actix-codec/Cargo.toml | 2 +- actix-rt/Cargo.toml | 7 +++---- actix-server/Cargo.toml | 8 ++++---- local-channel/Cargo.toml | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 0e5de486..03a995c7 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,4 @@ [alias] -chk = "check --workspace --all-features --tests --examples --bins" lint = "clippy --workspace --all-features --tests --examples --bins -- -Dclippy::todo" ci-doctest = "test --workspace --all-features --doc --no-fail-fast -- --nocapture" diff --git a/actix-codec/Cargo.toml b/actix-codec/Cargo.toml index 815f1039..7bf1c941 100644 --- a/actix-codec/Cargo.toml +++ b/actix-codec/Cargo.toml @@ -20,5 +20,5 @@ futures-core = { version = "0.3.7", default-features = false } futures-sink = { version = "0.3.7", default-features = false } log = "0.4" pin-project-lite = "0.2" -tokio = "1" +tokio = "1.5.1" tokio-util = { version = "0.6", features = ["codec", "io"] } diff --git a/actix-rt/Cargo.toml b/actix-rt/Cargo.toml index b466bb76..4b649252 100644 --- a/actix-rt/Cargo.toml +++ b/actix-rt/Cargo.toml @@ -8,8 +8,7 @@ authors = [ description = "Tokio-based single-threaded async runtime for the Actix ecosystem" keywords = ["async", "futures", "io", "runtime"] homepage = "https://actix.rs" -repository = "https://github.com/actix/actix-net" -documentation = "https://docs.rs/actix-rt" +repository = "https://github.com/actix/actix-net.git" categories = ["network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2018" @@ -27,11 +26,11 @@ io-uring = ["tokio-uring"] actix-macros = { version = "0.2.0", optional = true } futures-core = { version = "0.3", default-features = false } -tokio = { version = "1.3", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } +tokio = { version = "1.5.1", features = ["rt", "net", "parking_lot", "signal", "sync", "time"] } [target.'cfg(target_os = "linux")'.dependencies] tokio-uring = { version = "0.1", optional = true } [dev-dependencies] -tokio = { version = "1.2", features = ["full"] } +tokio = { version = "1.5.1", features = ["full"] } hyper = { version = "0.14", default-features = false, features = ["server", "tcp", "http1"] } diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index 89e1d4e2..92d5a25b 100755 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -7,7 +7,7 @@ authors = [ ] description = "General purpose TCP server built for the Actix ecosystem" keywords = ["network", "framework", "async", "futures"] -repository = "https://github.com/actix/actix-net" +repository = "https://github.com/actix/actix-net.git" categories = ["network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2018" @@ -29,13 +29,13 @@ futures-core = { version = "0.3.7", default-features = false, features = ["alloc log = "0.4" mio = { version = "0.7.6", features = ["os-poll", "net"] } num_cpus = "1.13" -tokio = { version = "1.2", features = ["sync"] } +tokio = { version = "1.5.1", features = ["sync"] } [dev-dependencies] actix-codec = "0.4.0-beta.1" actix-rt = "2.0.0" bytes = "1" -env_logger = "0.8" +env_logger = "0.9" futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } -tokio = { version = "1", features = ["io-util"] } +tokio = { version = "1.5.1", features = ["io-util"] } diff --git a/local-channel/Cargo.toml b/local-channel/Cargo.toml index 0ffd3597..1c20b941 100644 --- a/local-channel/Cargo.toml +++ b/local-channel/Cargo.toml @@ -18,4 +18,4 @@ futures-util = { version = "0.3.7", default-features = false } local-waker = "0.1" [dev-dependencies] -tokio = { version = "1", features = ["rt", "macros"] } +tokio = { version = "1.5.1", features = ["rt", "macros"] } From ca435b25750601861777b6bf744b842a6dcb3218 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 11 Oct 2021 05:14:34 +0100 Subject: [PATCH 4/7] prepare actix-server release 2.0.0-beta.6 --- actix-server/CHANGES.md | 20 +++++++++++--------- actix-server/Cargo.toml | 2 +- actix-server/src/builder.rs | 10 +++++++--- actix-server/src/server.rs | 9 ++++++++- actix-server/src/signals.rs | 16 ++++++++++++---- actix-server/src/test_server.rs | 23 +++++++++++------------ actix-server/src/worker.rs | 20 ++++++++++++-------- actix-tls/Cargo.toml | 2 +- 8 files changed, 63 insertions(+), 39 deletions(-) diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 69f5b08c..6b080daf 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -1,13 +1,15 @@ # Changes ## Unreleased - 2021-xx-xx -* Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to this change. [#349] -* Remove `ServerBuilder::configure` [#349] + + +## 2.0.0-beta.6 - 2021-10-11 * Add `io-uring` feature for enabling async file I/O on linux. [#374] -* Server no long listens to SIGHUP signal. - It actually did not take any action when receiving SIGHUP, the only thing SIGHUP did was to stop - the Server from receiving any future signal, because the `Signals` future stops on the first - signal received [#389] +* Server no long listens to `SIGHUP` signal. Previously, the received was not used but did block + subsequent exit signals from working. [#389] +* Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to + this change. [#349] +* Remove `ServerBuilder::configure` [#349] [#374]: https://github.com/actix/actix-net/pull/374 [#349]: https://github.com/actix/actix-net/pull/349 @@ -15,9 +17,9 @@ ## 2.0.0-beta.5 - 2021-04-20 -* Server shutdown would notify all workers to exit regardless if shutdown is graceful. - This would make all worker shutdown immediately in force shutdown case. [#333] - +* Server shutdown notifies all workers to exit regardless if shutdown is graceful. This causes all + workers to shutdown immediately in force shutdown case. [#333] + [#333]: https://github.com/actix/actix-net/pull/333 diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index 92d5a25b..8fd3112b 100755 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-server" -version = "2.0.0-beta.5" +version = "2.0.0-beta.6" authors = [ "Nikolay Kim ", "fakeshadow <24548779@qq.com>", diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index 46a55ef4..871abb5b 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -312,23 +312,25 @@ impl ServerBuilder { // Handle `SIGINT`, `SIGTERM`, `SIGQUIT` signals and stop actix system match sig { Signal::Int => { - info!("SIGINT received, exiting"); + info!("SIGINT received, starting forced shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: false, completion: None, }) } + Signal::Term => { - info!("SIGTERM received, stopping"); + info!("SIGTERM received, starting graceful shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: true, completion: None, }) } + Signal::Quit => { - info!("SIGQUIT received, exiting"); + info!("SIGQUIT received, starting forced shutdown"); self.exit = true; self.handle_cmd(ServerCommand::Stop { graceful: false, @@ -359,12 +361,14 @@ impl ServerBuilder { rt::spawn(async move { if graceful { + // wait for all workers to shut down let _ = join_all(stop).await; } if let Some(tx) = completion { let _ = tx.send(()); } + for tx in notify { let _ = tx.send(()); } diff --git a/actix-server/src/server.rs b/actix-server/src/server.rs index 6b0d0aea..f0dfca0b 100644 --- a/actix-server/src/server.rs +++ b/actix-server/src/server.rs @@ -15,8 +15,8 @@ pub(crate) enum ServerCommand { Pause(oneshot::Sender<()>), Resume(oneshot::Sender<()>), Signal(Signal), - /// Whether to try and shut down gracefully Stop { + /// True if shut down should be graceful. graceful: bool, completion: Option>, }, @@ -24,6 +24,13 @@ pub(crate) enum ServerCommand { Notify(oneshot::Sender<()>), } +/// Server handle. +/// +/// # Shutdown Signals +/// On UNIX systems, `SIGQUIT` will start a graceful shutdown and `SIGTERM` or `SIGINT` will start a +/// forced shutdown. On Windows, a CTRL-C signal will start a forced shutdown. +/// +/// A graceful shutdown will wait for all workers to stop first. #[derive(Debug)] pub struct Server( UnboundedSender, diff --git a/actix-server/src/signals.rs b/actix-server/src/signals.rs index cdd96b9c..c9cdb45e 100644 --- a/actix-server/src/signals.rs +++ b/actix-server/src/signals.rs @@ -4,27 +4,33 @@ use std::task::{Context, Poll}; use crate::server::Server; -/// Different types of process signals +/// Types of process signals. #[allow(dead_code)] #[derive(PartialEq, Clone, Copy, Debug)] pub(crate) enum Signal { - /// SIGINT + /// `SIGINT` Int, - /// SIGTERM + + /// `SIGTERM` Term, - /// SIGQUIT + + /// `SIGQUIT` Quit, } +/// Process signal listener. pub(crate) struct Signals { srv: Server, + #[cfg(not(unix))] signals: futures_core::future::LocalBoxFuture<'static, std::io::Result<()>>, + #[cfg(unix)] signals: Vec<(Signal, actix_rt::signal::unix::Signal)>, } impl Signals { + /// Spawns a signal listening future that is able to send commands to the `Server`. pub(crate) fn start(srv: Server) { #[cfg(not(unix))] { @@ -33,6 +39,7 @@ impl Signals { signals: Box::pin(actix_rt::signal::ctrl_c()), }); } + #[cfg(unix)] { use actix_rt::signal::unix; @@ -76,6 +83,7 @@ impl Future for Signals { } Poll::Pending => Poll::Pending, } + #[cfg(unix)] { for (sig, fut) in self.signals.iter_mut() { diff --git a/actix-server/src/test_server.rs b/actix-server/src/test_server.rs index 0611cf4b..ad6ee8ee 100644 --- a/actix-server/src/test_server.rs +++ b/actix-server/src/test_server.rs @@ -5,13 +5,12 @@ use actix_rt::{net::TcpStream, System}; use crate::{Server, ServerBuilder, ServiceFactory}; -/// The `TestServer` type. +/// A testing server. /// -/// `TestServer` is very simple test server that simplify process of writing -/// integration tests for actix-net applications. +/// `TestServer` is very simple test server that simplify process of writing integration tests for +/// network applications. /// /// # Examples -/// /// ``` /// use actix_service::fn_service; /// use actix_server::TestServer; @@ -39,7 +38,7 @@ pub struct TestServerRuntime { } impl TestServer { - /// Start new server with server builder + /// Start new server with server builder. pub fn start(mut factory: F) -> TestServerRuntime where F: FnMut(ServerBuilder) -> ServerBuilder + Send + 'static, @@ -64,7 +63,7 @@ impl TestServer { } } - /// Start new test server with application factory + /// Start new test server with application factory. pub fn with>(factory: F) -> TestServerRuntime { let (tx, rx) = mpsc::channel(); @@ -99,7 +98,7 @@ impl TestServer { } } - /// Get first available unused local address + /// Get first available unused local address. pub fn unused_addr() -> net::SocketAddr { let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); let socket = mio::net::TcpSocket::new_v4().unwrap(); @@ -111,27 +110,27 @@ impl TestServer { } impl TestServerRuntime { - /// Test server host + /// Test server host. pub fn host(&self) -> &str { &self.host } - /// Test server port + /// Test server port. pub fn port(&self) -> u16 { self.port } - /// Get test server address + /// Get test server address. pub fn addr(&self) -> net::SocketAddr { self.addr } - /// Stop http server + /// Stop server. fn stop(&mut self) { self.system.stop(); } - /// Connect to server, return tokio TcpStream + /// Connect to server, returning a Tokio `TcpStream`. pub fn connect(&self) -> std::io::Result { TcpStream::from_std(net::TcpStream::connect(self.addr)?) } diff --git a/actix-server/src/worker.rs b/actix-server/src/worker.rs index 21f98027..b99b2da2 100644 --- a/actix-server/src/worker.rs +++ b/actix-server/src/worker.rs @@ -429,13 +429,15 @@ struct Restart { fut: LocalBoxFuture<'static, Result<(usize, BoxedServerService), ()>>, } -// Shutdown keep states necessary for server shutdown: -// Sleep for interval check the shutdown progress. -// Instant for the start time of shutdown. -// Sender for send back the shutdown outcome(force/grace) to StopCommand caller. +/// State necessary for server shutdown. struct Shutdown { + // Interval for checking the shutdown progress. timer: Pin>, + + /// Start time of shutdown. start_from: Instant, + + /// Notify of the shutdown outcome (force/grace) to stop caller. tx: oneshot::Sender, } @@ -521,23 +523,25 @@ impl Future for ServerWorker { self.poll(cx) } WorkerState::Shutdown(ref mut shutdown) => { - // Wait for 1 second. + // wait for 1 second ready!(shutdown.timer.as_mut().poll(cx)); if this.counter.total() == 0 { - // Graceful shutdown. + // graceful shutdown if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) { let _ = shutdown.tx.send(true); } + Poll::Ready(()) } else if shutdown.start_from.elapsed() >= this.shutdown_timeout { - // Timeout forceful shutdown. + // timeout forceful shutdown if let WorkerState::Shutdown(shutdown) = mem::take(&mut this.state) { let _ = shutdown.tx.send(false); } + Poll::Ready(()) } else { - // Reset timer and wait for 1 second. + // reset timer and wait for 1 second let time = Instant::now() + Duration::from_secs(1); shutdown.timer.as_mut().reset(time); shutdown.timer.as_mut().poll(cx) diff --git a/actix-tls/Cargo.toml b/actix-tls/Cargo.toml index 9fa260c7..00082278 100755 --- a/actix-tls/Cargo.toml +++ b/actix-tls/Cargo.toml @@ -64,7 +64,7 @@ tokio-native-tls = { version = "0.3", optional = true } [dev-dependencies] actix-rt = "2.2.0" -actix-server = "2.0.0-beta.5" +actix-server = "2.0.0-beta.6" bytes = "1" env_logger = "0.8" futures-util = { version = "0.3.7", default-features = false, features = ["sink"] } From 5c555a9408c9e6e34aa9319f747a85e2f06c4751 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 11 Oct 2021 22:55:23 +0100 Subject: [PATCH 5/7] prepare actix-rt release 2.3.0 --- actix-rt/CHANGES.md | 5 ++++- actix-rt/Cargo.toml | 2 +- actix-rt/README.md | 4 ++-- actix-server/CHANGES.md | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/actix-rt/CHANGES.md b/actix-rt/CHANGES.md index 373640d3..642cf27a 100644 --- a/actix-rt/CHANGES.md +++ b/actix-rt/CHANGES.md @@ -1,8 +1,11 @@ # Changes ## Unreleased - 2021-xx-xx -* Add `io-uring` feature for enabling async file I/O on linux. [#374] + + +## 2.3.0 - 2021-10-11 * The `spawn` method can now resolve with non-unit outputs. [#369] +* Add experimental (semver-exempt) `io-uring` feature for enabling async file I/O on linux. [#374] [#369]: https://github.com/actix/actix-net/pull/369 [#374]: https://github.com/actix/actix-net/pull/374 diff --git a/actix-rt/Cargo.toml b/actix-rt/Cargo.toml index 4b649252..942d54aa 100644 --- a/actix-rt/Cargo.toml +++ b/actix-rt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "actix-rt" -version = "2.2.0" +version = "2.3.0" authors = [ "Nikolay Kim ", "Rob Ede ", diff --git a/actix-rt/README.md b/actix-rt/README.md index 4ad75f09..eb1d1b6f 100644 --- a/actix-rt/README.md +++ b/actix-rt/README.md @@ -3,11 +3,11 @@ > Tokio-based single-threaded async runtime for the Actix ecosystem. [![crates.io](https://img.shields.io/crates/v/actix-rt?label=latest)](https://crates.io/crates/actix-rt) -[![Documentation](https://docs.rs/actix-rt/badge.svg?version=2.2.0)](https://docs.rs/actix-rt/2.2.0) +[![Documentation](https://docs.rs/actix-rt/badge.svg?version=2.3.0)](https://docs.rs/actix-rt/2.3.0) [![Version](https://img.shields.io/badge/rustc-1.46+-ab6000.svg)](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-rt.svg)
-[![dependency status](https://deps.rs/crate/actix-rt/2.2.0/status.svg)](https://deps.rs/crate/actix-rt/2.2.0) +[![dependency status](https://deps.rs/crate/actix-rt/2.3.0/status.svg)](https://deps.rs/crate/actix-rt/2.3.0) ![Download](https://img.shields.io/crates/d/actix-rt.svg) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/WghFtEH6Hb) diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 6b080daf..54096eca 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -4,7 +4,7 @@ ## 2.0.0-beta.6 - 2021-10-11 -* Add `io-uring` feature for enabling async file I/O on linux. [#374] +* Add experimental (semver-exempt) `io-uring` feature for enabling async file I/O on linux. [#374] * Server no long listens to `SIGHUP` signal. Previously, the received was not used but did block subsequent exit signals from working. [#389] * Remove `config` module. `ServiceConfig`, `ServiceRuntime` public types are removed due to From 4ff8a2cf68d935fb2f33ca354899c5f3ac2f60fe Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 14 Oct 2021 10:54:39 +0100 Subject: [PATCH 6/7] make runtime macros more IDE friendly (#391) --- actix-macros/CHANGES.md | 4 ++ actix-macros/src/lib.rs | 68 +++++++++++++++++-- actix-macros/tests/trybuild.rs | 3 + .../tests/trybuild/test-04-system-path.rs | 10 +++ .../trybuild/test-05-system-expect-path.rs | 4 ++ .../test-05-system-expect-path.stderr | 5 ++ .../tests/trybuild/test-06-unknown-attr.rs | 7 ++ .../trybuild/test-06-unknown-attr.stderr | 11 +++ bytestring/Cargo.toml | 3 +- 9 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 actix-macros/tests/trybuild/test-04-system-path.rs create mode 100644 actix-macros/tests/trybuild/test-05-system-expect-path.rs create mode 100644 actix-macros/tests/trybuild/test-05-system-expect-path.stderr create mode 100644 actix-macros/tests/trybuild/test-06-unknown-attr.rs create mode 100644 actix-macros/tests/trybuild/test-06-unknown-attr.stderr diff --git a/actix-macros/CHANGES.md b/actix-macros/CHANGES.md index 8d7037cf..31f64207 100644 --- a/actix-macros/CHANGES.md +++ b/actix-macros/CHANGES.md @@ -1,6 +1,10 @@ # Changes ## Unreleased - 2021-xx-xx +* Improve error recovery potential when macro input is invalid. [#391] +* Allow custom `System`s on test macro. [#391] + +[#391]: https://github.com/actix/actix-net/pull/391 ## 0.2.1 - 2021-02-02 diff --git a/actix-macros/src/lib.rs b/actix-macros/src/lib.rs index d8aa5f77..4be79178 100644 --- a/actix-macros/src/lib.rs +++ b/actix-macros/src/lib.rs @@ -28,7 +28,12 @@ use quote::quote; #[proc_macro_attribute] #[cfg(not(test))] // Work around for rust-lang/rust#62127 pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { - let mut input = syn::parse_macro_input!(item as syn::ItemFn); + let mut input = match syn::parse::(item.clone()) { + Ok(input) => input, + // on parse err, make IDEs happy; see fn docs + Err(err) => return input_and_compile_error(item, err), + }; + let args = syn::parse_macro_input!(args as syn::AttributeArgs); let attrs = &input.attrs; @@ -101,8 +106,15 @@ pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { /// } /// ``` #[proc_macro_attribute] -pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { - let mut input = syn::parse_macro_input!(item as syn::ItemFn); +pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { + let mut input = match syn::parse::(item.clone()) { + Ok(input) => input, + // on parse err, make IDEs happy; see fn docs + Err(err) => return input_and_compile_error(item, err), + }; + + let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let attrs = &input.attrs; let vis = &input.vis; let sig = &mut input.sig; @@ -132,13 +144,59 @@ pub fn test(_: TokenStream, item: TokenStream) -> TokenStream { quote!(#[test]) }; + let mut system = syn::parse_str::("::actix_rt::System").unwrap(); + + for arg in &args { + match arg { + syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue { + lit: syn::Lit::Str(lit), + path, + .. + })) => match path + .get_ident() + .map(|i| i.to_string().to_lowercase()) + .as_deref() + { + Some("system") => match lit.parse() { + Ok(path) => system = path, + Err(_) => { + return syn::Error::new_spanned(lit, "Expected path") + .to_compile_error() + .into(); + } + }, + _ => { + return syn::Error::new_spanned(arg, "Unknown attribute specified") + .to_compile_error() + .into(); + } + }, + _ => { + return syn::Error::new_spanned(arg, "Unknown attribute specified") + .to_compile_error() + .into(); + } + } + } + (quote! { #missing_test_attr #(#attrs)* #vis #sig { - actix_rt::System::new() - .block_on(async { #body }) + <#system>::new().block_on(async { #body }) } }) .into() } + +/// Converts the error to a token stream and appends it to the original input. +/// +/// Returning the original input in addition to the error is good for IDEs which can gracefully +/// recover and show more precise errors within the macro body. +/// +/// See for more info. +fn input_and_compile_error(mut item: TokenStream, err: syn::Error) -> TokenStream { + let compile_err = TokenStream::from(err.to_compile_error()); + item.extend(compile_err); + return item; +} diff --git a/actix-macros/tests/trybuild.rs b/actix-macros/tests/trybuild.rs index 410d9499..c7f4a5ca 100644 --- a/actix-macros/tests/trybuild.rs +++ b/actix-macros/tests/trybuild.rs @@ -11,4 +11,7 @@ fn compile_macros() { t.pass("tests/trybuild/test-01-basic.rs"); t.pass("tests/trybuild/test-02-keep-attrs.rs"); t.compile_fail("tests/trybuild/test-03-only-async.rs"); + t.pass("tests/trybuild/test-04-system-path.rs"); + t.compile_fail("tests/trybuild/test-05-system-expect-path.rs"); + t.compile_fail("tests/trybuild/test-06-unknown-attr.rs"); } diff --git a/actix-macros/tests/trybuild/test-04-system-path.rs b/actix-macros/tests/trybuild/test-04-system-path.rs new file mode 100644 index 00000000..6d0f9951 --- /dev/null +++ b/actix-macros/tests/trybuild/test-04-system-path.rs @@ -0,0 +1,10 @@ +mod system { + pub use actix_rt::System as MySystem; +} + +#[actix_rt::test(system = "system::MySystem")] +async fn my_test() { + futures_util::future::ready(()).await +} + +fn main() {} diff --git a/actix-macros/tests/trybuild/test-05-system-expect-path.rs b/actix-macros/tests/trybuild/test-05-system-expect-path.rs new file mode 100644 index 00000000..fda3502b --- /dev/null +++ b/actix-macros/tests/trybuild/test-05-system-expect-path.rs @@ -0,0 +1,4 @@ +#[actix_rt::test(system = "!@#*&")] +async fn my_test() {} + +fn main() {} diff --git a/actix-macros/tests/trybuild/test-05-system-expect-path.stderr b/actix-macros/tests/trybuild/test-05-system-expect-path.stderr new file mode 100644 index 00000000..5eab3cf5 --- /dev/null +++ b/actix-macros/tests/trybuild/test-05-system-expect-path.stderr @@ -0,0 +1,5 @@ +error: Expected path + --> $DIR/test-05-system-expect-path.rs:1:27 + | +1 | #[actix_rt::test(system = "!@#*&")] + | ^^^^^^^ diff --git a/actix-macros/tests/trybuild/test-06-unknown-attr.rs b/actix-macros/tests/trybuild/test-06-unknown-attr.rs new file mode 100644 index 00000000..5d0c20c1 --- /dev/null +++ b/actix-macros/tests/trybuild/test-06-unknown-attr.rs @@ -0,0 +1,7 @@ +#[actix_rt::test(foo = "bar")] +async fn my_test_1() {} + +#[actix_rt::test(bar::baz)] +async fn my_test_2() {} + +fn main() {} diff --git a/actix-macros/tests/trybuild/test-06-unknown-attr.stderr b/actix-macros/tests/trybuild/test-06-unknown-attr.stderr new file mode 100644 index 00000000..f6896ddc --- /dev/null +++ b/actix-macros/tests/trybuild/test-06-unknown-attr.stderr @@ -0,0 +1,11 @@ +error: Unknown attribute specified + --> $DIR/test-06-unknown-attr.rs:1:18 + | +1 | #[actix_rt::test(foo = "bar")] + | ^^^^^^^^^^^ + +error: Unknown attribute specified + --> $DIR/test-06-unknown-attr.rs:4:18 + | +4 | #[actix_rt::test(bar::baz)] + | ^^^^^^^^ diff --git a/bytestring/Cargo.toml b/bytestring/Cargo.toml index 3dbf07b7..34237ce9 100644 --- a/bytestring/Cargo.toml +++ b/bytestring/Cargo.toml @@ -24,4 +24,5 @@ serde = { version = "1.0", optional = true } [dev-dependencies] serde_json = "1.0" -ahash = { version = "0.7", default-features = false } +# TODO: remove when ahash MSRV is restored +ahash = { version = "=0.7.4", default-features = false } From 00775884f801f6fde40967b7243fa82a69125790 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Thu, 14 Oct 2021 11:08:02 +0100 Subject: [PATCH 7/7] prepare actix-macros release 0.2.2 --- actix-macros/CHANGES.md | 3 +++ actix-macros/Cargo.toml | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/actix-macros/CHANGES.md b/actix-macros/CHANGES.md index 31f64207..0509eb35 100644 --- a/actix-macros/CHANGES.md +++ b/actix-macros/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2021-xx-xx + + +## 0.2.2 - 2021-10-14 * Improve error recovery potential when macro input is invalid. [#391] * Allow custom `System`s on test macro. [#391] diff --git a/actix-macros/Cargo.toml b/actix-macros/Cargo.toml index fd5737f8..ea1b51d0 100644 --- a/actix-macros/Cargo.toml +++ b/actix-macros/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "actix-macros" -version = "0.2.1" +version = "0.2.2" authors = [ "Nikolay Kim ", "Ibraheem Ahmed ", ] description = "Macros for Actix system and runtime" -repository = "https://github.com/actix/actix-net" +repository = "https://github.com/actix/actix-net.git" categories = ["network-programming", "asynchronous"] license = "MIT OR Apache-2.0" edition = "2018"