cufflink_native/
deadline.rs1use cufflink_types::ext::CallContext;
2use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
3
4const FAR_FUTURE: Duration = Duration::from_secs(86_400 * 365 * 30);
6
7pub trait CallDeadline {
9 fn deadline(&self) -> Instant;
12}
13
14impl CallDeadline for CallContext {
15 fn deadline(&self) -> Instant {
16 let now = SystemTime::now()
17 .duration_since(UNIX_EPOCH)
18 .unwrap_or_default();
19 Instant::now()
20 + Duration::from_millis(self.deadline_ms)
21 .saturating_sub(now)
22 .min(FAR_FUTURE)
23 }
24}
25
26#[cfg(test)]
27pub(crate) mod tests {
28 use super::*;
29 use cufflink_types::ext::CallerService;
30
31 pub(crate) fn context_until(deadline_ms: u64) -> CallContext {
32 CallContext {
33 tenant: "harbor".into(),
34 service: CallerService {
35 name: "reports-service".into(),
36 version: 3,
37 },
38 auth: None,
39 deadline_ms,
40 }
41 }
42
43 pub(crate) fn in_ms(ms: u64) -> u64 {
44 u64::try_from(
45 (SystemTime::now() + Duration::from_millis(ms))
46 .duration_since(UNIX_EPOCH)
47 .expect("clock")
48 .as_millis(),
49 )
50 .expect("millis")
51 }
52
53 #[test]
54 fn the_deadline_is_when_the_caller_stops_waiting() {
55 let before = Instant::now();
56 let deadline = context_until(in_ms(1_000)).deadline();
57 assert!(
58 deadline > before + Duration::from_millis(900)
59 && deadline <= Instant::now() + Duration::from_millis(1_000),
60 "{:?}",
61 deadline - before
62 );
63 }
64
65 #[test]
66 fn a_passed_deadline_is_now_and_a_far_one_is_bounded() {
67 assert!(context_until(0).deadline() <= Instant::now());
68 assert!(context_until(in_ms(0) - 5_000).deadline() <= Instant::now());
69 assert!(context_until(u64::MAX).deadline() <= Instant::now() + FAR_FUTURE);
70 }
71}