Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production. Actix. #19

Open
uwejan opened this issue Apr 26, 2023 · 5 comments
Open

Production. Actix. #19

uwejan opened this issue Apr 26, 2023 · 5 comments

Comments

@uwejan
Copy link

uwejan commented Apr 26, 2023

Hey there, I am coming from actix actors background, Suffering from some limitations, and I on search for an alternative or an easy convert.

I am going to state down my use case, and I wonder if it will be feasible to make the convert upon your answers. It is also good to know if the crate is being used on production.

  1. Websocket actor, handle read/write. With actix simple as ctx.addStream(), then implement the message types, for write add write part of the stream to the sate of the actor, and calling when needed.
  2. Db actor, handle db operations. here comes majore suffering with async/await/blocking thread ..etc, will share a snippets at the end.
  3. Also using tauri, so the runtime enviroment has to be shared, where as had a blummer back in while to figure actix runtime fix to make it work, which is still not compelling.
  4. some cpu intensive actors dealing with file system on seperate threads.
  5. back to 4 where as cross actor comunication through recipients or actor refs.

Not going to mention supervisoring as I already read that it is there.
Making the move to an already crate or using pure rust / tokio channels is the way to go for this project of mine, but knwoing a crate already has the potentials to solve the issues am facing will just make things easier, It will come at the end how much time the conversion of the project will take. So your answers are really important.

Thank you.

Blocking thread. // lack of async/await support.
I also tried atomicResponse but in that case I losse access to self, and being static issues.
Not trying to figure out a fix, as moving forward async/await is the future to go.

impl Handler<DbOperations> for McActor {
    type Result = String;
    //type Result = ResponseFuture<String>;
    fn handle(&mut self, msg: DbOperations, ctx: &mut Self::Context) -> Self::Result {
        return match msg {
             DbOperations::Get { key } => {
               block_on(async {
                    sqlx::query_as::<_, DbOperationValues>(select_query)
                        .bind(key)
                        .fetch_one(self.db.as_ref().unwrap())
                        .await
                        .unwrap()
                }).value
                 
            }
            DbOperations::Set { key, value } => {   
                block_on(async {
                    sqlx::query_as::<_, DbOperationValues>(insert_query)
                        .bind(key)
                        .bind(value)
                        .fetch_one(self.db.as_ref().unwrap())
                        .await
                        .unwrap()
                }).value
            }
        };
    }
}
@uwejan
Copy link
Author

uwejan commented Jun 19, 2023

@LeonHartley Could ou take a look please?

@uwejan
Copy link
Author

uwejan commented Jun 19, 2023

For the question parent to child comunication and viceversa. I am using the parent system to create supervisoed actor, which is allowing me to call child from parent, and parent from child.
I am noticing once a certain child is terminated, is effecting parents scheduled message.
I.e. parent has a scheduled messafe which basically prints childrens, but once one child is terminated. Parents schduled message stopes completley.
Perhaps am missing a concept here or there, thus i appreciate you taking a look.

@RedKinda
Copy link
Contributor

Looking at your code snippet, why sqlx operations are async, and the handle function should also be async, not sure what the goal of adding block_on and async again is.
Either way, I think database operations should not be executed from within an actor but rather a separate (global?) handler, because databases are able to handle multiple operations going on at the same time, while actors are not.

As for the blocking issue, make sure to use .notify instead of .send wherever you dont need an answer, otherwise you might create a deadlock (children sends to parent, and then parent sends to the same child, resulting in a deadlock because both are waiting for the other one to answer).

@uwejan
Copy link
Author

uwejan commented Jun 20, 2023

DB code you seen, is not related to coerce, it was just to show it was done using actix. And why am converting my code to this crate.
You are right about deadlocks.
However I am still figuring out, how to do internal communications, parent -> child, and viceversa. I am on local so doing anything like clustering is irrelevent.

@gembin
Copy link

gembin commented Jun 20, 2023

This should work? (not tested)

impl Handler<DbOperations> for McActor {
    type Result = ResponseActFuture<Self, Result<String, DatabaseError>>;

    fn handle(&mut self, msg: DbOperations, _ctx: &mut Self::Context) -> Self::Result {
        Box::pin(
            // ...
            async move {
               sqlx::query_as::<_, DbOperationValues>(select_query)
                        .bind(key)
                        .fetch_one(self.db.as_ref().unwrap())
                }
                .into_actor(self)
                .map(|res, _actor, _ctx| res)
            //...
        )
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants