Compare commits

..

No commits in common. "064da0e3ffbfc2be674c8aa157a489459a749d53" and "d61b33928debf441d387d2d802dd5707542e7133" have entirely different histories.

19 changed files with 322 additions and 507 deletions

View File

@ -1,8 +0,0 @@
version: "0.2"
words:
- actix
- addrs
- mptcp
- nonblocking
- oneshot
- rustup

View File

@ -8,4 +8,3 @@ updates:
directory: / directory: /
schedule: schedule:
interval: weekly interval: weekly
versioning-strategy: lockfile-only

View File

@ -59,12 +59,12 @@ jobs:
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
- name: Install Rust (${{ matrix.version }}) - name: Install Rust (${{ matrix.version }})
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: ${{ matrix.version }} toolchain: ${{ matrix.version }}
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean - name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
@ -116,12 +116,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust (nightly) - name: Install Rust (nightly)
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: nightly toolchain: nightly
- name: Install cargo-hack & cargo-minimal-versions - name: Install cargo-hack & cargo-minimal-versions
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: cargo-hack,cargo-minimal-versions tool: cargo-hack,cargo-minimal-versions

View File

@ -68,12 +68,12 @@ jobs:
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
- name: Install Rust (${{ matrix.version.name }}) - name: Install Rust (${{ matrix.version.name }})
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: ${{ matrix.version.version }} toolchain: ${{ matrix.version.version }}
- name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean - name: Install just, cargo-hack, cargo-nextest, cargo-ci-cache-clean
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean tool: just,cargo-hack,cargo-nextest,cargo-ci-cache-clean
@ -120,12 +120,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust (nightly) - name: Install Rust (nightly)
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: nightly toolchain: nightly
- name: Install just - name: Install just
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: just tool: just

View File

@ -18,12 +18,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust - name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
components: llvm-tools-preview components: llvm-tools-preview
- name: Install cargo-llvm-cov - name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: cargo-llvm-cov tool: cargo-llvm-cov
@ -31,7 +31,7 @@ jobs:
run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json run: cargo llvm-cov --workspace --all-features --codecov --output-path codecov.json
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v5.4.2 uses: codecov/codecov-action@v5.4.0
with: with:
files: codecov.json files: codecov.json
fail_ci_if_error: true fail_ci_if_error: true

View File

@ -18,7 +18,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: nightly toolchain: nightly
components: rustfmt components: rustfmt
@ -35,7 +35,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: { components: clippy } with: { components: clippy }
- uses: giraffate/clippy-action@v1.0.1 - uses: giraffate/clippy-action@v1.0.1
@ -51,12 +51,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust (${{ vars.RUST_VERSION_EXTERNAL_TYPES }}) - name: Install Rust (${{ vars.RUST_VERSION_EXTERNAL_TYPES }})
uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 uses: actions-rust-lang/setup-rust-toolchain@v1.11.0
with: with:
toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }} toolchain: ${{ vars.RUST_VERSION_EXTERNAL_TYPES }}
- name: Install just - name: Install just
uses: taiki-e/install-action@v2.50.10 uses: taiki-e/install-action@v2.49.45
with: with:
tool: just tool: just

519
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -187,7 +187,10 @@ impl SystemRunner {
match exit_code { match exit_code {
0 => Ok(()), 0 => Ok(()),
nonzero => Err(io::Error::other(format!("Non-zero exit code: {}", nonzero))), nonzero => Err(io::Error::new(
io::ErrorKind::Other,
format!("Non-zero exit code: {}", nonzero),
)),
} }
} }
@ -196,7 +199,8 @@ impl SystemRunner {
let SystemRunner { rt, stop_rx, .. } = self; let SystemRunner { rt, stop_rx, .. } = self;
// run loop // run loop
rt.block_on(stop_rx).map_err(io::Error::other) rt.block_on(stop_rx)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
} }
/// Retrieves a reference to the underlying [Actix runtime](crate::Runtime) associated with this /// Retrieves a reference to the underlying [Actix runtime](crate::Runtime) associated with this

View File

@ -2,9 +2,6 @@
## Unreleased ## Unreleased
## 2.6.0
- Add `ServerBuilder::shutdown_signal()` method.
- Minimum supported Rust version (MSRV) is now 1.74. - Minimum supported Rust version (MSRV) is now 1.74.
## 2.5.1 ## 2.5.1

View File

