Actor framework for Rust.

Last update: Jun 19, 2022

Actix

Actor framework for Rust

crates.io Documentation Version License Dependency Status
build status codecov Downloads Chat on Discord

Documentation

Features

  • Async and sync actors
  • Actor communication in a local/thread context
  • Uses futures for asynchronous message handling
  • Actor supervision
  • Typed messages (No Any type)
  • Runs on stable Rust 1.46+

Usage

To use actix, add this to your Cargo.toml:

[dependencies]
actix = "0.10"

Initialize Actix

In order to use actix you first need to create a System.

fn main() {
    let system = actix::System::new();

    system.run();
}

Actix uses the Tokio runtime. System::new() creates a new event loop. System.run() starts the Tokio event loop, and will finish once the System actor receives the SystemExit message.

Implementing an Actor

In order to define an actor you need to define a struct and have it implement the Actor trait.

use actix::{Actor, Addr, Context, System};

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        println!("I am alive!");
        System::current().stop(); // <- stop system
    }
}

fn main() {
    let mut system = System::new();

    let addr = system.block_on(async { MyActor.start() });

    system.run();
}

Spawning a new actor is achieved via the start and create methods of the Actor trait. It provides several different ways of creating actors; for details, check the docs. You can implement the started, stopping and stopped methods of the Actor trait. started gets called when the actor starts and stopping when the actor finishes. Check the API docs for more information on the actor lifecycle.

Handle Messages

An Actor communicates with another Actor by sending messages. In actix all messages are typed. Let's define a simple Sum message with two usize parameters and an actor which will accept this message and return the sum of those two numbers. Here we use the #[actix::main] attribute as an easier way to start our System and drive our main function so we can easily .await for the responses sent back from the Actor.

use actix::prelude::*;

// this is our Message
// we have to define the response type (rtype)
#[derive(Message)]
#[rtype(result = "usize")]
struct Sum(usize, usize);

// Actor definition
struct Calculator;

impl Actor for Calculator {
    type Context = Context<Self>;
}

// now we need to implement `Handler` on `Calculator` for the `Sum` message.
impl Handler<Sum> for Calculator {
    type Result = usize; // <- Message response type

    fn handle(&mut self, msg: Sum, ctx: &mut Context<Self>) -> Self::Result {
        msg.0 + msg.1
    }
}

#[actix::main] // <- starts the system and block until future resolves
async fn main() {
    let addr = Calculator.start();
    let res = addr.send(Sum(10, 5)).await; // <- send message and get future for result

    match res {
        Ok(result) => println!("SUM: {}", result),
        _ => println!("Communication to the actor has failed"),
    }
}

All communications with actors go through an Addr object. You can do_send a message without waiting for a response, or you can send an actor a specific message. The Message trait defines the result type for a message.

Actor State And Subscription For Specific Messages

You may have noticed that the methods of the Actor and Handler traits accept &mut self, so you are welcome to store anything in an actor and mutate it whenever necessary.

Address objects require an actor type, but if we just want to send a specific message to an actor that can handle the message, we can use the Recipient interface. Let's create a new actor that uses Recipient.

use actix::prelude::*;
use std::time::Duration;

#[derive(Message)]
#[rtype(result = "()")]
struct Ping {
    pub id: usize,
}

// Actor definition
struct Game {
    counter: usize,
    name: String,
    recipient: Recipient<Ping>,
}

impl Actor for Game {
    type Context = Context<Game>;
}

// simple message handler for Ping message
impl Handler<Ping> for Game {
    type Result = ();

    fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) {
        self.counter += 1;

        if self.counter > 10 {
            System::current().stop();
        } else {
            println!("[{0}] Ping received {1}", self.name, msg.id);

            // wait 100 nanoseconds
            ctx.run_later(Duration::new(0, 100), move |act, _| {
                act.recipient.do_send(Ping { id: msg.id + 1 });
            });
        }
    }
}

fn main() {
    let mut system = System::new();

    // To get a Recipient object, we need to use a different builder method
    // which will allow postponing actor creation
    let addr = system.block_on(async {
        Game::create(|ctx| {
            // now we can get an address of the first actor and create the second actor
            let addr = ctx.address();

            let addr2 = Game {
                counter: 0,
                name: String::from("Game 2"),
                recipient: addr.recipient(),
            }
            .start();

            // let's start pings
            addr2.do_send(Ping { id: 10 });

            // now we can finally create first actor
            Game {
                counter: 0,
                name: String::from("Game 1"),
                recipient: addr2.recipient(),
            }
        });
    });

    system.run();
}

Chat Example

See this chat example which shows more comprehensive usage in a networking client/server service.

Contributing

All contributions are welcome, if you have a feature request don't hesitate to open an issue!

License

This project is licensed under either of

at your option.

Code of Conduct

Contribution to the actix repo is organized under the terms of the Contributor Covenant. The Actix team promises to intervene to uphold that code of conduct.

GitHub

