Report Subscription
Report Subscription = automatic subscription to receive recurring reports (for example a weekly report). It is a thin automation path (thin MVP) that runs through the core primitives:
AutomationScheduler, shared key helper,Ensure*, dispatch guard, send claim.
Path
Sending
OutgoingMessagedirectly while skipping theNotificationSchedulerbridge requires separate approval and still must keep the send-claim guard.
Use AutomationScheduler (no new columns)
text
AutomationTypeId = ReportSubscription
TriggerTypeId = ScheduledRun | ManualRun
SourceEntityTypeId = ReportSubscription ; SourceEntityGuid = ReportSubscription.Guid
SchedulerKey = report-subscription:{guid}:scheduled:{periodStartUtc-or-scheduledOn}
| report-subscription:{guid}:manual:{manualRunGuid}SchedulerKeyis the canonical business run key — do not derive delivery keys fromAutomationScheduler.Id/Guid.manualRunGuidis generated before insert, returned to the caller, and reused on retry.StorageRunKeyHash(stable short hash ofSchedulerKey) groups delivery artifacts (MessagingJob.Guid, reportNotificationJob.RowKey).
One-Owner Guard — no double send during cutover
Old scheduler and new automation scheduler both check an ownership guard before creating delivery:
text
ReportRunOwnership: SchedulerKey, OwnerTypeId (OldScheduler | AutomationScheduler),
OwnerVersion, StatusId (Owned | DeliveryCreated | Cancelled), CoordinatesJson?- Only the owner may create
NotificationJob/MessagingJob/blob/NotificationScheduler. - Shadow rows do not acquire ownership.
- Retry reuses ownership + coordinates. Ownership conflict →
IsOnSupportHold, never creates a second delivery.
Step-by-step rollout (safe, rollbackable)
text
0 Design validation : xác nhận delivery path, hành vi scheduler cũ, ownership storage.
1 Shadow : row không-chạy; so khóa kỳ vọng với run của scheduler cũ.
2 Run-now allowlist : automation chạy các manual run được chọn; scheduler cũ bị chặn cho chúng.
3 Scheduled allowlist: chọn BU/subscription; theo dõi conflict/failure/latency.
4 Cutover : guard scheduler cũ cho subscription trong allowlist;
rollback = bỏ allowlist, ownership trả về scheduler cũ.Lifecycle & support
- Create/update → ensure next scheduled row (only next run, unless a clearly bounded horizon is needed).
- Pause/deactivate/delete → deactivate pending rows; completed runs are kept.
- Template/recipient/delivery changes → reload at execution. Run-now → new
manualRunGuid. - Support API:
GET/POST /report-subscriptions/{guid}/automation-runs[...]— report run detail, ownership detail, delivery coordinates, failed report queue, recent runs/subscription.
Related
- Automation & Reminders — shared automation foundation.
- Subscription — different from "report subscription"; subscription is a learning/billing package.