refactor(internal): allow an injectable sleep in the retry utility - #19425
Conversation
Codeowners resolved as |
Circular import analysis
|
🎉 All green!🧪 All tests passed 🔄 Datadog auto-retried 1 job - 1 passed on retry 🔗 Commit SHA: 20d09f7 | Docs | Datadog PR Page | Give us feedback! |
brettlangdon
left a comment
There was a problem hiding this comment.
nit about one of the tests, but otherwise lgtm
|
Interesting idea. Perhaps we can evolve the decorator to return a callable object that can be |
@P403n1x87 ok for a follow-up PR? |
BenchmarksBenchmark execution time: 2026-07-31 14:50:26 Comparing candidate commit 20d09f7 in PR branch Found 0 performance improvements and 7 performance regressions! Performance is the same for 610 metrics, 9 unstable metrics. scenario:httppropagationinject-ids_only
scenario:iastaspects-repr_aspect
scenario:iastaspects-translate_aspect
scenario:iastaspectsospath-ospathbasename_aspect
scenario:span-start
scenario:telemetryaddmetric-1-count-metric-1-times
scenario:tracer-small
|
59fe269
into
main
…19425) ## Description Adds an optional `sleep_func` parameter to `ddtrace/internal/utils/retry.py`, used for the initial wait and for each backoff between attempts. It defaults to `time.sleep`, so every existing caller behaves identically — the change is purely additive. The motivation is background-thread callers: `time.sleep` cannot be interrupted, so a service shutting down mid-backoff has to wait out the remaining delay. Passing an interruptible wait such as `threading.Event.wait` lets the caller abandon the backoff immediately. Split out of #19331 at review request. The Feature Flagging agentless poller is the first consumer and uses it to make shutdown prompt instead of waiting out up to ~30s of backoff. ## Testing Four tests added to `tests/internal/test_utils_retry.py`: - `sleep_func` receives the initial wait and every backoff delay, in order. - No backoff wait happens when the first attempt is accepted. - The default remains bound to `time.sleep` for callers that do not pass it. - An event-style wait can stop the remaining attempts (the interruptible-shutdown case). `tests/internal/test_utils_retry.py` passes in full (9 tests). ## Risks None expected. The parameter is optional and defaults to the previous behavior, and no existing caller passes it. ## Additional Notes No release note: this is an internal utility with no customer-visible behavior change, so `changelog/no-changelog` is applied. Co-authored-by: pavlo.khrebto <pavlo.khrebto@datadoghq.com>
Description
Adds an optional
sleep_funcparameter toddtrace/internal/utils/retry.py, used for the initial wait and for each backoff between attempts. It defaults totime.sleep, so every existing caller behaves identically — the change is purely additive.The motivation is background-thread callers:
time.sleepcannot be interrupted, so a service shutting down mid-backoff has to wait out the remaining delay. Passing an interruptible wait such asthreading.Event.waitlets the caller abandon the backoff immediately.Split out of #19331 at review request. The Feature Flagging agentless poller is the first consumer and uses it to make shutdown prompt instead of waiting out up to ~30s of backoff.
Testing
Four tests added to
tests/internal/test_utils_retry.py:sleep_funcreceives the initial wait and every backoff delay, in order.time.sleepfor callers that do not pass it.tests/internal/test_utils_retry.pypasses in full (9 tests).Risks
None expected. The parameter is optional and defaults to the previous behavior, and no existing caller passes it.
Additional Notes
No release note: this is an internal utility with no customer-visible behavior change, so
changelog/no-changelogis applied.