use std::{
fmt::{self, Formatter},
sync::Arc,
};
use tokio::sync::Barrier;
pub use self::types::{TaskId, TaskKind};
use crate::service::StopReceiver;
mod types;
#[async_trait::async_trait]
pub trait Task: 'static + Send {
fn kind(&self) -> TaskKind {
TaskKind::Task
}
fn id(&self) -> TaskId;
async fn run(self: Box<Self>, stop_receiver: StopReceiver) -> eyre::Result<()>;
}
impl dyn Task {
pub(super) async fn run_internal(
self: Box<Self>,
stop_receiver: StopReceiver,
preconditions_barrier: Arc<Barrier>,
) -> eyre::Result<()> {
match self.kind() {
TaskKind::Task | TaskKind::OneshotTask => {
self.run_with_barrier(stop_receiver, preconditions_barrier)
.await
}
TaskKind::UnconstrainedTask | TaskKind::UnconstrainedOneshotTask => {
self.run(stop_receiver).await
}
TaskKind::Precondition => {
self.check_precondition(stop_receiver, preconditions_barrier)
.await
}
}
}
async fn run_with_barrier(
self: Box<Self>,
mut stop_receiver: StopReceiver,
preconditions_barrier: Arc<Barrier>,
) -> eyre::Result<()> {
tokio::select! {
_ = preconditions_barrier.wait() => {
self.run(stop_receiver).await
}
_ = stop_receiver.0.changed() => {
Ok(())
}
}
}
async fn check_precondition(
self: Box<Self>,
mut stop_receiver: StopReceiver,
preconditions_barrier: Arc<Barrier>,
) -> eyre::Result<()> {
self.run(stop_receiver.clone()).await?;
tokio::select! {
_ = preconditions_barrier.wait() => {
Ok(())
}
_ = stop_receiver.0.changed() => {
Ok(())
}
}
}
}
impl fmt::Debug for dyn Task {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("Task")
.field("kind", &self.kind())
.field("name", &self.id())
.finish()
}
}