Facade
Once is a facade that wraps any arbitrary callback with an idempotency guarantee. Use it when you need idempotency outside of HTTP requests or queued jobs — inline in your service classes, event listeners, or any other application code.
Basic Usage
use Truschery\Idem\Facades\Once;
Once::do('my-unique-key', function () {
// Will only execute once
});
Once::do() returns a Record value object containing the response and replay status. On subsequent calls with the same key — the cached result is returned immediately without executing the callback.
Choosing a Key
String Key
Pass a plain string as the key. Idempotency is checked against this key only:
Once::do('send-welcome-email-user-42', function () {
Mail::to($user)->send(new WelcomeMail());
});
The same rules apply as in Job Middleware — use a stable, unique identifier tied to the business entity.
Key Value Object
Pass a Key value object when you need to include a hash check. On subsequent calls, both the key and the hash must match:
use Truschery\Idem\ValueObjects\Key;
$key = new Key(
key: 'create-invoice-42',
hash: $invoice->fingerprint()
);
Once::do($key, function () {
$externalService->createInvoice($invoice);
});
If the key is found but the hash differs, truschery/idem will throw IdempotencyHashMismatchException. This protects against calling the same key with different data.
| Key type | Idempotency check |
|---|---|
string | Key only |
Key | Key + hash |
Examples
Sending a notification
Once::do("notification-order-{$order->id}", function () {
Notification::send($user, new OrderConfirmed($order));
});
Calling an external API
Once::do("sync-crm-contact-{$contact->uuid}", function () {
$crm->createContact($contact);
});
Creating a record in a third-party system
Once::do(
new Key(key: "create-subscription-{$user->id}", hash: md5(serialize($plan))),
function () {
$billing->createSubscription($user, $plan);
}
);