fix(job-registry): fix error handling*
This commit is contained in:
@@ -608,11 +608,11 @@ impl JobHandler for StorageUsageService {
|
|||||||
async fn run(&self, _args: &JobRunArgs) -> JobOutcome {
|
async fn run(&self, _args: &JobRunArgs) -> JobOutcome {
|
||||||
let drives = match self.update_all_drives_storage_usage().await {
|
let drives = match self.update_all_drives_storage_usage().await {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => return JobOutcome::Err(format!("drive reconciliation failed: {e}")),
|
Err(e) => return JobOutcome::err(format!("drive reconciliation failed: {e}")),
|
||||||
};
|
};
|
||||||
let users = match self.update_all_users_storage_usage().await {
|
let users = match self.update_all_users_storage_usage().await {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => return JobOutcome::Err(format!("user reconciliation failed: {e}")),
|
Err(e) => return JobOutcome::err(format!("user reconciliation failed: {e}")),
|
||||||
};
|
};
|
||||||
JobOutcome::ok_with(
|
JobOutcome::ok_with(
|
||||||
drives + users,
|
drives + users,
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ pub(super) async fn dispatch(name: &str, entry: Arc<JobEntry>, args: &JobRunArgs
|
|||||||
// yield points may run to completion in the background.
|
// yield points may run to completion in the background.
|
||||||
// We still record timeout and release the permit.
|
// We still record timeout and release the permit.
|
||||||
(
|
(
|
||||||
JobOutcome::Err(format!("wall-clock timeout of {:?} exceeded", dur)),
|
JobOutcome::err(format!("wall-clock timeout of {:?} exceeded", dur)),
|
||||||
Some(ErrCause::Timeout),
|
Some(ErrCause::Timeout),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -249,12 +249,12 @@ fn translate_join(
|
|||||||
"unknown panic payload".to_string()
|
"unknown panic payload".to_string()
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
JobOutcome::Err(format!("handler panicked: {msg}")),
|
JobOutcome::err(format!("handler panicked: {msg}")),
|
||||||
Some(ErrCause::Panicked),
|
Some(ErrCause::Panicked),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(join_err) => (
|
Err(join_err) => (
|
||||||
JobOutcome::Err(format!("task cancelled: {join_err}")),
|
JobOutcome::err(format!("task cancelled: {join_err}")),
|
||||||
Some(ErrCause::Handler),
|
Some(ErrCause::Handler),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -278,7 +278,7 @@ fn log_outcome(name: &str, outcome: &JobOutcome, cause: Option<ErrCause>, elapse
|
|||||||
name,
|
name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
JobOutcome::Err(msg) => {
|
JobOutcome::Err { message: msg } => {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
target: "oxicloud::scheduler",
|
target: "oxicloud::scheduler",
|
||||||
event = "job.run",
|
event = "job.run",
|
||||||
@@ -342,7 +342,7 @@ mod tests {
|
|||||||
let (outcome, cause) = translate_join(join.await);
|
let (outcome, cause) = translate_join(join.await);
|
||||||
assert!(!outcome.is_ok());
|
assert!(!outcome.is_ok());
|
||||||
assert_eq!(cause, Some(ErrCause::Panicked));
|
assert_eq!(cause, Some(ErrCause::Panicked));
|
||||||
if let JobOutcome::Err(msg) = outcome {
|
if let JobOutcome::Err { message: msg } = outcome {
|
||||||
assert!(msg.contains("panicked"), "expected panic marker in: {msg}");
|
assert!(msg.contains("panicked"), "expected panic marker in: {msg}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,12 @@ pub enum JobOutcome {
|
|||||||
#[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
|
#[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
|
||||||
extra: serde_json::Value,
|
extra: serde_json::Value,
|
||||||
},
|
},
|
||||||
Err(String),
|
/// `Err` is a struct variant (not tuple-newtype) so it composes
|
||||||
|
/// with `#[serde(tag = "outcome")]`. Serde's internal tagging
|
||||||
|
/// refuses to serialise a tuple variant wrapping a bare String
|
||||||
|
/// — the tag has nowhere to live. The struct form `{ message }`
|
||||||
|
/// lets serde emit `{"outcome":"err","message":"..."}` cleanly.
|
||||||
|
Err { message: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JobOutcome {
|
impl JobOutcome {
|
||||||
@@ -69,11 +74,19 @@ impl JobOutcome {
|
|||||||
JobOutcome::Ok { count, extra }
|
JobOutcome::Ok { count, extra }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience constructor for `Err` — call-site ergonomics
|
||||||
|
/// match the retired tuple form.
|
||||||
|
pub fn err(message: impl Into<String>) -> Self {
|
||||||
|
JobOutcome::Err {
|
||||||
|
message: message.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Terse discriminant for logs / metrics: `"ok"` | `"err"`.
|
/// Terse discriminant for logs / metrics: `"ok"` | `"err"`.
|
||||||
pub fn kind(&self) -> &'static str {
|
pub fn kind(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
JobOutcome::Ok { .. } => "ok",
|
JobOutcome::Ok { .. } => "ok",
|
||||||
JobOutcome::Err(_) => "err",
|
JobOutcome::Err { .. } => "err",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +138,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn joboutcome_kind_label() {
|
fn joboutcome_kind_label() {
|
||||||
assert_eq!(JobOutcome::ok(0).kind(), "ok");
|
assert_eq!(JobOutcome::ok(0).kind(), "ok");
|
||||||
assert_eq!(JobOutcome::Err("boom".into()).kind(), "err");
|
assert_eq!(JobOutcome::err("boom").kind(), "err");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -3170,7 +3170,7 @@ impl crate::infrastructure::scheduler::JobHandler for DedupService {
|
|||||||
items,
|
items,
|
||||||
serde_json::json!({ "bytes_reclaimed": bytes, "forced": args.force }),
|
serde_json::json!({ "bytes_reclaimed": bytes, "forced": args.force }),
|
||||||
),
|
),
|
||||||
Err(e) => JobOutcome::Err(format!("dedup GC failed: {e}")),
|
Err(e) => JobOutcome::err(format!("dedup GC failed: {e}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ impl JobHandler for GrantCleanupService {
|
|||||||
"forced": args.force,
|
"forced": args.force,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
Err(e) => JobOutcome::Err(format!("grant cleanup failed: {e}")),
|
Err(e) => JobOutcome::err(format!("grant cleanup failed: {e}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ impl JobHandler for TrashCleanupService {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(e) => JobOutcome::Err(format!("trash cleanup failed: {e}")),
|
Err(e) => JobOutcome::err(format!("trash cleanup failed: {e}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user