Table of Contents

Class AuthoredSendUsageLedger

Namespace
MailFathom.Application.Mail.Delivery.Governance
Assembly
MailFathom.Application.dll

Counts what each caller has been admitted to send inside the period this process is in.

public sealed class AuthoredSendUsageLedger
Inheritance
AuthoredSendUsageLedger
Inherited Members

Remarks

Held in this process rather than in the database, which is the opposite of how the deployment's own ceilings are counted and is deliberate. Two reasons, and the second is the stronger one. What this bounds is one client looping — a fault that happens inside a running process and is caught by a counter inside it — while the fault a durable count exists for, a process restarting and beginning every period afresh, is already bounded by OutgoingMailCeilings, which is counted from the records themselves. And the key is the calling principal, which for a token is an issuer and a subject: an identifier for a person at somebody else's directory, which writing onto every outgoing record would put into the database for as long as the record lives, under no retention anybody asked for. A count that evaporates when its period rolls over holds it for exactly as long as the bound it serves.

Judging and charging are one operation, under one lock. A ceiling read and then charged after an awaited write is a ceiling two concurrent sends from one caller both pass, which is exactly the client this bound exists to stop: a loop that dispatches rather than waits would exceed it by however many calls it had in flight. So a send is weighed and counted in the same breath, and what a caller may still ask for is never a number read before an await.

What it is counted under is the send's own idempotency identity — the account it is sent as and the requester that asked — which is the same pair the outbox writes one record per. So a caller retrying under the key it first asked under is charged for one message however many times the call is repeated, and it is charged without waiting to see which record the retry produced.

The charge therefore stands whether or not a record follows it. A send this deployment's own bounds refuse after this ledger admitted it has spent the caller's allowance, and that is the honest answer rather than a leak: a client asking repeatedly for a send that is refused every time is the loop being bounded, and the period rolls over. A send already charged is admitted again without the ceiling being consulted at all, however full the period has become since — the charge stands, so asking again buys the caller nothing and refusing it would only strand a client retrying the message it was already admitted for.

Everything the ledger holds belongs to one period. The roll-over is not swept on a timer: the first caller to arrive in a new period clears what the last one left, which is what keeps a ledger nobody is using from holding anything at all.

Constructors

AuthoredSendUsageLedger(AuthoredSendCeilings, TimeProvider)

Counts what each caller has been admitted to send inside the period this process is in.

Fields

MaximumCallersPerPeriod

The greatest number of callers one period is counted for.

Methods

Admit(string, OutgoingEmailRequest)

Weighs one send against the caller's period and charges it to that caller in the same operation.