https://github.com/actix/actix
Comments
  • 1. Ingress and Egress from Actor Systems (Sync<->Async Bridging)

    In my current codebase, I have a bunch of full OS threads (thread::spawn) that are running select loops to receive messages on channels and reply on other channels. This pattern is pervasive throughout my codebase. Each of these "message handling thread loops" looks a lot like an actor. So, I tried my hand at converting the codebase from heavy OS threads to actix actors. The problem I'm having is that an actor system takes some inbound stimulus in order to start the massive chain of polling loops on futures, etc.

    I've got an actor that encapsulates a struct that has a callback function over FFI (it's wrapping invocations into a WebAssembly module). The actor receives a request to invoke, needs to call into the wasm (which can, in turn, make outbound calls which will be satisfied by further actor calls), and then respond with the value. In a call chain where everything is aware of futures, this works fine. But, since the actor receives a message that makes an FFI call, the code inside the FFI (wasm) is synchronous and expects a synchronous result.

    tl;dr at some vary small and crucial points in the application, I need to synchronously await the completion of a future from inside an actor's handle method that is not marked async (therefore await won't work). I've tried all kinds of shenanigans from using a map on the future to send the result out on a channel (doesn't work since nothing's polling the future that came from calling send), to using other runtimes to block_on the result (which just hangs forever).

    I've asked on Gitter and Twitter for patterns and workarounds to this problem to no avail.

    How does one await the result of some asynchronous actor invocation from inside a synchronous function that is not marked as an actix::main or a tokio::main or some other runtime's entry point?

    Reviewed by autodidaddict at 2020-09-20 18:46
  • 2. Define concurrency model and terms

    While studying Kabuki and Akka recently, I read mostly about their Actor model and its terms, but this list of concurrency models shows that it is only one family, among even Process Algebra, "a diverse family of related approaches for formally modelling concurrent systems". Many of them have non-descriptive names, so perhaps it would make the most sense to simply list which possible features of various Models for Programming Concurrency this project aims to implement.

    Also, based on noxisacat's reply to Actix 0.1 release announcement advising to switch away from Actor Model terms, since this project differs from its model, I picked out (possibly more) general and familiar concurrency terms, oriented toward teamwork and logistics, for a starting point in this:

    Actor ~> Worker: takes a job for processing

    Item ~> Work: piece of work (job)

    Cell ~> Schedule: ordering of a set of jobs (similar to a spool of thread)

    Supervisor ~> Delegate: sends jobs to workers' schedules

    Arbiter ~> Broker: sets how to use a field and which processes take place in it

    SyncArbiter ~> Dealer: handles users by spreading out supply

    System ~> Field: an environment for performing activities

    Context ~> Track: a laid out, measurable path with activities to follow; eg. on track and fast track

    State ~> Progress: measure of movement towards or away from defined start and end points; eg. work-in-progress and progress report

    Reviewed by naturallymitchell at 2017-10-13 01:40
  • 3. Support for Actors on different servers

    It would be nice to be able to have Actors running on completely different servers or different processes using something like tarpc so you could delegate work out horizontally.

    Use case would be that you have certain actors that are running on special hardware, such as GPUs etc..

    Reviewed by cetra3 at 2017-10-30 08:11
  • 4. Benchmarks?

    Are there any performance benchmarks for single node message latency/throughput (with varying number of actors) compared to Akka (or other actor frameworks)?

    Reviewed by ssbanerje at 2018-02-27 17:02
  • 5. async handlers with responses

    Are there any plans for adding something like an AsyncHandler trait:

    pub trait AsyncHandler<M> 
    where
        Self: Actor,
        M: Message, 
    {
        type Result: MessageResponse<Self, M>;
        async fn handle(&mut self, msg: M, ctx: &mut Self::Context) -> Self::Result;
    }
    

    which can return a future and has internally managed async memory access?

    I would really like to use actix with async APIs. I can use it with actix-interop right now, but that introduces a lot of boilerplate, especially because it requires the state used by the async code to be completely 'static, which means I have to manage all of my actor's state (that should be accessed by async functions) in a lazy_static variable. It would be nice if this could be handled by actix and if I could just write async code directly in an actix handler, which can also return responses.

    Reviewed by mankinskin at 2020-10-17 19:03
  • 6. Context.wait does not spawn futures

    My handle code looks like this:

    let fut = client
        .prepare(&sql)
        .into_actor(self)
        .map(|st, _a, _c| {
            println!("Request ok");
            ()
        })
        .map_err(|e, _a, _c| {
            println!("Reqest error: {:?}", e);
            ()
        });
    
    ctx.wait(fut);
    

    And it does not work (I don't see "Request ok"). But if I replace the last line with ctx.spawn( then it starts to work like charm. I believe ctx.wait is broken

    Reviewed by s-panferov at 2019-03-28 18:53
  • 7. thread '' panicked at 'no Task is currently running'

    Hi. We are encountering a panic during the execution of a migration script for an application running in production.

    It happens when we run a script which makes a lot of calls through the actix-web which triggers about 1000+ calls to a sync actor.

    It works fine for the first like 100 requests, then panic happens and the rest of the calls are served almost immediately without actually doing anything.

    thread '<unnamed>' panicked at 'no Task is currently running', /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.25/src/task_impl/mod.rs:44:9
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    stack backtrace:
       0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
                 at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
       1: std::sys_common::backtrace::print
                 at libstd/sys_common/backtrace.rs:71
                 at libstd/sys_common/backtrace.rs:59
       2: std::panicking::default_hook::{{closure}}
                 at libstd/panicking.rs:211
       3: std::panicking::default_hook
                 at libstd/panicking.rs:227
       4: std::panicking::rust_panic_with_hook
                 at libstd/panicking.rs:477
       5: std::panicking::begin_panic
                 at libstd/panicking.rs:411
       6: futures::task_impl::with
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.25/src/task_impl/mod.rs:44
       7: futures::task_impl::current
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.25/src/task_impl/mod.rs:115
       8: <actix::address::channel::AddressSender<A>>::park
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/address/channel.rs:372
       9: <actix::address::channel::AddressSender<A>>::try_send
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/address/channel.rs:276
      10: <actix::address::Addr<A>>::try_send
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/address/mod.rs:112
    
      /// application stack trace omitted
    
      15: <actix::sync::SyncContextEnvelope<A, M> as actix::address::envelope::EnvelopeProxy>::handle
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/sync.rs:337
      16: <actix::address::envelope::Envelope<A> as actix::address::envelope::EnvelopeProxy>::handle
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/address/envelope.rs:67
      17: <actix::sync::SyncContext<A>>::run
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/sync.rs:237
      18: <actix::sync::SyncArbiter<A>>::start::{{closure}}
                 at /home/tatrix/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.7.5/src/sync.rs:115
    
    Reviewed by TatriX at 2018-11-27 13:48
  • 8. `trust-dns-proto` fails to compile

    After updating actix from v0.7.5 to v0.7.6 I'm seeing the following failures on TravisCI:

    Downloading trust-dns-resolver v0.10.0
       Compiling trust-dns-proto v0.5.0
    error[E0432]: unresolved import `tokio_timer::Timeout`
      --> /home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/trust-dns-proto-0.5.0/src/tcp/tcp_stream.rs:20:5
       |
    20 | use tokio_timer::Timeout;
       |     ^^^^^^^^^^^^^^^^^^^^ no `Timeout` in the root
    error[E0599]: no method named `context` found for type `tokio_executor::SpawnError` in the current scope
       --> /home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/trust-dns-proto-0.5.0/src/error.rs:293:11
        |
    293 |         e.context(ProtoErrorKind::SpawnError).into()
        |           ^^^^^^^
        |
        = note: the method `context` exists but the following trait bounds were not satisfied:
                `tokio_executor::SpawnError : failure::Fail`
                `&tokio_executor::SpawnError : failure::Fail`
                `&mut tokio_executor::SpawnError : failure::Fail`
    error[E0277]: the trait bound `futures::Future<Item=tcp::tcp_stream::TcpStream<tokio_tcp::TcpStream>, Error=std::io::Error> + std::marker::Send: std::marker::Sized` is not satisfied
       --> /home/travis/.cargo/registry/src/github.com-1ecc6299db9ec823/trust-dns-proto-0.5.0/src/tcp/tcp_stream.rs:145:10
        |
    145 |         (Box::new(stream), message_sender)
        |          ^^^^^^^^ `futures::Future<Item=tcp::tcp_stream::TcpStream<tokio_tcp::TcpStream>, Error=std::io::Error> + std::marker::Send` does not have a constant size known at compile-time
        |
        = help: the trait `std::marker::Sized` is not implemented for `futures::Future<Item=tcp::tcp_stream::TcpStream<tokio_tcp::TcpStream>, Error=std::io::Error> + std::marker::Send`
        = note: required by `<std::boxed::Box<T>>::new`
    

    It seems a little unfortunate that such a problematic dependency was added in just a patch update. Are there any known workarounds for this problem?

    Reviewed by Turbo87 at 2018-11-26 08:18
  • 9. Strange Error When Running Cargo Doc

    I can't run cargo doc on my project using actix-web due to an error documenting actix. I am running rust 1.31 and have my project set to edition 2018:

    C:\Users\GregElenbaas\workspace\walkwiki>cargo doc --open
     Documenting actix v0.7.9
    error[E0275]: overflow evaluating the requirement `std::ptr::Unique<std::vec::Vec<u8>>: std::marker::Send`
      |
      = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
      = note: required because it appears within the type `alloc::raw_vec::RawVec<std::vec::Vec<u8>>`
      = note: required because it appears within the type `std::vec::Vec<std::vec::Vec<u8>>`
      = note: required because it appears within the type `mio::sys::windows::buffer_pool::BufferPool`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<mio::sys::windows::buffer_pool::BufferPool>`
      = note: required because it appears within the type `mio::sys::windows::selector::SelectorInner`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<mio::sys::windows::selector::SelectorInner>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `lazycell::AtomicLazyCell<std::sync::Arc<mio::sys::windows::selector::SelectorInner>>`
      = note: required because it appears within the type `mio::sys::windows::selector::Binding`
      = note: required because it appears within the type `mio::sys::windows::selector::ReadyBinding`
      = note: required because it appears within the type `mio::sys::windows::udp::Inner`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<mio::sys::windows::udp::Inner>`
      = note: required because it appears within the type `mio::sys::windows::udp::Io`
      = note: required because of the requirements on the impl of `std::marker::Send` for `mio::sys::windows::from_raw_arc::FromRawArc<mio::sys::windows::udp::Io>`
      = note: required because it appears within the type `mio::sys::windows::udp::Imp`
      = note: required because it appears within the type `mio::sys::windows::udp::UdpSocket`
      = note: required because it appears within the type `mio::net::udp::UdpSocket`
      = note: required because it appears within the type `std::option::Option<mio::net::udp::UdpSocket>`
      = note: required because it appears within the type `tokio_reactor::PollEvented<mio::net::udp::UdpSocket>`
      = note: required because it appears within the type `tokio::net::UdpSocket`  = note: required because it appears within the type `std::option::Option<tokio::net::UdpSocket>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::udp::udp_client_stream::SingleUseUdpSocket`
      = note: required because it appears within the type `tokio_timer::Timeout<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::udp_client_stream::SingleUseUdpSocket>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse`
      = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `futures::lock::Lock<std::option::Option<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
      = note: required because it appears within the type `futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
      = note: required because it appears within the type `futures::Sender<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>>`
      = note: required because it appears within the type `futures::sync::mpsc::Sender<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
      = note: required because it appears within the type `futures::sync::mpsc::UnboundedSender<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::DnsRequestStreamHandle<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::BufDnsRequestStreamHandle<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleConnected`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner>>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
      = note: required because it appears within the type `alloc::raw_vec::RawVec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
      = note: required because it appears within the type `std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>>>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::NameServerPool<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::RetryDnsHandle<actors::resolver::trust_dns_resolver::name_server_pool::NameServerPool<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup::LookupEither<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup_state::CachingClient<actors::resolver::trust_dns_resolver::lookup::LookupEither<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup::LookupFuture`
      = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `futures::lock::Lock<std::option::Option<actors::resolver::trust_dns_resolver::lookup::LookupFuture>>`
      = note: required because it appears within the type `futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::lookup::LookupFuture>>`
      = note: required because it appears within the type `futures::Sender<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::async_resolver::Request`
      = note: required because of the requirements on the impl of `std::marker::Send` for `futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::async_resolver::Request>`
      = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::async_resolver::Request>>`
      = note: required because it appears within the type `futures::sync::mpsc::Sender<actors::resolver::trust_dns_resolver::async_resolver::Request>`
      = note: required because it appears within the type `futures::sync::mpsc::UnboundedSender<actors::resolver::trust_dns_resolver::async_resolver::Request>`
      = note: required because it appears within the type `actors::resolver::trust_dns_resolver::AsyncResolver`
      = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::AsyncResolver>`
      = note: required because it appears within the type `actors::resolver::Resolver`
    
    error: Could not document `actix`.
    
    Caused by:
      process didn't exit successfully: `rustdoc --crate-name actix C:\Users\GregElenbaas\.cargo\registry\src\github.com-1ecc6299db9ec823\actix-0.7.9\src/lib.rs --cap-lints allow --color always -o C:\Users\GregElenbaas\workspace\walkwiki\target\doc --cfg "feature=\"default\"" --cfg "feature=\"resolver\"" --cfg
    "feature=\"signal\"" --cfg "feature=\"tokio-signal\"" --cfg "feature=\"trust-dns-proto\"" --cfg "feature=\"trust-dns-resolver\"" -L dependency=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps --extern actix_derive=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\actix_derive-bd8466e5a3f5ab2e.dll --extern bitflags=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libbitflags-61bd86b3d3426acc.rmeta --extern bytes=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libbytes-788e68bf23e600c4.rmeta --extern crossbeam_channel=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libcrossbeam_channel-5710b2ac07374b9a.rmeta --extern failure=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libfailure-16119ac25b7925ea.rmeta --extern fnv=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libfnv-b0a886f693aec69a.rmeta --extern futures=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libfutures-827c59f67b54d9b1.rmeta --extern log=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\liblog-af14f4756be5f5ff.rmeta --extern parking_lot=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libparking_lot-a37e1f717009eefe.rmeta --extern smallvec=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libsmallvec-f81bda96822d22d1.rmeta --extern tokio_codec=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_codec-97bbab1c0e18efad.rmeta --extern tokio_executor=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_executor-b06cad3c378d2a78.rmeta --extern tokio=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio-8f497d79da1555f5.rmeta --extern tokio_io=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_io-900bba5937a286f6.rmeta --extern tokio_reactor=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_reactor-bfd49ad96ed059ee.rmeta --extern tokio_signal=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_signal-2aa4201aeb82222b.rmeta --extern tokio_tcp=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_tcp-4dfe06b6d9c86800.rmeta --extern tokio_timer=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtokio_timer-280ccb9444c2ed1f.rmeta --extern trust_dns_proto=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtrust_dns_proto-c53fd955f53bbe34.rmeta --extern trust_dns_resolver=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libtrust_dns_resolver-ac33edc762adeac4.rmeta --extern uuid=C:\Users\GregElenbaas\workspace\walkwiki\target\debug\deps\libuuid-df9acd76c1660055.rmeta` (exit code: 1)
    
    Reviewed by gregelenbaas at 2018-12-21 16:12
  • 10. Ping example doesn't match that on the website

    Not sure if this should be an issue but I was reading the docs and then followed the link to the example's code on github and noticed that they differed. Which is considered more up-to-date (and thus the best practice)?

    Reviewed by mandreyel at 2019-02-17 22:09
  • 11. Rust 2018

    I was experimenting yesterday, upgrading my little project to the 2018 edition. One of the changes there is about crates and imports. To cut it short, following the guide, I should remove extern crate actix and the rest should just work. However there is a problem.

    The problem is actix::prelude has a module named actix and it causes a conflict with the crate name itself. I was able to fix the error in 2 ways:

    1. Replace prelude with specific imports. This obviously works, but defeats the purpose of prelude.
    2. Add :: prefix: use ::actix::prelude::*;. I would make a peace importing it this way, however rustfmt rewrites it removing the prefix.

    It's a minor issue, but it would be nice to have it fixed (if possible at all) for 2018 edition release, for smoother migration.

    Reviewed by DGolubets at 2018-10-23 10:12
  • 12. "there is no reactor running" panic when system is quickly dropped

    Here is code that reproduces the issue: main.rs

    struct A {}
    
    impl actix::Actor for A {
        type Context = actix::Context<Self>;
    
        fn started(&mut self, ctx: &mut Self::Context) {
            use actix::AsyncContext;
            ctx.run_interval(std::time::Duration::from_millis(100), |_a, _c| {
                println!("Hi!");
            });
        }
    }
    
    fn main() {
        actix_rt::System::new().block_on(async {
            actix::Actor::start(A {});
            // tokio::time::sleep(std::time::Duration::from_millis(1)).await;
        });
    }
    

    Cargo.toml

    [dependencies]
    actix = "0.13.0"
    actix-rt = "2.7.0"
    tokio = { version = "1.17.0", features = ["time"]}
    

    Expected Behavior

    The program does not panic. Nothing should be sent to stdout, as system is dropped before 100 milliseconds pass (interval).

    Current Behavior

    The program panics and produces the following backtrace on crash:

    thread 'main' panicked at 'there is no reactor running, must be called from the context of a Tokio 1.x runtime', /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/context.rs:54:26
    stack backtrace:
       0: rust_begin_unwind
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panicking.rs:517:5
       1: core::panicking::panic_fmt
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/panicking.rs:101:14
       2: core::option::expect_failed
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/option.rs:1615:5
       3: core::option::Option<T>::expect
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/option.rs:698:21
       4: tokio::runtime::context::time_handle::{{closure}}
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/context.rs:54:13
       5: std::thread::local::LocalKey<T>::try_with
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/thread/local.rs:399:16
       6: tokio::runtime::context::time_handle
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/context.rs:52:15
       7: tokio::time::driver::handle::Handle::current
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/time/driver/handle.rs:57:13
       8: tokio::time::driver::sleep::Sleep::new_timeout
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/time/driver/sleep.rs:257:22
       9: tokio::time::driver::sleep::sleep
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/time/driver/sleep.rs:129:27
      10: actix::utils::IntervalFunc<A>::new
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.13.0/src/utils.rs:186:20
      11: actix::actor::AsyncContext::run_interval
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.13.0/src/actor.rs:459:20
      12: <playround::A as actix::actor::Actor>::started
                 at ./src/main.rs:8:9
      13: <actix::contextimpl::ContextFut<A,C> as core::future::future::Future>::poll
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.13.0/src/contextimpl.rs:360:13
      14: <actix::contextimpl::ContextFut<A,C> as core::ops::drop::Drop>::drop
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-0.13.0/src/contextimpl.rs:226:21
      15: core::ptr::drop_in_place<actix::contextimpl::ContextFut<playround::A,actix::context::Context<playround::A>>>
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ptr/mod.rs:188:1
      16: core::ptr::drop_in_place<tokio::runtime::task::core::Stage<actix::contextimpl::ContextFut<playround::A,actix::context::Context<playround::A>>>>
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ptr/mod.rs:188:1
      17: tokio::runtime::task::core::CoreStage<T>::set_stage::{{closure}}
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/core.rs:214:35
      18: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/loom/std/unsafe_cell.rs:14:9
      19: tokio::runtime::task::core::CoreStage<T>::set_stage
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/core.rs:214:9
      20: tokio::runtime::task::core::CoreStage<T>::drop_future_or_output
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/core.rs:180:13
      21: tokio::runtime::task::harness::cancel_task::{{closure}}
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/harness.rs:438:9
      22: core::ops::function::FnOnce::call_once
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ops/function.rs:227:5
      23: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/panic/unwind_safe.rs:271:9
      24: std::panicking::try::do_call
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panicking.rs:403:40
      25: __rust_try
      26: std::panicking::try
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panicking.rs:367:19
      27: std::panic::catch_unwind
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/std/src/panic.rs:129:14
      28: tokio::runtime::task::harness::cancel_task
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/harness.rs:437:15
      29: tokio::runtime::task::harness::Harness<T,S>::shutdown
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/harness.rs:147:9
      30: tokio::runtime::task::raw::shutdown
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/raw.rs:164:5
      31: tokio::runtime::task::raw::RawTask::shutdown
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/raw.rs:109:18
      32: tokio::runtime::task::Task<S>::shutdown
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/mod.rs:338:9
      33: tokio::runtime::task::list::LocalOwnedTasks<S>::close_and_shutdown_all
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/runtime/task/list.rs:225:13
      34: <tokio::task::local::LocalSet as core::ops::drop::Drop>::drop::{{closure}}
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/task/local.rs:606:13
      35: tokio::macros::scoped_tls::ScopedKey<T>::set
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/macros/scoped_tls.rs:61:9
      36: tokio::task::local::LocalSet::with
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/task/local.rs:561:9
      37: <tokio::task::local::LocalSet as core::ops::drop::Drop>::drop
                 at /home/prk3/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/task/local.rs:603:9
      38: core::ptr::drop_in_place<tokio::task::local::LocalSet>
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ptr/mod.rs:188:1
      39: core::ptr::drop_in_place<actix_rt::runtime::Runtime>
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ptr/mod.rs:188:1
      40: core::ptr::drop_in_place<actix_rt::system::SystemRunner>
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ptr/mod.rs:188:1
      41: playround::main
                 at ./src/main.rs:18:7
      42: core::ops::function::FnOnce::call_once
                 at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35/library/core/src/ops/function.rs:227:5
    

    Possible Solution

    I suspect run_interval creates some task that isn't dropped in time or it always assumes tokio runtime exists. I noticed that a short sleep just after staring the actor fixes the issue (commented in the example). Explicit ctx.cancel_future in stopping or stopped method does not fix the problem.

    Steps to Reproduce (for bugs)

    1. Call run_interval in actor's started method.
    2. Start actor in actix-rt system.
    3. Quickly drop the system.

    Context

    We came across this error twice. Once when running a test function with should_panic attribute. It looks like the expected panic triggers drops and the drop of the system causes this panic. Another case was starting and dropping a system in a loop in a fuzz test.

    Your Environment

    Linux work 5.16.13-200.fc35.x86_64 #1 SMP PREEMPT Tue Mar 8 22:50:58 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

    • Rust Version (I.e, output of rustc -V): rustc 1.58.1 (db9d1b20b 2022-01-20)
    • Actix Version: 0.13.0, 0.12.0
    Reviewed by prk3 at 2022-03-30 12:19
  • 13. API Extensions for WeakAddr and WeakRecipient

    PR Type

    Feature

    PR Checklist

    Check your PR fulfills the following:

    • [x] Tests for the changes have been added / updated.
    • [x] Documentation comments have been added / updated.
    • [x] A changelog entry has been made for the appropriate packages.
    • [x] Format code with the latest stable rustfmt

    Overview

    Both WeakAddr and WeakRecipient now offer a connected associated function with the same behavior as their strong counterparts. Furthermore a conversion trait From<Addr<A>> for WeakAddr<A> was added so that the conversions between weak / strong addresses and weak / strong recipients now all just work.

    (Unlikely) Breaking Change the WeakSender trait was extended by a connected associated function. It is unlikely that downstream crates implement this trait themselves, so this will probably not break any code.

    Reviewed by geo-ant at 2022-03-23 19:58
  • 14. Question: How to wait for an event on actor startup?

    I have an Actor that sets up an MQTT Server, but I only want the server to start, after I received a Message DatabaseConnection.

    What would be the recommended way to do this?

    Reviewed by LasseRosenow at 2022-03-22 03:04
  • 15. Fair handling of async sub-tasks in ContextFut

    In implementation of Future trait for actix::contextimpl::ContextFut there's a section which concerns with mailbox processing: https://github.com/actix/actix/blob/8dfab7eca079bec0a83c6d425a37c19da5106565/actix/src/contextimpl.rs#L380-L386

    the implementation itself is OK, except for the cases when mailbox is constantly being flooded with new messages: https://github.com/actix/actix/blob/8dfab7eca079bec0a83c6d425a37c19da5106565/actix/src/mailbox.rs#L77-L94 The poll method of Mailbox<A> gets forever stuck in the while loop as AddressReceiver::poll_next will keep producing values (message consumption rate is equal or lower than message production), and as such ContextFut won't be able to make progress on other sub-tasks (including Actor termination, if one is requested)

    Expected Behavior

    All sub-tasks should have a chance to make progress in one iteration of loop even if mailbox always has new messages to process

    Current Behavior

    <ContextFut as Future>::poll gets stuck at mailbox processing if message production rate is higher than consumption

    Possible Solution

    Maybe, introduction of an extra optional parameter, to limit the number of consecutively processed mailbox messages, could've helped, like

        pub fn poll(&mut self, act: &mut A, ctx: &mut A::Context, task: &mut task::Context<'_>,  max_consecutive:  Option<usize>) {
            let mut n_polls = 0u16;
    
            while !ctx.waiting() {
                match Pin::new(&mut self.msgs).poll_next(task) {
                    Poll::Ready(Some(mut msg)) => {
                        msg.handle(act, ctx);
                        n_polls += 1;
                        // Maximum number of consecutive polls in a loop is passed as parameter.
                        match max_consecutive {
                              Some(max) if n_polls >= max => return,
                              _ => continue,
                        }
                        
                    }
                    Poll::Ready(None) | Poll::Pending => return,
                }
            }
        }
    

    Steps to Reproduce

    1. Create a consumer Actor
    2. Create multiple producer Actors
    3. Send messages from producers to consumer (might as well use try_send)
    4. Make sure that production is higher than consumption
    5. Try to terminate consumer within message handling after some time, if mailbox is always at its full capacity, the consumer Actor will never be able to terminate

    Context

    I was using actix-web-actors, for websocket connection management, and the task was to forward some data from pubsub service to clients via websocket connection. Websocket connection manager is implemented as separate Actor, which gets messages from other Actors in system and forwards them to clients. In case if the message production rate is higher than the websocket connection manager is able to consume them, its mailbox gets full and stays full, as message production never stops (no back-pressure). At the meantime messages get handled by websocket connection actor and are added to queue in WebsocketContext::messages in order to be sent to client: https://github.com/actix/actix-web/blob/fc5ecdc30bb1b964b512686bff3eaf83b7271cf5/actix-web-actors/src/ws.rs#L370-L377 but as mailbox processing never stops, the VecDeque grows without bounds, as there's no opportunity to empty it and send queued messages to client. Eventually as one might guess the application crashes after running out of memory.

    • Rust Version (I.e, output of rustc -V): 1.56.1
    • Actix Version: 0.12.0
    • Actix-web-actors: 4.0.0-beta.10
    Reviewed by bobs4462 at 2022-02-02 15:47
  • 16. Mock example added

    PR Type

    Docs

    PR Checklist

    Check your PR fulfills the following:

    • [X] Tests for the changes have been added / updated.
    • [X] Documentation comments have been added / updated.
    • [ ] A changelog entry has been made for the appropriate packages.
    • [X] Format code with the latest stable rustfmt

    Overview

    The mocker docs mentions a mock example. I couldn't find it anywhere, so I thought that maybe I could contribute with one.

    I've seen two questions on Reddit about how to use it,(1, 2), so I figured this example might be helpful to others.

    Reviewed by abbudao at 2021-11-22 11:56
  • 17. Addr::send does not respect Mailbox size

    Addr::send will actually check if the Mailbox is full, but the future created by it uses a clone of AddressSender, and due to how AddressSender::clone is implemented, the newly cloned AddressSender will always bypass the Mailbox size check, which will cause MsgRequest to push to the queue on the first poll, independent if the queue is full or not.

    AddressSender::clone: https://github.com/actix/actix/blob/8dfab7eca079bec0a83c6d425a37c19da5106565/actix/src/address/channel.rs#L517-L521

    Note that it uses an Arc for maybe_parked, but instead of cloning the existing Arc it creates a new one. That Arc seems to never be used.

    However, here comes the catch, the docs of channel seem to imply that this is the intended behavior, i.e. clone an AddressSender and you can bypass the queue by one message, but it's counter-intuitive that Addr::send would behave like that, the docs specifically mention a bounded channel.

    I think we should change this behavior somehow or update the docs of Addr::send to reflect the current behavior.

    Expected Behavior

    The future returned by Addr::send (MsgRequest) should hold on to the item if the queue is full.

    Current Behavior

    MsgRequest always pushes the message to the Mailbox on the first poll, which might flood the actor and block ContextFut indefinitely, given that it tries to process all mailbox messages on a single poll.

    Possible Solution

    MsgRequest shouldn't have this power to always bypass queue line, we can change the behavior of AddressSender::clone or use another thing to implement MsgRequest. We also need to fix MsgRequest's Future implementation, since it returns Poll::Pending without registering a waker: https://github.com/actix/actix/blob/8dfab7eca079bec0a83c6d425a37c19da5106565/actix/src/address/message.rs#L73-L82

    Today this isn't a problem, since it bypasses the queue which never returns SendError::Full.

    Steps to Reproduce (for bugs)

    The following example will panic due to: https://github.com/actix/actix/blob/8dfab7eca079bec0a83c6d425a37c19da5106565/actix/src/mailbox.rs#L89

    /// [dependencies]
    /// actix = { version = "0.12.0", features = ["mailbox_assert"] }
    /// actix-rt = "2.3.0"
    /// tokio = { version = "1.13.0", default-features = false, features = ["signal"] }
    /// futures-util = { version = "0.3.17", default-features = false, features = ["alloc"] }
    
    use actix::{Actor, Context, Handler, Message};
    use futures_util::stream::{FuturesUnordered, StreamExt};
    
    struct MyMsg;
    
    impl Message for MyMsg {
        type Result = ();
    }
    
    struct MyActor;
    
    impl Actor for MyActor {
        type Context = Context<Self>;
    }
    
    impl Handler<MyMsg> for MyActor {
        type Result = ();
    
        fn handle(&mut self, _msg: MyMsg, _ctx: &mut Self::Context) -> Self::Result {}
    }
    
    #[actix_rt::main]
    async fn main() {
        let addr = MyActor.start();
        let mut futs = FuturesUnordered::new();
    
        for _ in 0..300 {
            let request = addr.send(MyMsg);
            futs.push(request);
        }
    
        actix_rt::spawn(async move {
            while futs.next().await.is_some() {}
            println!("Done");
        });
    
        tokio::signal::ctrl_c().await.unwrap();
    }
    

    Context

    The wanted solution is to be able to have a future that will await for the Mailbox to have enough space for the message before enqueuing, which in turn will allow me send several messages without being afraid of blocking ContextFut::poll for too long.

    Your Environment

    • Rust Version (I.e, output of rustc -V): 1.55.0
    • Actix Version: 0.12.0
    Reviewed by thalesfragoso at 2021-11-04 23:23
Implementing Bendersnatch curve using Arkwork's framework in Rust.

This is a reference implementation of Bendersnatch curve using Arkwork's framework in Rust. The spec of the curve is available here. There was also a Python reference implementation here.

Jun 18, 2022
Rust implementation of PRECIS Framework: Preparation, Enforcement, and Comparison of Internationalized Strings in Application Protocols

Rust PRECIS Framework libray PRECIS Framework: Preparation, Enforcement, and Comparison of Internationalized Strings in Application Protocols as descr

May 20, 2022
High performance I/O framework written by Rust inspired by Netty
High performance I/O framework written by Rust inspired by Netty

Introduction Retty is a High performance I/O framework written by Rust inspired by Netty 基于mio的IO多路复用高并发、高性能网络通信开发框架 Feature Rayon 线程池包装 EventLoop / E

Feb 16, 2022
A simple message based networking library for the bevy framework

Spicy Networking for Bevy bevy_spicy_networking is a solution to the "How do I connect multiple clients to a single server" problem in your bevy games

Jun 2, 2022
axum-server is a hyper server implementation designed to be used with axum framework.

axum-server axum-server is a hyper server implementation designed to be used with axum framework. Features Conveniently bind to any number of addresse

Jun 15, 2022
Fullstack development framework for UTXO-based dapps on Nervos Network

Trampoline-rs The framework for building powerful dApps on the number one UTXO chain, Nervos Network CKB. This is an early-stage, currently very incom

Mar 25, 2022
A versatile and efficient proxy framework with nice features suitable for various use cases.

A versatile and efficient proxy framework with nice features suitable for various use cases.

Jun 16, 2022
Astar Network is an interoperable blockchain based the Substrate framework and the hub for dApps within the Polkadot Ecosystem
Astar Network is an interoperable blockchain based the Substrate framework and the hub for dApps within the Polkadot Ecosystem

Astar Network is an interoperable blockchain based the Substrate framework and the hub for dApps within the Polkadot Ecosystem. With Astar Network and

Jun 19, 2022
Drpc-Correct, high performance, robust, easy use Remote invocation framework
Drpc-Correct, high performance, robust, easy use Remote invocation framework

Drpc - Correct, high performance, robust, easy use Remote invocation framework

May 19, 2022
Grow Rust is a Growtopia Private Server made in Rust

Grow Rust is a Growtopia Private Server made in Rust

Mar 14, 2022
Multiplex server for rust-analyzer, allows multiple LSP clients (editor windows) to share a single rust-analyzer instance per cargo workspace

ra-multiplex   Multiplex server for rust-analyzer, allows multiple LSP clients (editor windows) to share a single rust-analyzer instance per cargo wor

Jun 18, 2022
Rust crate for configurable parallel web crawling, designed to crawl for content

url-crawler A configurable parallel web crawler, designed to crawl a website for content. Changelog Docs.rs Example extern crate url_crawler; use std:

Aug 22, 2021
Rust crate for scraping URLs from HTML pages

url-scraper Rust crate for scraping URLs from HTML pages. Example extern crate url_scraper; use url_scraper::UrlScraper; fn main() { let director

Apr 25, 2022
FTP client for Rust

rust-ftp FTP client for Rust Documentation rust-ftp Installation Usage License Contribution Development environment Installation FTPS support is achie

Jun 25, 2022
The gRPC library for Rust built on C Core library and futures

gRPC-rs gRPC-rs is a Rust wrapper of gRPC Core. gRPC is a high performance, open source universal RPC framework that puts mobile and HTTP/2 first. Sta

Jun 24, 2022
A library to work with CIDRs in rust

ipnetwork This is a library to work with IPv4 and IPv6 CIDRs in Rust Run Clippy by doing rustup component add clippy cargo clippy Installation This c

Jun 8, 2022
Network simulation in Rust

netsim - A Rust library for network simulation and testing (currently linux-only). netsim is a crate for simulating networks for the sake of testing n

May 23, 2022
Cross-platform, low level networking using the Rust programming language.

libpnet Linux ∪ OS X Build Status: Windows Build Status: Discussion and support: #libpnet on freenode / #rust-networking on irc.mozilla.org / #rust on

Jun 25, 2022
A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...

Tokio A runtime for writing reliable, asynchronous, and slim applications with the Rust programming language. It is: Fast: Tokio's zero-cost abstracti

Jun 20, 2022