feat(webhooks): implement automatic retries for failed webhook deliveries using scheduler (#3842)

This commit is contained in:
Sanchith Hegde
2024-03-04 12:01:02 +05:30
committed by GitHub
parent fee0663d66
commit 5bb67c7dcc
27 changed files with 965 additions and 215 deletions

View File

@ -342,24 +342,48 @@ pub fn get_pm_schedule_time(
}
}
/// Get the delay based on the retry count
fn get_delay<'a>(
pub fn get_outgoing_webhook_retry_schedule_time(
mapping: process_data::OutgoingWebhookRetryProcessTrackerMapping,
merchant_name: &str,
retry_count: i32,
mut array: impl Iterator<Item = (&'a i32, &'a i32)>,
) -> Option<i32> {
match array.next() {
Some(ele) => {
let v = retry_count - ele.0;
if v <= 0 {
Some(*ele.1)
} else {
get_delay(v, array)
}
}
None => None,
let retry_mapping = match mapping.custom_merchant_mapping.get(merchant_name) {
Some(map) => map.clone(),
None => mapping.default_mapping,
};
// For first try, get the `start_after` time
if retry_count == 0 {
Some(retry_mapping.start_after)
} else {
get_delay(
retry_count,
retry_mapping
.count
.iter()
.zip(retry_mapping.frequency.iter()),
)
}
}
/// Get the delay based on the retry count
fn get_delay<'a>(retry_count: i32, array: impl Iterator<Item = (&'a i32, &'a i32)>) -> Option<i32> {
// Preferably, fix this by using unsigned ints
if retry_count <= 0 {
return None;
}
let mut cumulative_count = 0;
for (&count, &frequency) in array {
cumulative_count += count;
if cumulative_count >= retry_count {
return Some(frequency);
}
}
None
}
pub(crate) async fn lock_acquire_release<T, F, Fut>(
state: &T,
settings: &SchedulerSettings,
@ -392,3 +416,38 @@ where
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_delay() {
let count = [10, 5, 3, 2];
let frequency = [300, 600, 1800, 3600];
let retry_counts_and_expected_delays = [
(-4, None),
(-2, None),
(0, None),
(4, Some(300)),
(7, Some(300)),
(10, Some(300)),
(12, Some(600)),
(16, Some(1800)),
(18, Some(1800)),
(20, Some(3600)),
(24, None),
(30, None),
];
for (retry_count, expected_delay) in retry_counts_and_expected_delays {
let delay = get_delay(retry_count, count.iter().zip(frequency.iter()));
assert_eq!(
delay, expected_delay,
"Delay and expected delay differ for `retry_count` = {retry_count}"
);
}
}
}