Notification Delivery Storage
Summary
NotificationDeliveryAttempts records one append-only row per delivery attempt against a channel provider, including timing and any error.
Audience
Engineers, architects, QA, support and security reviewers.
Reference Content
The verified reference material for this topic is set out in the sections below.
Ownership
Owned by NotificationDbContext. Written by the dispatcher's attempt recorder on every try and by the template test endpoint's live-send path. Read by the attempts endpoint.
Columns
| Column | Type | Constraint |
|---|---|---|
Id | GUID | Primary key |
NotificationMessageId | GUID | Plain value, no constraint |
AttemptNumber | int | One-based |
Channel | string | Max length 40, required |
Provider | string | Max length 60, required |
Status | string | Max length 40, required |
Error | string | Max length 2000, nullable |
StartedOnUtc | timestamp | — |
CompletedOnUtc | timestamp | — |
DurationMs | long | — |
Attempt status values are stored as plain strings drawn from a constants class: success, failed and skipped.
Indexes
| Index | Columns | Unique |
|---|---|---|
IX_DeliveryAttempts_MessageId | message | No |
There is no unique index on the message and attempt-number pair, so nothing structurally prevents two rows claiming the same attempt number for the same message.
Relationships
None declared. NotificationMessageId is a plain GUID with no foreign key, no navigation property and no cascade rule. Attempt rows are not deleted when a message is — and no code path deletes either.
Truncation
The error text is truncated in application code to the mapped maximum length before the row is added, so an oversized provider error is stored clipped rather than raising a length violation. This is one of only two places in the module where a value is defensively truncated; the other is the audit detail.
Timing
The recorder captures a start timestamp, measures elapsed time with a stopwatch, and computes the completion timestamp by adding the measured duration to the start value rather than reading the clock a second time. The stored duration and the stored timestamp difference are therefore consistent by construction.
Lifecycle
Append-only. Rows are never updated or deleted by any reviewed code path.
Classification
Implemented.
Requires confirmation
Whether a uniqueness guarantee on message and attempt number is intended requires confirmation.
Related Articles
See Also
Keywords
- Notification database
- Delivery Storage
- Draft database documentation
Source References
microservices/src/notification-service/Infrastructure/NotificationDbContext.csmicroservices/src/notification-service/Domain/NotificationEntities.csmicroservices/src/notification-service/Application/NotificationDispatcher.csmicroservices/src/notification-service/Api/NotificationEndpoints.csmicroservices/src/notification-service/Infrastructure/Migrations/20260705113059_InitialNotificationSchema.cs
Revision Information
- Status: Draft
- Last reviewed: 2026-07-21
- Review cycle: Quarterly