mem engine scheduler/outbox — coverage reconciliation against the seam task's foundation with the one unpinned posture (mem-engine-scheduler-outbox): run_once issues no engine-issued heartbeat in delivery — the handover carries the raw claim deadline and the boxed JobHandle's own heartbeat stays available to the closure (renewal is the consumer's obligation). All other pins (boundary fire determinism, 64-cap catch-up + grid-honest skip-forward, no-double-fire, leadership contention/loss/clean-stop/lease-release, validation + @every grammar matrix, outbox ack/retry curve + derived name + unreachability) verified already present in scheduler.rs/outbox.rs's suite. No production code changed; tests only (+1 + fixture widening, mem suite at 100). Task file: status completed, Notes/Summary filled
This commit is contained in:
1 parent
3eca862f84
commit
47ac6f7739
2 files changed
+111
-9
No files matched your search
@@ -155,6 +155,8 @@ mod tests {
|
||||
struct RecordingDelivery {
|
||||
saw_payload: Option<Vec<u8>>,
|
||||
stamps: Option<(i64, i64, i64, Option<i64>)>,
|
||||
handover_deadline: Option<i64>,
|
||||
manual_heartbeat: bool,
|
||||
outcome: Option<Result<()>>,
|
||||
}
|
||||
|
||||
@@ -163,6 +165,8 @@ mod tests {
|
||||
Self {
|
||||
saw_payload: None,
|
||||
stamps: None,
|
||||
handover_deadline: None,
|
||||
manual_heartbeat: false,
|
||||
outcome: Some(outcome),
|
||||
}
|
||||
}
|
||||
@@ -182,8 +186,18 @@ mod tests {
|
||||
j.backoff_base_s,
|
||||
j.dead_letter_retention_s,
|
||||
));
|
||||
self.handover_deadline = j.claim_expires_at;
|
||||
let beat = self.manual_heartbeat;
|
||||
let outcome = self.outcome.take().unwrap_or(Ok(()));
|
||||
Box::pin(async move { outcome })
|
||||
Box::pin(async move {
|
||||
if beat {
|
||||
assert!(
|
||||
job.heartbeat(600).await.unwrap(),
|
||||
"the boxed JobHandle's own heartbeat stays available to the closure"
|
||||
);
|
||||
}
|
||||
outcome
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +301,37 @@ mod tests {
|
||||
assert!(dead.died_at == 2_000 || dead.died_at > 0);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn run_once_issues_no_engine_heartbeat_in_delivery() {
|
||||
let store = MemStore::new();
|
||||
store.clock.freeze(1_000);
|
||||
let mut ob = outbox(&store, "mail");
|
||||
ob.enqueue(serde_json::json!(1), EnqueueOpts::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let mut delivery = RecordingDelivery::with(Ok(()));
|
||||
assert!(ob.run_once("w1", &mut delivery).await.unwrap());
|
||||
assert_eq!(
|
||||
delivery.handover_deadline,
|
||||
Some(1_060),
|
||||
"handover carries the raw claim deadline — \
|
||||
run_once issues no engine-side renewal for the closure"
|
||||
);
|
||||
assert!(store.state.queues.guard().live.is_empty(), "Ok ⇒ ack");
|
||||
let id = ob
|
||||
.enqueue(serde_json::json!(2), EnqueueOpts::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let mut renewal = RecordingDelivery::with(Ok(()));
|
||||
renewal.manual_heartbeat = true;
|
||||
assert!(ob.run_once("w2", &mut renewal).await.unwrap());
|
||||
assert!(
|
||||
store.state.queues.guard().live.is_empty(),
|
||||
"renewal inside the window is the closure's obligation — \
|
||||
and the boxed handle's heartbeat carries it ({id} acked)"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn empty_worker_id_is_invalid() {
|
||||
let store = MemStore::new();
|
||||
|
||||
Reference in new issue
Block a user