use std::fmt;
use std::panic::{self, AssertUnwindSafe};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use crate::error::{Error, Result};
use crate::executor::metric_sink::NoopMetricSink;
use crate::executor::metrics::ExecutorMetricsInner;
use crate::executor::{self, BoxTask, ExecutorMetrics};
use crate::policy::{BackpressurePolicy, ExpiredTaskPolicy};
use crate::timer::{Timeout, TimerMetrics};
pub struct Executor {
handle: tokio::runtime::Handle,
closed: AtomicBool,
metrics: Arc<ExecutorMetricsInner>,
}
impl Executor {
pub fn current() -> Result<Self> {
let handle = tokio::runtime::Handle::try_current().map_err(|_| Error::Closed)?;
Ok(Self {
handle,
closed: AtomicBool::new(false),
metrics: Arc::new(ExecutorMetricsInner::new(0, Arc::new(NoopMetricSink))),
})
}
}
impl executor::Executor for Executor {
fn try_execute(&self, task: BoxTask) -> std::result::Result<(), executor::RejectedTask> {
if self.closed.load(Ordering::Acquire) {
return Err(executor::RejectedTask::new(Error::Closed, task));
}
let metrics = Arc::clone(&self.metrics);
self.metrics.submitted();
self.handle.spawn(async move {
let result = panic::catch_unwind(AssertUnwindSafe(|| {
task.run();
}));
if result.is_err() {
metrics.panicked();
}
metrics.completed();
});
Ok(())
}
fn shutdown(&self) -> Result<()> {
self.closed.store(true, Ordering::Release);
Ok(())
}
fn metrics(&self) -> ExecutorMetrics {
self.metrics.snapshot()
}
}
impl fmt::Debug for Executor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Executor")
.field("closed", &self.closed.load(Ordering::Acquire))
.field("metrics", &self.metrics.snapshot())
.finish_non_exhaustive()
}
}
#[derive(Debug)]
pub struct Timer {
inner: crate::Timer,
}
impl Timer {
pub fn builder() -> TimerBuilder {
TimerBuilder::default()
}
pub fn schedule<F>(&self, delay: Duration, task: F) -> Result<Timeout>
where
F: FnOnce() + Send + 'static,
{
self.inner.schedule(delay, task)
}
pub fn shutdown(&self) -> Result<()> {
self.inner.shutdown()
}
pub fn metrics(&self) -> TimerMetrics {
self.inner.metrics()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
}
#[derive(Clone, Default)]
pub struct TimerBuilder {
inner: crate::TimerBuilder,
}
impl TimerBuilder {
pub fn tick(mut self, tick: Duration) -> Self {
self.inner = self.inner.tick(tick);
self
}
pub fn bucket_count(mut self, bucket_count: usize) -> Self {
self.inner = self.inner.bucket_count(bucket_count);
self
}
pub fn command_capacity(mut self, command_capacity: usize) -> Self {
self.inner = self.inner.command_capacity(command_capacity);
self
}
pub fn max_pending(mut self, max_pending: usize) -> Self {
self.inner = self.inner.max_pending(max_pending);
self
}
pub fn backpressure_policy(mut self, policy: BackpressurePolicy) -> Self {
self.inner = self.inner.backpressure_policy(policy);
self
}
pub fn expired_task_policy(mut self, policy: ExpiredTaskPolicy) -> Self {
self.inner = self.inner.expired_task_policy(policy);
self
}
pub fn expired_task_retry(mut self, retry: Duration) -> Self {
self.inner = self.inner.expired_task_retry(retry);
self
}
pub fn build(self) -> Result<Timer> {
let executor: Arc<dyn executor::Executor> = Arc::new(Executor::current()?);
Ok(Timer {
inner: self.inner.executor(executor).build()?,
})
}
}
impl fmt::Debug for TimerBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TimerBuilder").finish_non_exhaustive()
}
}