use crate::types::{RunId, StepId, TaskId};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use thiserror::Error;
pub mod inmemory;
pub mod sqlite;
pub use inmemory::InMemoryRunStore;
pub use sqlite::SqliteRunStore;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RunStatus {
Pending,
Running,
Done,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StepEntry {
pub step_id: StepId,
pub step_ref: Option<String>,
pub status: Option<String>,
pub at: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunRecord {
pub id: RunId,
pub task_id: TaskId,
pub status: RunStatus,
pub step_entries: Vec<StepEntry>,
pub operator_sid: Option<String>,
pub result_ref: Option<serde_json::Value>,
pub created_at: u64,
pub updated_at: u64,
}
#[derive(Debug, Error)]
pub enum RunStoreError {
#[error("run not found: {0}")]
NotFound(RunId),
#[error("run already exists: {0}")]
Duplicate(RunId),
#[error("other: {0}")]
Other(String),
}
#[derive(Clone)]
pub struct RunContext {
pub run_id: RunId,
pub run_store: Arc<dyn RunStore>,
}
impl std::fmt::Debug for RunContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RunContext")
.field("run_id", &self.run_id)
.field("run_store", &self.run_store.name())
.finish()
}
}
#[async_trait]
pub trait RunStore: Send + Sync {
fn name(&self) -> &str;
async fn create(&self, record: RunRecord) -> Result<(), RunStoreError>;
async fn get(&self, id: &RunId) -> Result<RunRecord, RunStoreError>;
async fn list_by_task(&self, task_id: &TaskId) -> Result<Vec<RunRecord>, RunStoreError>;
async fn append_step_entry(&self, id: &RunId, entry: StepEntry) -> Result<(), RunStoreError>;
async fn update_status(&self, id: &RunId, status: RunStatus) -> Result<(), RunStoreError>;
async fn set_result(
&self,
id: &RunId,
result_ref: serde_json::Value,
) -> Result<(), RunStoreError>;
}
#[derive(Default)]
pub(crate) struct Inner {
pub(crate) order: Vec<RunId>,
pub(crate) records: HashMap<RunId, RunRecord>,
}
pub(crate) type SharedInner = Mutex<Inner>;