refactor(workspace): enforce layered crate boundaries

This commit is contained in:
elky
2026-07-15 23:47:19 +08:00
parent a728c090a9
commit 8616fe6ee2
969 changed files with 40187 additions and 27240 deletions
+62
View File
@@ -0,0 +1,62 @@
use serde::{Deserialize, Serialize};
use crate::RetryPolicy;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TaskKind {
Scheduled,
Daemon,
OnDemand,
FireAndForget,
}
impl TaskKind {
pub const fn as_str(self) -> &'static str {
match self {
Self::Scheduled => "scheduled",
Self::Daemon => "daemon",
Self::OnDemand => "on_demand",
Self::FireAndForget => "fire_and_forget",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct TaskDefinition {
pub key: &'static str,
pub kind: TaskKind,
pub trigger: &'static str,
pub singleton: bool,
pub persist_history: bool,
pub retry_policy: RetryPolicy,
}
impl TaskDefinition {
pub const fn new(
key: &'static str,
kind: TaskKind,
trigger: &'static str,
singleton: bool,
persist_history: bool,
retry_policy: RetryPolicy,
) -> Self {
Self {
key,
kind,
trigger,
singleton,
persist_history,
retry_policy,
}
}
pub const fn singleton(
key: &'static str,
kind: TaskKind,
trigger: &'static str,
persist_history: bool,
retry_policy: RetryPolicy,
) -> Self {
Self::new(key, kind, trigger, true, persist_history, retry_policy)
}
}
+16
View File
@@ -0,0 +1,16 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FencingToken(u64);
impl FencingToken {
pub const fn new(value: u64) -> Option<Self> {
if value == 0 {
None
} else {
Some(Self(value))
}
}
pub const fn get(self) -> u64 {
self.0
}
}
+59
View File
@@ -0,0 +1,59 @@
use crate::FencingToken;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TaskLease {
pub task_key: String,
pub owner: String,
pub fencing_token: String,
pub expires_at_unix_ms: u64,
}
impl TaskLease {
pub fn is_expired(&self, now_unix_ms: u64) -> bool {
now_unix_ms >= self.expires_at_unix_ms
}
pub fn parsed_fencing_token(&self) -> Result<FencingToken, TaskLeaseError> {
self.fencing_token
.parse::<u64>()
.ok()
.and_then(FencingToken::new)
.ok_or(TaskLeaseError::InvalidFencingToken)
}
}
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum TaskLeaseError {
#[error("task lease is unavailable")]
Unavailable,
#[error("task lease has expired")]
Expired,
#[error("task fencing token is invalid")]
InvalidFencingToken,
}
#[cfg(test)]
mod tests {
use super::TaskLease;
use crate::{RetryPolicy, TaskDefinition, TaskKind};
#[test]
fn singleton_definition_expiry_and_fencing_are_explicit() {
let definition = TaskDefinition::singleton(
"cleanup",
TaskKind::Scheduled,
"interval",
true,
RetryPolicy::default(),
);
assert!(definition.singleton);
let lease = TaskLease {
task_key: "cleanup".to_string(),
owner: "node-a".to_string(),
fencing_token: "1".to_string(),
expires_at_unix_ms: 10,
};
assert!(lease.is_expired(10));
assert_eq!(lease.parsed_fencing_token().unwrap().get(), 1);
}
}
+11
View File
@@ -0,0 +1,11 @@
//! Runtime-independent task contracts.
mod definition;
mod fencing;
mod lease;
mod retry;
pub use definition::{TaskDefinition, TaskKind};
pub use fencing::FencingToken;
pub use lease::{TaskLease, TaskLeaseError};
pub use retry::RetryPolicy;
+12
View File
@@ -0,0 +1,12 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct RetryPolicy {
pub max_attempts: u32,
}
impl Default for RetryPolicy {
fn default() -> Self {
Self { max_attempts: 1 }
}
}