Skip to content

Enforce a hard limit

Enforce a hard limit

Guard an operation against an org's allowance on the hot path.

Reserve, work, commit

use Cbox\Billing\Metering\Contracts\Enforcement;
use Cbox\Billing\Metering\Exceptions\QuotaExceeded;

public function handle(Enforcement $enforcement, string $org): void
{
    try {
        $reservation = $enforcement->reserve($org, 'api.calls', estimate: 1);
    } catch (QuotaExceeded) {
        abort(429, 'Usage limit reached');
    }

    try {
        $this->doTheWork();
        $enforcement->commit($reservation, actual: 1);
    } catch (\Throwable $e) {
        $enforcement->release($reservation); // return the held unit
        throw $e;
    }
}

reserve holds the estimate and hard-blocks when the leased allowance is exhausted. commit settles to the actual amount (releasing any difference) and appends the durable usage event. Always release on the error path.

Branch instead of catching

If you would rather branch on a value than catch an exception, use the outcome API. It also lets you see whether an infra failure was allowed through (fail-open):

$outcome = $enforcement->reserveOutcome($org, 'api.calls', estimate: 1);

if ($outcome->refused()) {
    abort(429, 'Usage limit reached');
}

if ($outcome->failedOpen()) {
    Log::warning('Enforcement admitted on infra fail-open', ['org' => $org]);
}

$enforcement->commit($outcome->reservation(), actual: 1);

refused() is true for a real denial and for an infra failure under a deny policy. failedOpen() is true only when a dependency was down and the configured policy (billing.metering.enforcement.infra_failure) let it through — the durable ledger and reconciliation recover the truth.