@ -1,6 +1,6 @@
[package] [package]
name = "actix-server" name = "actix-server"
version = "2.6.0" version = "2.5.1"
authors = [ authors = [
"Nikolay Kim <fafhrd91@gmail.com>", "Nikolay Kim <fafhrd91@gmail.com>",
"Rob Ede <robjtede@icloud.com>", "Rob Ede <robjtede@icloud.com>",
@ -44,10 +44,7 @@ actix-rt = "2.8"
bytes = "1" bytes = "1"
futures-util = { version = "0.3.17", default-features = false, features = ["sink", "async-await-macro"] } futures-util = { version = "0.3.17", default-features = false, features = ["sink", "async-await-macro"] }
pretty_env_logger = "0.5" pretty_env_logger = "0.5"
static_assertions = "1" tokio = { version = "1.44.2", features = ["io-util", "rt-multi-thread", "macros", "fs"] }
tokio = { version = "1.44.2", features = ["io-util", "rt-multi-thread", "macros", "fs", "time"] }
tokio-util = "0.7"
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
[lints] [lints]
workspace = true workspace = true

View File

@ -5,11 +5,11 @@
<!-- prettier-ignore-start --> <!-- prettier-ignore-start -->
[![crates.io](https://img.shields.io/crates/v/actix-server?label=latest)](https://crates.io/crates/actix-server) [![crates.io](https://img.shields.io/crates/v/actix-server?label=latest)](https://crates.io/crates/actix-server)
[![Documentation](https://docs.rs/actix-server/badge.svg?version=2.6.0)](https://docs.rs/actix-server/2.6.0) [![Documentation](https://docs.rs/actix-server/badge.svg?version=2.5.1)](https://docs.rs/actix-server/2.5.1)
[![Version](https://img.shields.io/badge/rustc-1.52+-ab6000.svg)](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html) [![Version](https://img.shields.io/badge/rustc-1.52+-ab6000.svg)](https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html)
![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-server.svg) ![MIT or Apache 2.0 licensed](https://img.shields.io/crates/l/actix-server.svg)
<br /> <br />
[![Dependency Status](https://deps.rs/crate/actix-server/2.6.0/status.svg)](https://deps.rs/crate/actix-server/2.6.0) [![Dependency Status](https://deps.rs/crate/actix-server/2.5.1/status.svg)](https://deps.rs/crate/actix-server/2.5.1)
![Download](https://img.shields.io/crates/d/actix-server.svg) ![Download](https://img.shields.io/crates/d/actix-server.svg)
[![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x) [![Chat on Discord](https://img.shields.io/discord/771444961383153695?label=chat&logo=discord)](https://discord.gg/NWpN5mmg3x)

View File

@ -1,51 +0,0 @@
//! Demonstrates use of the `ServerBuilder::shutdown_signal` method using `tokio-util`s
//! `CancellationToken` helper using a nonsensical timer. In practice, this cancellation token would
//! be wired throughout your application and typically triggered by OS signals elsewhere.
use std::{io, time::Duration};
use actix_rt::net::TcpStream;
use actix_server::Server;
use actix_service::fn_service;
use tokio_util::sync::CancellationToken;
use tracing::level_filters::LevelFilter;
use tracing_subscriber::{prelude::*, EnvFilter};
async fn run(stop_signal: CancellationToken) -> io::Result<()> {
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy(),
)
.init();
let addr = ("127.0.0.1", 8080);
tracing::info!("starting server on port: {}", &addr.0);
Server::build()
.bind("shutdown-signal", addr, || {
fn_service(|_stream: TcpStream| async { Ok::<_, io::Error>(()) })
})?
.shutdown_signal(stop_signal.cancelled_owned())
.workers(2)
.run()
.await
}
#[tokio::main]
async fn main() -> io::Result<()> {
let stop_signal = CancellationToken::new();
tokio::spawn({
let stop_signal = stop_signal.clone();
async move {
tokio::time::sleep(Duration::from_secs(10)).await;
stop_signal.cancel();
}
});
run(stop_signal).await?;
Ok(())
}

View File

@ -76,7 +76,7 @@ impl Accept {
let accept_handle = thread::Builder::new() let accept_handle = thread::Builder::new()
.name("actix-server acceptor".to_owned()) .name("actix-server acceptor".to_owned())
.spawn(move || accept.poll_with(&mut sockets)) .spawn(move || accept.poll_with(&mut sockets))
.map_err(io::Error::other)?; .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
Ok((waker_queue, handles_server, accept_handle)) Ok((waker_queue, handles_server, accept_handle))
} }

View File

@ -1,7 +1,6 @@
use std::{future::Future, io, num::NonZeroUsize, time::Duration}; use std::{io, num::NonZeroUsize, time::Duration};
use actix_rt::net::TcpStream; use actix_rt::net::TcpStream;
use futures_core::future::BoxFuture;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use crate::{ use crate::{
@ -40,7 +39,6 @@ pub struct ServerBuilder {
pub(crate) mptcp: MpTcp, pub(crate) mptcp: MpTcp,
pub(crate) exit: bool, pub(crate) exit: bool,
pub(crate) listen_os_signals: bool, pub(crate) listen_os_signals: bool,
pub(crate) shutdown_signal: Option<BoxFuture<'static, ()>>,
pub(crate) cmd_tx: UnboundedSender<ServerCommand>, pub(crate) cmd_tx: UnboundedSender<ServerCommand>,
pub(crate) cmd_rx: UnboundedReceiver<ServerCommand>, pub(crate) cmd_rx: UnboundedReceiver<ServerCommand>,
pub(crate) worker_config: ServerWorkerConfig, pub(crate) worker_config: ServerWorkerConfig,
@ -66,7 +64,6 @@ impl ServerBuilder {
mptcp: MpTcp::Disabled, mptcp: MpTcp::Disabled,
exit: false, exit: false,
listen_os_signals: true, listen_os_signals: true,
shutdown_signal: None,
cmd_tx, cmd_tx,
cmd_rx, cmd_rx,
worker_config: ServerWorkerConfig::default(), worker_config: ServerWorkerConfig::default(),
@ -173,41 +170,6 @@ impl ServerBuilder {
self self
} }
/// Specify shutdown signal from a future.
///
/// Using this method will prevent OS signal handlers being set up.
///
/// Typically, a `CancellationToken` will be used, but any future _can_ be.
///
/// # Examples
///
/// ```
/// # use std::io;
/// # use tokio::net::TcpStream;
/// # use actix_server::Server;
/// # async fn run() -> io::Result<()> {
/// use actix_service::fn_service;
/// use tokio_util::sync::CancellationToken;
///
/// let stop_signal = CancellationToken::new();
///
/// Server::build()
/// .bind("shutdown-signal", "127.0.0.1:12345", || {
/// fn_service(|_stream: TcpStream| async { Ok::<_, io::Error>(()) })
/// })?
/// .shutdown_signal(stop_signal.cancelled_owned())
/// .run()
/// .await
/// # }
/// ```
pub fn shutdown_signal<Fut>(mut self, shutdown_signal: Fut) -> Self
where
Fut: Future<Output = ()> + Send + 'static,
{
self.shutdown_signal = Some(Box::pin(shutdown_signal));
self
}
/// Timeout for graceful workers shutdown in seconds. /// Timeout for graceful workers shutdown in seconds.
/// ///
/// After receiving a stop signal, workers have this much time to finish serving requests. /// After receiving a stop signal, workers have this much time to finish serving requests.
@ -408,6 +370,9 @@ pub(super) fn bind_addr<S: ToSocketAddrs>(
} else if let Some(err) = opt_err.take() { } else if let Some(err) = opt_err.take() {
Err(err) Err(err)
} else { } else {
Err(io::Error::other("Can not bind to address.")) Err(io::Error::new(
io::ErrorKind::Other,
"Can not bind to address.",
))
} }
} }

View File

@ -18,7 +18,7 @@ use crate::{
builder::ServerBuilder, builder::ServerBuilder,
join_all::join_all, join_all::join_all,
service::InternalServiceFactory, service::InternalServiceFactory,
signals::{OsSignals, SignalKind, StopSignal}, signals::{SignalKind, Signals},
waker_queue::{WakerInterest, WakerQueue}, waker_queue::{WakerInterest, WakerQueue},
worker::{ServerWorker, ServerWorkerConfig, WorkerHandleServer}, worker::{ServerWorker, ServerWorkerConfig, WorkerHandleServer},
ServerHandle, ServerHandle,
@ -210,12 +210,7 @@ impl ServerInner {
let (waker_queue, worker_handles, accept_handle) = Accept::start(sockets, &builder)?; let (waker_queue, worker_handles, accept_handle) = Accept::start(sockets, &builder)?;
let mux = ServerEventMultiplexer { let mux = ServerEventMultiplexer {
signal_fut: builder.shutdown_signal.map(StopSignal::Cancel).or_else(|| { signal_fut: (builder.listen_os_signals).then(Signals::new),
builder
.listen_os_signals
.then(OsSignals::new)
.map(StopSignal::Os)
}),
cmd_rx: builder.cmd_rx, cmd_rx: builder.cmd_rx,
}; };
@ -320,16 +315,7 @@ impl ServerInner {
fn map_signal(signal: SignalKind) -> ServerCommand { fn map_signal(signal: SignalKind) -> ServerCommand {
match signal { match signal {
SignalKind::Cancel => { SignalKind::Int => {
info!("Cancellation token/channel received; starting graceful shutdown");
ServerCommand::Stop {
graceful: true,
completion: None,
force_system_stop: true,
}
}
SignalKind::OsInt => {
info!("SIGINT received; starting forced shutdown"); info!("SIGINT received; starting forced shutdown");
ServerCommand::Stop { ServerCommand::Stop {
graceful: false, graceful: false,
@ -338,7 +324,7 @@ impl ServerInner {
} }
} }
SignalKind::OsTerm => { SignalKind::Term => {
info!("SIGTERM received; starting graceful shutdown"); info!("SIGTERM received; starting graceful shutdown");
ServerCommand::Stop { ServerCommand::Stop {
graceful: true, graceful: true,
@ -347,7 +333,7 @@ impl ServerInner {
} }
} }
SignalKind::OsQuit => { SignalKind::Quit => {
info!("SIGQUIT received; starting forced shutdown"); info!("SIGQUIT received; starting forced shutdown");
ServerCommand::Stop { ServerCommand::Stop {
graceful: false, graceful: false,
@ -361,7 +347,7 @@ impl ServerInner {
struct ServerEventMultiplexer { struct ServerEventMultiplexer {
cmd_rx: UnboundedReceiver<ServerCommand>, cmd_rx: UnboundedReceiver<ServerCommand>,
signal_fut: Option<StopSignal>, signal_fut: Option<Signals>,
} }
impl Stream for ServerEventMultiplexer { impl Stream for ServerEventMultiplexer {

View File

@ -1,11 +1,10 @@
use std::{ use std::{
fmt, fmt,
future::Future, future::Future,
pin::{pin, Pin}, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
use futures_core::future::BoxFuture;
use tracing::trace; use tracing::trace;
/// Types of process signals. /// Types of process signals.
@ -13,51 +12,28 @@ use tracing::trace;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
#[allow(dead_code)] // variants are never constructed on non-unix #[allow(dead_code)] // variants are never constructed on non-unix
pub(crate) enum SignalKind { pub(crate) enum SignalKind {
/// Cancellation token or channel. /// `SIGINT`
Cancel, Int,
/// OS `SIGINT`. /// `SIGTERM`
OsInt, Term,
/// OS `SIGTERM`. /// `SIGQUIT`
OsTerm, Quit,
/// OS `SIGQUIT`.
OsQuit,
} }
impl fmt::Display for SignalKind { impl fmt::Display for SignalKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self { f.write_str(match self {
SignalKind::Cancel => "Cancellation token or channel", SignalKind::Int => "SIGINT",
SignalKind::OsInt => "SIGINT", SignalKind::Term => "SIGTERM",
SignalKind::OsTerm => "SIGTERM", SignalKind::Quit => "SIGQUIT",
SignalKind::OsQuit => "SIGQUIT",
}) })
} }
} }
pub(crate) enum StopSignal {
/// OS signal handling is configured.
Os(OsSignals),
/// Cancellation token or channel.
Cancel(BoxFuture<'static, ()>),
}
impl Future for StopSignal {
type Output = SignalKind;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.get_mut() {
StopSignal::Os(os_signals) => pin!(os_signals).poll(cx),
StopSignal::Cancel(cancel) => pin!(cancel).poll(cx).map(|()| SignalKind::Cancel),
}
}
}
/// Process signal listener. /// Process signal listener.
pub(crate) struct OsSignals { pub(crate) struct Signals {
#[cfg(not(unix))] #[cfg(not(unix))]
signals: futures_core::future::BoxFuture<'static, std::io::Result<()>>, signals: futures_core::future::BoxFuture<'static, std::io::Result<()>>,
@ -65,14 +41,14 @@ pub(crate) struct OsSignals {
signals: Vec<(SignalKind, actix_rt::signal::unix::Signal)>, signals: Vec<(SignalKind, actix_rt::signal::unix::Signal)>,
} }
impl OsSignals { impl Signals {
/// Constructs an OS signal listening future. /// Constructs an OS signal listening future.
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
trace!("setting up OS signal listener"); trace!("setting up OS signal listener");
#[cfg(not(unix))] #[cfg(not(unix))]
{ {
OsSignals { Signals {
signals: Box::pin(actix_rt::signal::ctrl_c()), signals: Box::pin(actix_rt::signal::ctrl_c()),
} }
} }
@ -82,9 +58,9 @@ impl OsSignals {
use actix_rt::signal::unix; use actix_rt::signal::unix;
let sig_map = [ let sig_map = [
(unix::SignalKind::interrupt(), SignalKind::OsInt), (unix::SignalKind::interrupt(), SignalKind::Int),
(unix::SignalKind::terminate(), SignalKind::OsTerm), (unix::SignalKind::terminate(), SignalKind::Term),
(unix::SignalKind::quit(), SignalKind::OsQuit), (unix::SignalKind::quit(), SignalKind::Quit),
]; ];
let signals = sig_map let signals = sig_map
@ -103,18 +79,18 @@ impl OsSignals {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
OsSignals { signals } Signals { signals }
} }
} }
} }
impl Future for OsSignals { impl Future for Signals {
type Output = SignalKind; type Output = SignalKind;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
#[cfg(not(unix))] #[cfg(not(unix))]
{ {
self.signals.as_mut().poll(cx).map(|_| SignalKind::OsInt) self.signals.as_mut().poll(cx).map(|_| SignalKind::Int)
} }
#[cfg(unix)] #[cfg(unix)]
@ -130,10 +106,3 @@ impl Future for OsSignals {
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
static_assertions::assert_impl_all!(StopSignal: Send, Unpin);
}

View File

@ -341,10 +341,11 @@ impl ServerWorker {
Ok((token, svc)) => services.push((idx, token, svc)), Ok((token, svc)) => services.push((idx, token, svc)),
Err(err) => { Err(err) => {
error!("can not start worker: {err:?}"); error!("can not start worker: {:?}", err);
return Err(io::Error::other(format!( return Err(io::Error::new(
"can not start server service {idx}", io::ErrorKind::Other,
))); format!("can not start server service {}", idx),
));
} }
} }
} }
@ -439,12 +440,13 @@ impl ServerWorker {
Ok((token, svc)) => services.push((idx, token, svc)), Ok((token, svc)) => services.push((idx, token, svc)),
Err(err) => { Err(err) => {
error!("can not start worker: {err:?}"); error!("can not start worker: {:?}", err);
Arbiter::current().stop(); Arbiter::current().stop();
factory_tx factory_tx
.send(Err(io::Error::other(format!( .send(Err(io::Error::new(
"can not start server service {idx}", io::ErrorKind::Other,
)))) format!("can not start server service {}", idx),
)))
.unwrap(); .unwrap();
return; return;
} }

View File

@ -1,4 +1,4 @@
//! When MSRV is 1.82, replace with `core::future::Ready` and `core::future::ready()`. //! When MSRV is 1.48, replace with `core::future::Ready` and `core::future::ready()`.
use core::{ use core::{
future::Future, future::Future,

View File

@ -1,8 +1,6 @@
_list: _list:
@just --list @just --list
toolchain := ""
# Check project. # Check project.
check: && clippy check: && clippy
just --unstable --fmt --check just --unstable --fmt --check
@ -23,11 +21,11 @@ fmt:
# Downgrade dependencies necessary to run MSRV checks/tests. # Downgrade dependencies necessary to run MSRV checks/tests.
[private] [private]
downgrade-for-msrv: downgrade-for-msrv:
cargo {{ toolchain }} update -p=native-tls --precise=0.2.13 # next ver: 1.80.0 cargo update -p=clap --precise=4.4.18 # next ver: 1.74.0
cargo {{ toolchain }} update -p=idna_adapter --precise=1.2.0 # next ver: 1.82.0 cargo update -p=native-tls --precise=0.2.13 # next ver: 1.80.0
cargo {{ toolchain }} update -p=litemap --precise=0.7.4 # next ver: 1.81.0 cargo update -p=litemap --precise=0.7.4 # next ver: 1.81.0
cargo {{ toolchain }} update -p=zerofrom --precise=0.1.5 # next ver: 1.81.0 cargo update -p=zerofrom --precise=0.1.5 # next ver: 1.81.0
cargo {{ toolchain }} update -p=half --precise=2.4.1 # next ver: 1.81.0 cargo update -p=half --precise=2.4.1 # next ver: 1.81.0
msrv := ``` msrv := ```
cargo metadata --format-version=1 \ cargo metadata --format-version=1 \
@ -45,39 +43,37 @@ non_linux_all_features_list := ```
all_crate_features := if os() == "linux" { "--all-features" } else { "--features='" + non_linux_all_features_list + "'" } all_crate_features := if os() == "linux" { "--all-features" } else { "--features='" + non_linux_all_features_list + "'" }
# Run Clippy over workspace. # Run Clippy over workspace.
clippy: clippy toolchain="":
cargo {{ toolchain }} clippy --workspace --all-targets {{ all_crate_features }} cargo {{ toolchain }} clippy --workspace --all-targets {{ all_crate_features }}
# Run Clippy using MSRV. # Run Clippy using MSRV.
clippy-msrv: downgrade-for-msrv clippy-msrv: downgrade-for-msrv (clippy msrv_rustup)
@just toolchain={{ msrv_rustup }} clippy
# Test workspace code. # Test workspace code.
[macos] [macos]
[windows] [windows]
test: test toolchain="":
cargo {{ toolchain }} test --lib --tests --package=actix-macros cargo {{ toolchain }} test --lib --tests --package=actix-macros
cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros --no-default-features cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros --no-default-features
cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ all_crate_features }} cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ all_crate_features }}
# Test workspace code. # Test workspace code.
[linux] [linux]
test: test toolchain="":
cargo {{ toolchain }} test --lib --tests --package=actix-macros cargo {{ toolchain }} test --lib --tests --package=actix-macros
cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros --no-default-features cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros --no-default-features
cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ non_linux_all_features_list }} cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ non_linux_all_features_list }}
cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ all_crate_features }} cargo {{ toolchain }} nextest run --no-tests=warn --workspace --exclude=actix-macros {{ all_crate_features }}
# Test workspace using MSRV. # Test workspace using MSRV.
test-msrv: downgrade-for-msrv test-msrv: downgrade-for-msrv (test msrv_rustup)
@just toolchain={{ msrv_rustup }} test
# Test workspace docs. # Test workspace docs.
test-docs: && doc test-docs toolchain="": && doc
cargo {{ toolchain }} test --doc --workspace {{ all_crate_features }} --no-fail-fast -- --nocapture cargo {{ toolchain }} test --doc --workspace {{ all_crate_features }} --no-fail-fast -- --nocapture
# Test workspace. # Test workspace.
test-all: test test-docs test-all toolchain="": (test toolchain) (test-docs toolchain)
# Document crates in workspace. # Document crates in workspace.
doc *args: && doc-set-workspace-crates doc *args: && doc-set-workspace-crates
@ -100,12 +96,12 @@ doc-watch:
cargo watch -- just doc cargo watch -- just doc
# Check for unintentional external type exposure on all crates in workspace. # Check for unintentional external type exposure on all crates in workspace.
check-external-types-all: check-external-types-all toolchain="+nightly":
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
exit=0 exit=0
for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do
if ! just toolchain="+nightly" check-external-types-manifest "$f"; then exit=1; fi if ! just check-external-types-manifest "$f" {{ toolchain }}; then exit=1; fi
echo echo
echo echo
done done
@ -118,9 +114,9 @@ check-external-types-all-table toolchain="+nightly":
for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do for f in $(find . -mindepth 2 -maxdepth 2 -name Cargo.toml | grep -vE "\-codegen/|\-derive/|\-macros/"); do
echo echo
echo "Checking for $f" echo "Checking for $f"
just toolchain="+nightly" check-external-types-manifest "$f" --output-format=markdown-table just check-external-types-manifest "$f" {{ toolchain }} --output-format=markdown-table
done done
# Check for unintentional external type exposure on a crate. # Check for unintentional external type exposure on a crate.
check-external-types-manifest manifest_path *extra_args="": check-external-types-manifest manifest_path toolchain="+nightly" *extra_args="":
cargo {{ toolchain }} check-external-types --manifest-path "{{ manifest_path }}" {{ extra_args }} cargo {{ toolchain }} check-external-types --manifest-path "{{ manifest_path }}" {{ extra_args }}