Actix - running actors

Hello.
I would like to run actors based on the configuration.
In the first step I want to create an actor. Then start it if the name is in the list (cfg).
How to get sender address in handler ?

use actix::*;
use std::collections::HashMap;

struct MyActor
{
    val: usize,
}

impl MyActor
{
    pub fn new() -> Self { return MyActor{ val: 0 }; }
}

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

#[derive(Debug, Clone)]
pub struct PushData<T> {
    pub value: T,
}

impl<T: 'static> Message for PushData<T>
{
    type Result = T;
}

impl Handler<PushData> for MyActor
{
    type Result = ();

    fn handle(&mut self, msg: PushData, ctx: &mut Self::Context) -> Self::Result
    {
          // ...any code
    }
}

fn main()
{
    //load actors
    let mut actors = HashMap::new();
    actors.insert("MyActor1", MyActor::new());

    //config
    let mut cfg = Vec::new();
    cfg.push("MyActor1");
    cfg.push("MyActor2");
    cfg.push("MyActorX");

    for c in cfg
    {
        System::run(move || {
            let addr = actors[c].start();
        });
    }
}

Errors:

error[E0507]: cannot move out of index of `std::collections::HashMap<&str, MyActor>`
  --> src/main.rs:45:24
   |
45 |             let addr = actors[c].start();
   |                        ^^^^^^^^^ move occurs because value has type `MyActor`, which does not implement the `Copy` trait
   |
32 |     let mut actors = HashMap::new();
   |         ---------- move occurs because `actors` has type `std::collections::HashMap<&str, MyActor>`, which does not implement the `Copy` trait
...
44 |         System::run(move || {
   |                     ^^^^^^^ value moved into closure here, in previous iteration of loop
45 |             let addr = actors[c].start();
   |                        ------ use occurs due to use in closure

You have to take ownership of the actor. The self() method destroys the actor, so it cannot still be in the hash map.

for c in cfg
{
    let actor = actors.remove(c).expect("No such actor");
    System::run(move || {
        let addr = actor.start();
    });
}
1 Like

@alice, thx for reply.
One more question... How to get sender address in handler ?

What does your handler look like? How is it called? If you show a more complete example, it will be easier to help.

impl Handler<PushData> for MyActor
{
    type Result = ();

    fn handle(&mut self, msg: PushData, ctx: &mut Self::Context) -> Self::Result
    {
          // ...any code
    }
}

Oh I see what you're asking. I'm not super familiar with actix, but I don't think there's a direct way to access that. I think if you want the sender address, I would include it in the message. This is a common pattern in multi threaded code to send an address or a channel with a message to enable responding to a message.

In my solution I have an address in the message - PushData.
But I expected to get the address from the context variable - ctx: &mut Self::Context.

The context can get you the address of the current actor. Make sure you have use actix::AsyncContext at the top of the file, then I believe you can use ctx.address() to get the address of the current actor.

actix::AsyncContext

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.