DEV Community

CarterHughes6849
CarterHughes6849

Posted on

Go Logistics Outage Replay — API Capacity Planning With Usage-Derived Spend Cap

A page fires: logistics-event-ingest has reached 85% of its API spend limit, while a regional depot is reconnecting after an outage. The on-call view shows the current burn rate, the delayed-event count, the credential that made each request, and the last approved limit change. It does not merely show last month's invoice.

Use time-bucketed request and cost history to forecast normal traffic, then reserve a separate envelope for outage replay. Set the limit from those two workloads, alert on projected exhaustion early enough to act, and require an auditable approval for every limit change. This is the least complex policy that protects ingestion without treating a billing total as a capacity model.

Short answer: derive an API spend cap from recent usage history by workload and credential, add an explicit replay allowance for queued logistics events, and page on forecasted exhaustion rather than waiting for the cap itself.

What should the first page tell the on-call?

The cap page is late. By the time it fires, the useful question is not "How much did we spend?" It is "Which event stream changed, which credential sent it, and will the backlog fit inside the remaining allowance?" A workable alert payload needs the observed rate, expected rate, remaining allowance, oldest queued event, replay estimate, credential identity, and the approval record for the active limit. Without those fields, the responder has a finance symptom and no operational action.

I've been paged by missed jobs and duplicate deliveries. That history creates an idempotency reflex: raising a cap can restore throughput, but it must not turn a replay into duplicate shipment transitions. The consumer should claim a stable event ID before applying a state change, and a replay should follow the same path as a live event. A larger allowance cannot repair weak delivery semantics.

The signal that should have fired earlier is projected exhaustion. Compute it from the current workload's recent buckets, not from a calendar invoice that merges quiet hours, peaks, credentials, and unrelated calls. If the forecast crosses the configured response window, warn; if the delayed-event queue is growing at the same time, page. One condition measures financial headroom. The other confirms operational pressure.

Act sooner.

How should API capacity planning use usage history to set a spend cap?

Start with usage records that preserve time, workload, operation, credential, request count, and attributed cost. Keep unsuccessful attempts visible when they consume allowance, and keep retry or replay traffic distinguishable from first delivery. Access auditability is the primary decision axis here: a number that cannot be traced to a principal and an approved change is not a control the on-call can trust. OWASP's secrets management guidance calls for auditing who requested a secret, who used it, and when it was changed; the same identity trail should join the usage record without logging the secret value itself.

For each workload, choose a bucket small enough to expose its bursts, calculate a high percentile of ordinary bucket cost, and project that baseline across the cap window. Then add separately named allowances for expected growth and outage replay. Don't hide them inside one multiplier. The replay allowance comes from the maximum backlog the service is required to drain within its recovery objective, multiplied by the observed per-event cost for that route. If those inputs are uncertain, label them; I'm not sure a generic safety factor can represent a depot reconnect storm, and your mileage may vary until a controlled replay test supplies the missing distribution.

Here is an illustrative calculation, not a production benchmark. Suppose a team supplies hourly costs from its own ledger, a 24-hour window, and a replay reserve derived from its recovery test. The function returns an input to the approval workflow; it does not silently change the limit.

package capacity

import (
    "errors"
    "sort"
)

type CapInput struct {
    HourlyCostCents []int64
    WindowHours     int64
    ReplayCents     int64
    GrowthCents     int64
}

func ProposedCapCents(in CapInput) (int64, error) {
    if len(in.HourlyCostCents) == 0 || in.WindowHours <= 0 {
        return 0, errors.New("usage history and a positive window are required")
    }

    samples := append([]int64(nil), in.HourlyCostCents...)
    sort.Slice(samples, func(i, j int) bool { return samples[i] < samples[j] })

    // Nearest-rank p95 keeps the policy reviewable without a forecasting SDK.
    rank := (95*len(samples) + 99) / 100
    baseline := samples[rank-1] * in.WindowHours
    return baseline + in.ReplayCents + in.GrowthCents, nil
}
Enter fullscreen mode Exit fullscreen mode

The arithmetic is deliberately boring. The hard work is deciding which history represents ordinary demand and which records belong to an incident, launch, test, or replay. Keep those classifications in the dataset, review exclusions as code, and backtest the proposed limit against held-out periods. A model that predicts one total but cannot explain a limit change is poorly matched to an audited account platform.

Model the outage before choosing the limit

A logistics backend has two demand curves after an outage: new events continue to arrive, while stored events compete for the same downstream allowance. Forecasting only the live curve produces a cap that looks correct during steady state and fails during recovery. Forecasting every historical incident as ordinary demand does the opposite; it permanently inflates the baseline. Separate them.

Use a queue-age objective and a controlled drain rate to define replay demand. For an illustrative trace, imagine 18,000 delayed scan events, an observed replay plan of 300 events per minute, and ongoing live arrivals tracked in their own series. The capacity review asks whether both series fit within the downstream request and spend envelopes for the whole drain. Those numbers are placeholders for a team's measured values, not claims about typical logistics traffic.

The catch is that a spend cap is not suitable as the only overload control. Keep concurrency limits, bounded retries, backoff, idempotency keys, and queue retention in the design. If events have hard real-time deadlines or a replay estimate has no trustworthy cost attribution, stick with a conservative fixed limit and an explicit human escalation until the missing measurements exist. A statistically tidy forecast is worse than a blunt control when its inputs cannot be audited.

Make every access and cap change reconstructable

Treat the limit as configuration with provenance. A change record should contain the old value, proposed value, model version, history window, replay allowance, requester, approver, timestamp, and reason. Usage records should carry a credential identifier that can be joined to an owner, while secret material remains outside logs and analytics. Rotation must preserve identity continuity so an investigator can follow usage before and after a credential changes.

A practical review table is short enough to use during an incident:

Question Evidence Block the change when
What caused the increase? Workload buckets and backlog trace Growth has no attributable stream
Who can spend it? Credential-to-owner inventory A credential has no owner
Can replay duplicate effects? Idempotency test results Repeated event IDs change state twice
Who approved the risk? Immutable change record Requester and approver are absent

This is also where team boundaries matter. Finance can define the allowed exposure, service owners can explain event demand, and the platform team can enforce the control. None of them should be able to erase the record that connects a limit increase to the credential that uses it.

Tune the early warning, then pay attention to false positives

Deploy the instrumentation before changing the policy. Run the forecast in shadow mode, record when it would warn or page, and compare those moments with backlog growth and operator action. Test ordinary peaks, a credential rotation, a delayed depot reconnect, duplicate delivery, and a partial replay. The rollout should have an immediate path back to the previous fixed limit because a forecasting change is still a production change.

Alerting on 85% consumed sounds concrete, but percentage alone ignores time. At 85% with two minutes left in the window, no page may be needed; at 40% with most of the window remaining and a rising queue, the forecast may already require action. Use remaining allowance divided by a workload-aware burn estimate, then couple it with queue age or backlog growth. Page only when a human has a defined action, such as approving a bounded increase, slowing replay, or isolating an unexpected credential.

There is a real limitation here — early forecasts are noisy when workloads have little history or when operational classifications are wrong. A threshold tuned too tightly turns depot reconnects into routine pages, teaches responders to discount the alert, and spends attention that should be reserved for missed or duplicated work. A threshold tuned too loosely recreates the original cap page. Review false positives after each replay test and incident, but don't optimize them away by deleting the audit context. The goal is a page that arrives early enough to protect the event path and carries enough evidence to justify the action.

References

Top comments (0)