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

Using Riker with Tokio #150

Open
mankinskin opened this issue Dec 15, 2020 · 7 comments
Open

Using Riker with Tokio #150

mankinskin opened this issue Dec 15, 2020 · 7 comments

Comments

@mankinskin
Copy link

mankinskin commented Dec 15, 2020

Hi, I am having some trouble spawning a future on riker's executor. I want to spawn a stream polling future that should forward messages to an actor. Basically this is the only interesting part:

fn pre_start(&mut self, ctx: &Context<Self::Msg>) {
    let myself = ctx.myself();
    self.handle = Some(ctx.run(async move {
        while let Some(res) = crate::telegram::telegram().api.stream().next().await {
            match res {
                Ok(update) => myself.tell(update, None),
                Err(e) => error!("{}", e),
            }
        }
    }).expect("Failed to spawn telegram stream!"));
}

then I create the actor in my main function. annotated with tokio::main:

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut telegram_actor = crate::actor_sys_mut().await.actor_of::<TelegramActor>("telegram-actor").unwrap();
}

Where actor_sys() lazily creates the ActorSystem:

lazy_static! {
    static ref ACTOR_SYS: Arc<RwLock<ActorSystem>> = Arc::new(RwLock::new(ActorSystem::new().unwrap()));
}
pub async fn actor_sys() -> RwLockReadGuard<'static, ActorSystem> {
    ACTOR_SYS.read().await
}
pub async fn actor_sys_mut() -> RwLockWriteGuard<'static, ActorSystem> {
    ACTOR_SYS.write().await
}

However when I run this with the ctx.run call, I get this error:

thread 'pool-thread-#3' panicked at 'there is no timer running, must be called from the context of Tokio runtime', /home/linusb/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.24/src/time/driver/handle.rs:25:14

Am I doing something wrong? How can I solve this? Is there a better approach?

@mankinskin
Copy link
Author

So the problem seems to be that I have a tokio executor running, but riker uses the executor from futures. I'm thinking about configuring riker to use the tokio executor now.

@mankinskin mankinskin changed the title "there is no timer running, must be called from the context of tokio runtime" Using Riker with Tokio Dec 17, 2020
@mankinskin
Copy link
Author

mankinskin commented Dec 17, 2020

So this is my current state.

The ActorSystem starts the executor, which is currently hardcoded to futures::executor::ThreadPool, which is a handle to a ThreadPool, i.e. it can be cloned.

I have tried to make this field generic using an ExecutorHandle trait, but I realized that ActorSystem is passed all over the crate as a handle to the ActorSystem, so that meant adding generic parameters everywhere, which requires a lot of maintenance.

Then I tried to use cargo features to select the executor used using compiler flags. This got me pretty far, but there are some issues making the tests pass. I also had to edit riker-testkit. which seems to implement some mock actors for testing. I got it to compile, but for some reason the tests won't run through, they are just blocking and not being executed. Now I am looking into it on my forks tokio_executor branches:
https://github.com/mankinskin/riker/tree/tokio_executor
https://github.com/mankinskin/riker-testkit/tree/tokio_executor

@mankinskin
Copy link
Author

I have come to believe that it would be better to migrate the whole crate to use async/await and a tokio executor, which also intersects with the discussion in #87 . I would probably remove the feature in my fork and focus on migrating the entire crate to tokio using as much async/await as possible. But I will have to get more familiar with the individual components of this crate first. Any comments or suggestions would be much appreciated.

@mankinskin
Copy link
Author

The problem was not with riker or tokio, but rather telegram-bot.. It might be that there is an incompatibility between tokio 0.2 and 0.3

@mankinskin
Copy link
Author

mankinskin commented Dec 18, 2020

Actually, the problem was still there, even when using tokio 0.2 (in my crate). I thought the issue was that I was using telegram-bot (tokio 0.2) and with tokio 0.3, but that was not it. Even when using 0.2 everywhere, the futures executed by riker conflict with the tokio runtime.

The tokio_executor branch solves this though, by replacing the ThreadPool executor with a tokio::executor::Handle.

The code is a little bit ugly because of all the feature guards, and probably not ready to be merged in this repository. It works for my usecase right now, as I only really want to use tokio, but I would be happy to discuss how to turn this into a PR. Probably we can make the feature guards less extensive by encapsulating some parts of the code more.

@BratSinot
Copy link

@mankinskin Greetings again!
I don't know it problem of Tokio or Rust, but using riker from your branch gives me about 74-76% higher RAM usage than stock lib.

@mankinskin
Copy link
Author

mankinskin commented Aug 3, 2021

@BratSinot this might well be due to tokio: https://www.reddit.com/r/rust/comments/i3fync/why_async_version_of_simple_program_use_to_50x/

I have not benchmarked this branch, but I don't think anything except tokio could allocate this much RAM. In the reddit answer they say it is not really used memory, but just virtual memory, i.e. reserved memory ready to use but not actually used.

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

2 participants