Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/13-dlr-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ A terminal receipt remains in `sendium_dlr.dlr_message` while HTTP or SMPP deliv

The V1 retention thresholds are fixed application behavior, not environment settings:

| State | Eligible for cleanup after |
| DLR lifecycle state | Eligible for cleanup after |
| :--- | :--- |
| Provider message correlation | 3 days |
| Message waiting for provider receipt | 7 days from creation |
| Pending or failed terminal delivery | 7 days from resolution |
| Waiting for final provider DLR | 7 days from provider acceptance |
| Waiting to forward final DLR to the client | 7 days from receiving the final provider outcome |

Waiting for a final provider DLR includes both the message row and its provider-message correlations. These are separate database records with separate cleanup conditions, but both use the same seven-day threshold. After Sendium records a final provider DLR or provider rejection, it removes the correlations and retains the message row while forwarding the outcome to the HTTP or SMPP client. Successful client delivery deletes the row immediately; pending or failed forwarding remains eligible for cleanup seven days after provider resolution.

Cleanup is triggered by storage activity and runs no more than once per hour. These values are therefore eligibility thresholds, not exact physical deletion deadlines: idle records can remain in the database longer, and an active deployment can retain newly eligible state until the next cleanup pass. A provider receipt cannot be matched after its correlation has been removed. Making the thresholds or cleanup schedule configurable is outside the V1 storage replacement.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ WITH due AS (

private static final String DELETE_EXPIRED_CORRELATIONS_SQL = """
DELETE FROM sendium_dlr.provider_correlation
WHERE created_at < CURRENT_TIMESTAMP - INTERVAL '3 days'
WHERE created_at < CURRENT_TIMESTAMP - INTERVAL '7 days'
""";

private static final String DELETE_EXPIRED_MESSAGES_SQL = """
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,22 +405,19 @@ void retentionUsesCreatedAtWhileWaitingAndResolvedAtAfterResolution() throws SQL
}

@Test
void correlationRetentionRemainsThreeDays() throws SQLException {
void correlationRetentionMatchesWaitingMessageRetention() throws SQLException {
MessageState state = state(MessageState.DeliveryChannel.HTTP, "system", "https://example.test/dlr");
acceptProviderMessage(state, "old-correlation");
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("""
UPDATE sendium_dlr.provider_correlation
SET created_at = CURRENT_TIMESTAMP - INTERVAL '4 days'
WHERE provider_name = ? AND provider_message_id = ?
""")) {
statement.setString(1, PROVIDER);
statement.setString(2, "old-correlation");
statement.executeUpdate();
}
setCorrelationCreatedAt("old-correlation", "CURRENT_TIMESTAMP - INTERVAL '4 days'");

PostgresqlDlrStorage cleanup = new PostgresqlDlrStorage(dataSource, 0);
assertThat(cleanup.getState(state.getGatewayMsgId())).isPresent();
assertThat(countCorrelations(state.getGatewayMsgId())).isOne();

setCorrelationCreatedAt("old-correlation", "CURRENT_TIMESTAMP - INTERVAL '8 days'");

cleanup = new PostgresqlDlrStorage(dataSource, 0);
assertThat(cleanup.getState(state.getGatewayMsgId())).isPresent();
assertThat(countCorrelations(state.getGatewayMsgId())).isZero();
}

Expand Down Expand Up @@ -501,6 +498,17 @@ SELECT COUNT(*) FROM sendium_dlr.provider_correlation WHERE gateway_message_id =
}
}

private void setCorrelationCreatedAt(String providerMessageId, String expression) throws SQLException {
String sql = "UPDATE sendium_dlr.provider_correlation SET created_at = " + expression
+ " WHERE provider_name = ? AND provider_message_id = ?";
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, PROVIDER);
statement.setString(2, providerMessageId);
statement.executeUpdate();
}
}

private void setCreatedAt(String gatewayMsgId, String expression) throws SQLException {
updateTimestamp(gatewayMsgId, "created_at", expression);
}
Expand Down
Loading