pub mod ready;
use crate::executor::Executor;
use async_trait::async_trait;
use futures::Future;
use graceful_shutdown::Shutdown;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::fmt::{self, Display};
use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WorkerId {
name: String,
}
impl Display for WorkerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
impl WorkerId {
pub fn new<T: AsRef<str>>(name: T) -> Self {
Self {
name: name.as_ref().to_string(),
}
}
pub fn name(&self) -> &str {
&self.name
}
}
#[derive(Error, Debug)]
pub enum WorkerError {
#[error("Failed to process job: {0}")]
JobProcessingError(String),
#[error("Service error: {0}")]
ServiceError(String),
#[error("Failed to start worker: {0}")]
StartError(String),
}
#[async_trait]
pub trait Worker<Job>: Sized {
type Service;
type Source;
fn id(&self) -> WorkerId;
async fn start<E: Executor + Send + Sync + 'static>(
self,
ctx: WorkerContext<E>,
) -> Result<(), WorkerError>;
}
#[derive(Clone)]
pub struct WorkerContext<E: Executor> {
pub(crate) shutdown: Shutdown,
pub(crate) executor: E,
pub(crate) worker_id: WorkerId,
}
impl<E: Executor> fmt::Debug for WorkerContext<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WorkerContext")
.field("shutdown", &["Shutdown handle"])
.field("worker_id", &self.worker_id)
.finish()
}
}
impl<E: Executor + Send> WorkerContext<E> {
pub fn id(&self) -> WorkerId {
self.worker_id.clone()
}
pub fn spawn(&self, future: impl Future<Output = ()> + Send + 'static) {
self.executor.spawn(self.shutdown.graceful(future));
}
pub fn shutdown(&self) {}
}
#[async_trait::async_trait]
pub trait HeartBeat {
async fn heart_beat(&mut self);
fn interval(&self) -> Duration;
}