use std::sync::{Arc, Mutex, mpsc};
use std::thread::{self, JoinHandle};
use std::time::Duration;
use timerwheel::Timer;
use timerwheel::executor::{BoxTask, Executor, ExecutorMetrics, Pool, RejectedTask};
struct ChannelExecutor {
sender: Mutex<Option<mpsc::Sender<BoxTask>>>,
worker: Mutex<Option<JoinHandle<()>>>,
}
impl ChannelExecutor {
fn new() -> Arc<Self> {
let (sender, receiver) = mpsc::channel::<BoxTask>();
let worker = thread::spawn(move || {
while let Ok(task) = receiver.recv() {
task.run();
}
});
Arc::new(Self {
sender: Mutex::new(Some(sender)),
worker: Mutex::new(Some(worker)),
})
}
}
impl Executor for ChannelExecutor {
fn try_execute(&self, task: BoxTask) -> std::result::Result<(), RejectedTask> {
let Some(sender) = self.sender.lock().expect("sender lock").as_ref().cloned() else {
return Err(RejectedTask::new(timerwheel::Error::Closed, task));
};
sender
.send(task)
.map_err(|error| RejectedTask::new(timerwheel::Error::Closed, error.0))
}
fn shutdown(&self) -> timerwheel::Result<()> {
self.sender.lock().expect("sender lock").take();
if let Some(worker) = self.worker.lock().expect("worker lock").take() {
let _ = worker.join();
}
Ok(())
}
fn metrics(&self) -> ExecutorMetrics {
ExecutorMetrics::default()
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let pool = Pool::builder().workers(2).queue_capacity(32).build()?;
let (pool_tx, pool_rx) = mpsc::channel();
pool.execute(move || {
pool_tx.send("pool").expect("send succeeds");
})?;
println!("{}", pool_rx.recv_timeout(Duration::from_secs(1))?);
pool.shutdown()?;
let executor = ChannelExecutor::new();
let timer_executor: Arc<dyn Executor> = executor.clone();
let timer = Timer::builder().executor(timer_executor).build()?;
let (timer_tx, timer_rx) = mpsc::channel();
timer.schedule(Duration::from_millis(10), move || {
timer_tx.send("custom").expect("send succeeds");
})?;
println!("{}", timer_rx.recv_timeout(Duration::from_secs(1))?);
timer.shutdown()?;
executor.shutdown()?;
Ok(())
}