commit 99521657e064ffb74bde06282d604a0ebd74634b
parent 0e9a504cd122430320ed971f2b1cddabf650c342
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 13:42:47 +0000
provider: add retry classification and scheduling
Diffstat:
2 files changed, 67 insertions(+), 0 deletions(-)
diff --git a/src/hyf_provider/jev_retry.mojo b/src/hyf_provider/jev_retry.mojo
@@ -0,0 +1,50 @@
+
+
+@fieldwise_init
+struct RetryPolicy(Copyable, Movable):
+ var max_retries: Int
+ var base_delay_ms: Int
+ var max_delay_ms: Int
+ var budget_ms: Int
+
+
+def retry_policy(
+ max_retries: Int, base_delay_ms: Int, max_delay_ms: Int, budget_ms: Int
+) raises -> RetryPolicy:
+ if max_retries < 0:
+ raise Error("max_retries must be non-negative")
+ if base_delay_ms <= 0:
+ raise Error("base_delay_ms must be positive")
+ if max_delay_ms < base_delay_ms:
+ raise Error("max_delay_ms must be at least base_delay_ms")
+ if budget_ms <= 0:
+ raise Error("budget_ms must be positive")
+ return RetryPolicy(
+ max_retries=max_retries,
+ base_delay_ms=base_delay_ms,
+ max_delay_ms=max_delay_ms,
+ budget_ms=budget_ms,
+ )
+
+
+def retry_delay_ms(policy: RetryPolicy, attempt: Int) -> Int:
+ var delay = policy.base_delay_ms
+ for _ in range(attempt):
+ delay *= 2
+ if delay >= policy.max_delay_ms:
+ return policy.max_delay_ms
+ if delay > policy.max_delay_ms:
+ return policy.max_delay_ms
+ return delay
+
+
+def should_retry(
+ policy: RetryPolicy, attempt: Int, elapsed_ms: Int, retryable: Bool
+) -> Bool:
+ if not retryable:
+ return False
+ if attempt >= policy.max_retries:
+ return False
+ if elapsed_ms + retry_delay_ms(policy, attempt) >= policy.budget_ms:
+ return False
+ return True
diff --git a/tests/test_jev.mojo b/tests/test_jev.mojo
@@ -204,3 +204,20 @@ def test_data_minimized_state_projection() raises:
huge += "xxxxxxxxxx"
with assert_raises():
_ = minimal_state(huge, "", "")
+
+
+from hyf_provider.jev_retry import retry_delay_ms, retry_policy, should_retry
+
+
+def test_retry_classification_and_bounded_scheduling() raises:
+ var policy = retry_policy(3, 100, 500, 1000)
+ assert_equal(retry_delay_ms(policy, 0), 100)
+ assert_equal(retry_delay_ms(policy, 1), 200)
+ assert_equal(retry_delay_ms(policy, 2), 400)
+ assert_equal(retry_delay_ms(policy, 5), 500)
+ assert_true(should_retry(policy, 0, 0, True))
+ assert_true(not should_retry(policy, 0, 0, False))
+ assert_true(not should_retry(policy, 3, 0, True))
+ assert_true(not should_retry(policy, 0, 950, True))
+ with assert_raises():
+ _ = retry_policy(1, 0, 10, 100)