Skip to content

Commit 7fe243a

Browse files
authored
Return 409 on duplicate message insert (#1466)
Ensure that we don't return a 5xx when user attempts to insert a duplicate message (i.e., due to msg-uid conflict) Fixes #1454
1 parent 034a6a4 commit 7fe243a

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

server/svix-server/src/v1/endpoints/message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::{
3030
},
3131
},
3232
db::models::{application, message, messagecontent},
33-
error::{Error, HttpError, Result},
33+
error::{http_error_on_conflict, Error, HttpError, Result},
3434
queue::{MessageTaskBatch, TaskQueueProducer},
3535
v1::utils::{
3636
filter_and_paginate_time_limited, openapi_tag, validation_error, ApplicationMsgPath,
@@ -360,7 +360,7 @@ pub(crate) async fn create_message_inner(
360360
let (msg, msg_content) = db
361361
.transaction(|txn| {
362362
async move {
363-
let msg = msg.insert(txn).await?;
363+
let msg = msg.insert(txn).await.map_err(http_error_on_conflict)?;
364364
let msg_content = messagecontent::ActiveModel::new(msg.id.clone(), payload);
365365
let msg_content = msg_content.insert(txn).await?;
366366
Ok((msg, msg_content))

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
use chrono::{Duration, Utc};
55
use reqwest::StatusCode;
66
use sea_orm::{sea_query::Expr, ColumnTrait, EntityTrait, QueryFilter};
7+
use serde::de::IgnoredAny;
78
use svix_server::{
9+
core::types::{EventTypeName, MessageUid},
810
db::models::messagecontent,
911
expired_message_cleaner,
1012
v1::{
1113
endpoints::{
1214
attempt::MessageAttemptOut,
13-
message::{MessageOut, RawPayload},
15+
message::{MessageIn, MessageOut, RawPayload},
1416
},
1517
utils::ListResponse,
1618
},
@@ -472,3 +474,44 @@ async fn test_expunge_message_payload() {
472474

473475
assert_eq!(msg.payload.0.get(), r#"{"expired":true}"#);
474476
}
477+
478+
#[tokio::test]
479+
async fn test_message_conflict() {
480+
let (client, _jh) = start_svix_server().await;
481+
482+
let app_id = create_test_app(&client, "v1MessageCRTestApp")
483+
.await
484+
.unwrap()
485+
.id;
486+
487+
let _endp_id = create_test_endpoint(&client, &app_id, "http://localhost:2/bad/url/")
488+
.await
489+
.unwrap()
490+
.id;
491+
492+
let msg_in = MessageIn {
493+
event_type: EventTypeName("user.signup".to_owned()),
494+
payload: RawPayload::from_string(serde_json::json!({"test": "value"}).to_string()).unwrap(),
495+
payload_retention_period: 5,
496+
channels: None,
497+
uid: Some(MessageUid("test1".to_owned())),
498+
};
499+
500+
let _: MessageOut = client
501+
.post(
502+
&format!("api/v1/app/{}/msg/", &app_id),
503+
msg_in.clone(),
504+
StatusCode::ACCEPTED,
505+
)
506+
.await
507+
.unwrap();
508+
509+
let _: IgnoredAny = client
510+
.post(
511+
&format!("api/v1/app/{}/msg/", &app_id),
512+
msg_in,
513+
StatusCode::CONFLICT,
514+
)
515+
.await
516+
.unwrap();
517+
}

0 commit comments

Comments
 (0)