0

Currently I'm checking out Actix, a Rust based actor framework. I'm also using Actix web to build a REST API. Now, I'm familiar with actor based architecture from working with Akka, however, I'm not being able to start a simple async task inside of my handler.

It's simplified, but I have the following code:

#[post("/upload")]
pub async fn upload_images(
    app_config: web::Data<AppConfig>,
    mut payload: Multipart,
) -> Result<HttpResponse> {
    ... transforms the multipart form into images...

    for img in img_vec {
        app_config.image_processor_addr.do_send(ResizeImage{
            img_id: img._id,
            img_format: img.format,
            image_buffer: img.image.bytes,
        });
    };

    Ok(HttpResponse::Ok().content_type(ContentType::plaintext()).body(format!("Inserted {} images.", vec_len)))
}

As you can see, I receive a multipart upload which consists of images, which I then send to an image processing actor to perform a resize on the images.

And this is the simplified code for the handling of the message ResizeImage for the ImageProcessor actor:

impl Handler<ResizeImage> for ImageProcessor {
    type Result = ();

    fn handle(&mut self, msg: ResizeImage, _: &mut Self::Context) -> Self::Result {
        let thumbnail_col = self.thumbnail_col.clone();
        let img_col = self.img_col.clone();
        let img_format: ImageFormat = msg.img_format.clone().into();

        log::info!("Parsing image {} with actor {}.", msg.img_id, self.id);

        let actor_task_fut = Box::pin(async move {
            ... parses the image here...
        });

        match Arbiter::current().spawn(actor_task_fut) {
            true => log::info!("Sent task to arbiter."),
            false => log::error!("Failed to send task to arbiter!"),
        }
    }
}

The idea is that I would resolve the web handler, and the resize task would be done async on the actor thread. However, this works on the first call, but when I call the same endpoint before all the images from the previous call are parsed, it doesn't resolve immediately, it waits till the actor has resized the previous batch.

I was under the impression that the messages would be sent to the actor mailbox and then the handler code would not need to wait for anything, since I'm using do_sent, which the documentation states that it doesn't await for the answer. Using Akka I can easily do something similar, and it seems to work. Am I missing something here? Is the way I'm handling async inside the actor thread wrong?

CG-SS
  • 11
  • 4
  • Side note. Actix no longer uses the actor model. They just didn't bother to change the name. – Aleksander Krauze Oct 22 '22 at 00:48
  • I needed async handlers a while back, and they have an rc version of actix-actor with experimental support for async handlers, but there was 0 documentation and i couldn't get it to work. So I ended up using xactor instead. Why not have a seperate async runner, and just send your data over a channel? – t348575 Oct 22 '22 at 05:11
  • @AleksanderKrauze Well that's a shame, I wish they would update the documentation at least, it still says it's an "actor based framework" on Actix. – CG-SS Oct 23 '22 at 03:05
  • @t348575 Oh yeah, sure, I could use the normal async Rust stuff, but I'm looking into Actix, I would like to leverage the actor framework. – CG-SS Oct 23 '22 at 03:08

0 Answers0