Coder Social home page Coder Social logo

Comments (6)

slawlor avatar slawlor commented on May 14, 2024 1

The other thing is pre_start would probably have to take in self and return Result<Self, ActorProcessingErr> in order to deal with potential ownership things. Then the other function would probably be

async fn handle(&mut self, ...)

etc...

The reason the supervisor example uses the struct itself is just an artifact that should be cleaned up. If self contains re-only data you're free to use it, but ideally it should be in the state as a pattern. It should be moved to that actor's Arguments and stored in the state, thanks for the pointer :)

from ractor.

slawlor avatar slawlor commented on May 14, 2024

I'll try and add something to this effect onto the docs, but the short answer is the Actor's state is constructed and mutated only by the actor's processing loop. It also allows ownership of objects where if we utilize the struct implementing the Actor trait we can only give a mutable reference and can't have full ownership of objects inside the pre_start routine.

Essentially if we made the struct mutable from the start, you have to initialize it before calling spawn of the actor. This means that if initialization were to panic! or throw some unhandled error, it would need to be captured manually by the caller instead of getting a cleaner SpawnErr.

It was a design choice, but this seemed like a safer pattern to me when creating it to prevent unhandled panic's from accidentally taking down the caller.

As another anecdote, imagine your "root" actor panic!s in it's initialization. Without pre_start capturing it for you, you might crash your app where you could potentially handle the error.

Does that make sense?

from ractor.

tbillington avatar tbillington commented on May 14, 2024

Fair enough! Thanks for that clarification.

I had a reference to db in the struct field, but I think I'll move it to state now. Mentally to me it's more of some kind of "global resource" as opposed to actor state but I think it still fits best there.

from ractor.

tqwewe avatar tqwewe commented on May 14, 2024

It also allows ownership of objects where if we utilize the struct implementing the Actor trait we can only give a mutable reference and can't have full ownership of objects inside the pre_start routine.

Essentially if we made the struct mutable from the start, you have to initialize it before calling spawn of the actor. This means that if initialization were to panic! or throw some unhandled error, it would need to be captured manually by the caller instead of getting a cleaner SpawnErr.

Wouldn't this all be solved if pre_start could simply return Self without taking &self?

#[async_trait]
impl Actor for PingPong {
    type Msg = Message;
    type Arguments = u32;

    async fn pre_start(
        _: ActorRef<Self::Msg>,
        initial_value: u32,
    ) -> Result<Self, ActorProcessingErr> {
        Ok(initial_value)
    }
}

It was a design choice, but this seemed like a safer pattern to me when creating it to prevent unhandled panic's from accidentally taking down the caller.

As another anecdote, imagine your "root" actor panic!s in it's initialization. Without pre_start capturing it for you, you might crash your app where you could potentially handle the error.

Another idea would be to use a kind of "factory" to start actors.

Actor::spawn(MyActor { state: 123 }); // Like this if MyActor cannot fail.
Actor::try_spawn(move || MyActor::new(123).unwrap()); // This could fail, but won't panic outside the scope.

This means the pre_start method is optional, and all the methods would take &mut self.

In my opionion, removing the State associated type would make things much simpler.

from ractor.

slawlor avatar slawlor commented on May 14, 2024

So there's an open problem in Rust which we're looking at addressing, in that even if a panic is caught, the context isn't capturable. We'll likely be proposing some upstream core Rust change to support this, but at the moment if a panic is unwinding, and we catch_unwind, the backtrace can't be caught and propagated to understand where an error occurred. This was the reason for adding ActorProcessingErr in the crate, so you could return a better typed error with both an underlying error context along with a backtrace to understand the root of an actor exiting due to error.

By making a change like this, if you try_spawn and it panic's you would catch it, but any logging infra / etc wouldn't know where it was caused. Perhaps a closure which returns an ActorProcessingErr might make sense, but then this new syntax is getting heavier/uglier.

from ractor.

jsgf avatar jsgf commented on May 14, 2024

The way I think of it is that the data in the Actor is like config, whereas its State is the dynamic runtime state. The distinction may seem moot for the simple case but I find it very valuable when using a Factory which means that for every logical actor (Factory) there's distinct state for each worker (actor instance).

This would work better if Factories were more transparent (ie don't change the channel type).

from ractor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.