A multi-tenant platform must answer two different questions: “will this request overwhelm the system?” and “has this customer paid for this call?” Two independent mechanisms answer them, and conflating them is a classic architecture mistake:
- Noisy neighbors are the Host rate limiter’s job: a Redis token bucket short-circuits floods at the edge;
- Plan overruns belong to PlatformBilling metered quotas: remaining allowance decides approval or rejection.
BitzOrcas has no cross-cutting “quota pipeline.” No quota behavior exists in the Mediator pipeline, and declared attributes such as [QuotaConsumer] do not exist either. There are exactly two enforcement points: Host middleware and explicit quota-service calls.
Division of responsibilities
| Concern | Owner | Typical signal |
|---|---|---|
| Abuse and floods | Host RateLimiting | HTTP 429 |
| Plan call allowances | PlatformBilling quota | quota error in business result |
| Usage reconciliation | UsageMeter.Record | /api/platform-billing/usage |
Step one: Host rate limiting
The API composition root enables rate limiting by default (RateLimiting:Enabled=true). RedisTokenBucketRateLimiter provides a Redis-backed token bucket consistent across instances, and partition policies also include sliding-window and fixed-window variants. An exhausted bucket returns 429 before the request ever reaches the Mediator pipeline.
Step two: billing quota checks
Plan quotas are not attached to pipelines; they are business semantics checked explicitly in the application layer. QuotaService.Check compares the active plan against UsageMeter balance:
// Plan is the tenant's effective plan; UsageMeter is the authoritative usage aggregate.var check = quotaService.Check(plan, usageMeter, meterCode: "reporting.advanced_export", quantity: 1);
// An exhausted quota is not an exception; it is an expected business rejection with a stable code.if (check.IsFailure) return Result.Failure<string>(check.Error);// usageId is client-assigned; resubmitting the same usageId never creates a second fact.var record = RecordUsageCommand.Create( tenantId: currentTenant.Tenant.EffectiveTenantId, usageId: usageId, meterCode: "reporting.advanced_export", quantity: 1, occurredAt: clock.UtcNow);RecordUsageCommand is exposed via [GenerateEndpoint(HttpRoute.Post, "/api/platform-billing/usage")], requires the platform-billing.usage.create permission, and lands through UsageMeter.Record(usageId, quantity, occurredAt).
Summary
- 429 always originates in the Host limiter; plan overruns surface as business-layer quota errors. Front ends branch retry logic on that distinction instead of treating both as server faults;
- quota atomicity lives in the database (conditional updates on the usage aggregate), not in a pipeline — keeping usage facts independently auditable from business transactions;
- if you need Feature-level runtime switches, that is License Feature or Tenant Feature Entitlement territory, not this page’s machinery.