refactor(revenue_recovery): Add configs for calculate job (#9106)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Aniket Burman <aniket.burman@Aniket-Burman-JDXHW2PH34.local>
Co-authored-by: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com>
This commit is contained in:
AdityaWNL
2025-08-29 20:48:55 +05:30
committed by GitHub
parent 4a60b07954
commit 8ce36a2fd5
8 changed files with 63 additions and 16 deletions

View File

@ -1203,7 +1203,10 @@ max_retries_per_day = 20
max_retry_count_for_thirty_day = 20 max_retry_count_for_thirty_day = 20
[revenue_recovery.recovery_timestamp] # Timestamp configuration for Revenue Recovery [revenue_recovery.recovery_timestamp] # Timestamp configuration for Revenue Recovery
initial_timestamp_in_hours = 1 # number of hours added to start time for Decider service of Revenue Recovery initial_timestamp_in_seconds = 3600 # number of seconds added to start time for Decider service of Revenue Recovery
job_schedule_buffer_time_in_seconds = 3600 # buffer time in seconds to schedule the job for Revenue Recovery
reopen_workflow_buffer_time_in_seconds = 3600 # time in seconds to be added in scheduling for calculate workflow
max_random_schedule_delay_in_seconds = 300 # max random delay in seconds to schedule the payment for Revenue Recovery
[clone_connector_allowlist] [clone_connector_allowlist]
merchant_ids = "merchant_ids" # Comma-separated list of allowed merchant IDs merchant_ids = "merchant_ids" # Comma-separated list of allowed merchant IDs

View File

@ -410,7 +410,10 @@ max_retries_per_day = 20
max_retry_count_for_thirty_day = 20 max_retry_count_for_thirty_day = 20
[revenue_recovery.recovery_timestamp] # Timestamp configuration for Revenue Recovery [revenue_recovery.recovery_timestamp] # Timestamp configuration for Revenue Recovery
initial_timestamp_in_hours = 1 # number of hours added to start time for Decider service of Revenue Recovery initial_timestamp_in_seconds = 3600 # number of seconds added to start time for Decider service of Revenue Recovery
job_schedule_buffer_time_in_seconds = 3600 # time in seconds to be added in schedule time as a buffer
reopen_workflow_buffer_time_in_seconds = 3600 # time in seconds to be added in scheduling for calculate workflow
max_random_schedule_delay_in_seconds = 300 # max random delay in seconds to schedule the payment for Revenue Recovery
[chat] [chat]
enabled = false # Enable or disable chat features enabled = false # Enable or disable chat features

View File

@ -1302,7 +1302,10 @@ retry_algorithm_type = "cascading"
redis_ttl_in_seconds=3888000 redis_ttl_in_seconds=3888000
[revenue_recovery.recovery_timestamp] [revenue_recovery.recovery_timestamp]
initial_timestamp_in_hours = 1 initial_timestamp_in_seconds = 3600
job_schedule_buffer_time_in_seconds = 3600
reopen_workflow_buffer_time_in_seconds = 3600
max_random_schedule_delay_in_seconds = 300
[revenue_recovery.card_config.amex] [revenue_recovery.card_config.amex]
max_retries_per_day = 20 max_retries_per_day = 20

View File

@ -1219,6 +1219,11 @@ max_retry_count_for_thirty_day = 20
max_retries_per_day = 20 max_retries_per_day = 20
max_retry_count_for_thirty_day = 20 max_retry_count_for_thirty_day = 20
[revenue_recovery.recovery_timestamp] # Timestamp configuration for Revenue Recovery
initial_timestamp_in_seconds = 3600 # number of seconds added to start time for Decider service of Revenue Recovery
job_schedule_buffer_time_in_seconds = 3600 # time in seconds to be added in schedule time as a buffer
reopen_workflow_buffer_time_in_seconds = 60 # time in seconds to be added in scheduling for calculate workflow
[clone_connector_allowlist] [clone_connector_allowlist]
merchant_ids = "merchant_123, merchant_234" # Comma-separated list of allowed merchant IDs merchant_ids = "merchant_123, merchant_234" # Comma-separated list of allowed merchant IDs
connector_names = "stripe, adyen" # Comma-separated list of allowed connector names connector_names = "stripe, adyen" # Comma-separated list of allowed connector names

View File

@ -56,8 +56,9 @@ pub async fn upsert_calculate_pcr_task(
// Create process tracker ID in the format: CALCULATE_WORKFLOW_{payment_intent_id} // Create process tracker ID in the format: CALCULATE_WORKFLOW_{payment_intent_id}
let process_tracker_id = format!("{runner}_{task}_{}", payment_id.get_string_repr()); let process_tracker_id = format!("{runner}_{task}_{}", payment_id.get_string_repr());
// Set scheduled time to 1 hour from now // Scheduled time is now because this will be the first entry in
let schedule_time = common_utils::date_time::now() + time::Duration::hours(1); // process tracker and we dont want to wait
let schedule_time = common_utils::date_time::now();
let payment_attempt_id = payment_attempt_id let payment_attempt_id = payment_attempt_id
.ok_or(error_stack::report!( .ok_or(error_stack::report!(
@ -580,7 +581,13 @@ pub async fn perform_calculate_workflow(
update_calculate_job_schedule_time( update_calculate_job_schedule_time(
db, db,
process, process,
time::Duration::minutes(15), time::Duration::seconds(
state
.conf
.revenue_recovery
.recovery_timestamp
.job_schedule_buffer_time_in_seconds,
),
scheduled_token.scheduled_at, scheduled_token.scheduled_at,
&connector_customer_id, &connector_customer_id,
) )
@ -607,7 +614,13 @@ pub async fn perform_calculate_workflow(
update_calculate_job_schedule_time( update_calculate_job_schedule_time(
db, db,
process, process,
time::Duration::minutes(15), time::Duration::seconds(
state
.conf
.revenue_recovery
.recovery_timestamp
.job_schedule_buffer_time_in_seconds,
),
Some(common_utils::date_time::now()), Some(common_utils::date_time::now()),
&connector_customer_id, &connector_customer_id,
) )

View File

@ -1180,7 +1180,14 @@ pub async fn reopen_calculate_workflow_on_payment_failure(
// 3. Set business status to QUEUED // 3. Set business status to QUEUED
// 4. Schedule for immediate execution // 4. Schedule for immediate execution
let new_retry_count = process.retry_count + 1; let new_retry_count = process.retry_count + 1;
let new_schedule_time = common_utils::date_time::now() + time::Duration::hours(1); let new_schedule_time = common_utils::date_time::now()
+ time::Duration::seconds(
state
.conf
.revenue_recovery
.recovery_timestamp
.reopen_workflow_buffer_time_in_seconds,
);
let pt_update = storage::ProcessTrackerUpdate::Update { let pt_update = storage::ProcessTrackerUpdate::Update {
name: Some(task.to_string()), name: Some(task.to_string()),

View File

@ -77,13 +77,19 @@ pub struct RevenueRecoverySettings {
#[derive(Debug, serde::Deserialize, Clone)] #[derive(Debug, serde::Deserialize, Clone)]
pub struct RecoveryTimestamp { pub struct RecoveryTimestamp {
pub initial_timestamp_in_hours: i64, pub initial_timestamp_in_seconds: i64,
pub job_schedule_buffer_time_in_seconds: i64,
pub reopen_workflow_buffer_time_in_seconds: i64,
pub max_random_schedule_delay_in_seconds: i64,
} }
impl Default for RecoveryTimestamp { impl Default for RecoveryTimestamp {
fn default() -> Self { fn default() -> Self {
Self { Self {
initial_timestamp_in_hours: 1, initial_timestamp_in_seconds: 1,
job_schedule_buffer_time_in_seconds: 15,
reopen_workflow_buffer_time_in_seconds: 60,
max_random_schedule_delay_in_seconds: 300,
} }
} }
} }

View File

@ -324,9 +324,9 @@ pub(crate) async fn get_schedule_time_for_smart_retry(
let start_time_primitive = payment_intent.created_at; let start_time_primitive = payment_intent.created_at;
let recovery_timestamp_config = &state.conf.revenue_recovery.recovery_timestamp; let recovery_timestamp_config = &state.conf.revenue_recovery.recovery_timestamp;
let modified_start_time_primitive = start_time_primitive.saturating_add(time::Duration::hours( let modified_start_time_primitive = start_time_primitive.saturating_add(
recovery_timestamp_config.initial_timestamp_in_hours, time::Duration::seconds(recovery_timestamp_config.initial_timestamp_in_seconds),
)); );
let start_time_proto = date_time::convert_to_prost_timestamp(modified_start_time_primitive); let start_time_proto = date_time::convert_to_prost_timestamp(modified_start_time_primitive);
@ -550,7 +550,8 @@ pub async fn get_token_with_schedule_time_based_on_retry_algorithm_type(
.change_context(errors::ProcessTrackerError::EApiErrorResponse)?; .change_context(errors::ProcessTrackerError::EApiErrorResponse)?;
} }
} }
let delayed_schedule_time = scheduled_time.map(add_random_delay_to_schedule_time); let delayed_schedule_time =
scheduled_time.map(|time| add_random_delay_to_schedule_time(state, time));
Ok(delayed_schedule_time) Ok(delayed_schedule_time)
} }
@ -776,10 +777,16 @@ pub async fn check_hard_decline(
#[cfg(feature = "v2")] #[cfg(feature = "v2")]
pub fn add_random_delay_to_schedule_time( pub fn add_random_delay_to_schedule_time(
state: &SessionState,
schedule_time: time::PrimitiveDateTime, schedule_time: time::PrimitiveDateTime,
) -> time::PrimitiveDateTime { ) -> time::PrimitiveDateTime {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let random_secs = rng.gen_range(1..=3600); let delay_limit = state
.conf
.revenue_recovery
.recovery_timestamp
.max_random_schedule_delay_in_seconds;
let random_secs = rng.gen_range(1..=delay_limit);
logger::info!("Adding random delay of {random_secs} seconds to schedule time"); logger::info!("Adding random delay of {random_secs} seconds to schedule time");
schedule_time + time::Duration::seconds(random_secs) schedule_time + time::Duration::seconds(random_secs)
} }