Skip to content

Commit 464abe1

Browse files
jaymellsvix-james
authored andcommitted
Recover Failed Webhooks use configurable until
Our API docs support an optional `until` parameter. This adds support for it in the backend.
1 parent 4d5ec73 commit 464abe1

File tree

5 files changed

+23
-10
lines changed

5 files changed

+23
-10
lines changed

server/openapi.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,6 +1985,11 @@
19851985
"since": {
19861986
"format": "date-time",
19871987
"type": "string"
1988+
},
1989+
"until": {
1990+
"format": "date-time",
1991+
"nullable": true,
1992+
"type": "string"
19881993
}
19891994
},
19901995
"required": [

server/svix-server/src/v1/endpoints/endpoint/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ pub struct EndpointSecretOut {
542542
#[serde(rename_all = "camelCase")]
543543
pub struct RecoverIn {
544544
pub since: DateTime<Utc>,
545+
pub until: Option<DateTime<Utc>>,
545546
}
546547

547548
fn endpoint_headers_example() -> HashMap<&'static str, &'static str> {

server/svix-server/src/v1/endpoints/endpoint/recovery.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use axum::extract::{Path, State};
2-
use chrono::{DateTime, Utc};
2+
use chrono::{DateTime, Duration, Utc};
33
use schemars::JsonSchema;
44
use sea_orm::{entity::prelude::*, QueryOrder, QuerySelect};
55
use serde::{Deserialize, Serialize};
@@ -27,6 +27,7 @@ async fn bulk_recover_failed_messages(
2727
app: application::Model,
2828
endp: endpoint::Model,
2929
since: DateTime<Utc>,
30+
until: DateTime<Utc>,
3031
) -> Result<()> {
3132
const RECOVER_LIMIT: u64 = 10_000;
3233
const BATCH_SIZE: u64 = 100;
@@ -36,6 +37,7 @@ async fn bulk_recover_failed_messages(
3637
loop {
3738
let mut query = messagedestination::Entity::secure_find_by_endpoint(endp.id.clone())
3839
.filter(messagedestination::Column::Id.gte(MessageEndpointId::start_id(since)))
40+
.filter(messagedestination::Column::Id.lt(MessageEndpointId::start_id(until)))
3941
.filter(messagedestination::Column::Status.eq(MessageStatus::Fail))
4042
.order_by_asc(messagedestination::Column::Id)
4143
.limit(RECOVER_LIMIT);
@@ -99,16 +101,20 @@ pub(super) async fn recover_failed_webhooks(
99101
}): State<AppState>,
100102
Path(ApplicationEndpointPath { endpoint_id, .. }): Path<ApplicationEndpointPath>,
101103
permissions::Application { app }: permissions::Application,
102-
ValidatedJson(data): ValidatedJson<RecoverIn>,
104+
ValidatedJson(RecoverIn { since, until }): ValidatedJson<RecoverIn>,
103105
) -> Result<JsonStatus<202, RecoverOut>> {
106+
let until = until.unwrap_or_else(Utc::now);
107+
104108
// Add five minutes so that people can easily just do `now() - two_weeks` without having to worry about clock sync
105-
let timeframe = chrono::Duration::days(14);
106-
let timeframe = timeframe + chrono::Duration::minutes(5);
109+
let max_timeframe = Duration::days(14) + Duration::minutes(5);
107110

108-
if data.since < Utc::now() - timeframe {
111+
if since < until - max_timeframe {
109112
return Err(HttpError::unprocessable_entity(vec![ValidationErrorItem {
110113
loc: vec!["body".to_owned(), "since".to_owned()],
111-
msg: "Cannot recover messages more than 14 days old.".to_owned(),
114+
msg: format!(
115+
"Cannot recover more than {} days of messages",
116+
max_timeframe.num_days()
117+
),
112118
ty: "value_error".to_owned(),
113119
}])
114120
.into());
@@ -121,9 +127,9 @@ pub(super) async fn recover_failed_webhooks(
121127

122128
let db = db.clone();
123129
let queue_tx = queue_tx.clone();
124-
tokio::spawn(
125-
async move { bulk_recover_failed_messages(db, queue_tx, app, endp, data.since).await },
126-
);
130+
tokio::spawn(async move {
131+
bulk_recover_failed_messages(db, queue_tx, app, endp, since, until).await
132+
});
127133

128134
Ok(JsonStatus(RecoverOut {
129135
id: QueueBackgroundTaskId::new(None, None),

server/svix-server/tests/it/e2e_endpoint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ async fn test_recovery_should_fail_if_start_time_too_old() {
979979
&format!("api/v1/app/{app_id}/endpoint/{endp_id}/recover/"),
980980
RecoverIn {
981981
since: Utc::now() - chrono::Duration::weeks(3),
982+
until: None,
982983
},
983984
StatusCode::UNPROCESSABLE_ENTITY,
984985
)

server/svix-server/tests/it/utils/common_calls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ pub async fn common_test_list<
368368

369369
pub async fn recover_webhooks(client: &TestClient, since: DateTime<Utc>, url: &str) {
370370
client
371-
.post_without_response(url, RecoverIn { since }, StatusCode::ACCEPTED)
371+
.post_without_response(url, RecoverIn { since, until: None }, StatusCode::ACCEPTED)
372372
.await
373373
.unwrap();
374374
}

0 commit comments

Comments
 (0)