lunatic icon indicating copy to clipboard operation
lunatic copied to clipboard

Add a (unified) API for timeouts.

Open teymour-aldridge opened this issue 3 years ago • 2 comments

Timeouts are very useful!

It would be great to have an API which makes it possible to conduct operations with a timeout.

teymour-aldridge avatar Mar 05 '21 20:03 teymour-aldridge

This would require a scheduler. Technically this would nice for AssemblyScript devs too, but I don't think lunatic is heading in that sort of direction.

jtenner avatar Mar 06 '21 16:03 jtenner

So I wrote a very hacky solution based on @bkolobara's advice.

use std::time::Duration;

use lunatic::{channel::Sender, Process};
use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct TimeoutError;

#[derive(Serialize, Deserialize)]
pub enum Msg<R> {
    Done(R),
    Timeout,
}

fn sleep_and_send_message<T>((duration, sender): (Duration, Sender<Msg<T>>))
where
    T: Serialize + for<'de> Deserialize<'de>,
{
    std::thread::sleep(duration);
    sender
        .send(Msg::Timeout)
        .expect("failed to send timeout notification");
}

pub fn timeout<IN, OUT>(
    ctx: IN,
    op: fn((IN, Sender<Msg<OUT>>)),
    duration: Duration,
) -> Result<OUT, TimeoutError>
where
    OUT: Serialize + for<'de> Deserialize<'de>,
    IN: Serialize + for<'de> Deserialize<'de>,
{
    let (sender, receiver) = lunatic::channel::bounded(1);

    Process::spawn_with((ctx, sender.clone()), op).detach();
    Process::spawn_with((duration, sender), sleep_and_send_message).detach();

    match receiver.receive().expect("failed to receive") {
        Msg::Done(t) => Ok(t),
        Msg::Timeout => Err(TimeoutError),
    }
}

Which I'm using internally in my web framework for Lunatic.

teymour-aldridge avatar Mar 06 '21 22:03 teymour-aldridge