egensolve / realtime-laravel
Transactional Laravel outbox for ERS publications.
Requires
- php: ^8.4
- egensolve/realtime: ^0.2
- laravel/framework: ^10.0 || ^11.0 || ^12.0 || ^13.0
Suggests
- ext-curl: Required by the default publication transport; optional with an injected transport.
Conflicts
- egensolve/realtime-laravel-outbox: *
This package is not auto-updated.
Last update: 2026-08-28 01:32:04 UTC
README
Record an ERS event in the same database transaction as your application change, then publish asynchronously with retry and lease fencing. Delivery is at least once; consumers must deduplicate event IDs. Application authorization and recovery remain yours.
Install
Requires PHP 8.4+ and a compatible Laravel 10–13 application.
composer require egensolve/realtime-laravel:^0.2.1 php artisan vendor:publish --tag=realtime-outbox-config
The service provider loads its migration. For a new installation, review the migration, select
the database connection and table before running your normal migration process. The default
table is ers_realtime_outbox. Do not change an existing table name to move data; that requires
an application-owned migration. Existing installations must preserve their table and rows.
Use PostgreSQL or MySQL 8+/MariaDB 10.6+ for concurrent production workers. SQLite is for local single-process testing, not production concurrency guarantees.
Configure
Store installation credentials only in your backend secret configuration:
REALTIME_OUTBOX_GATEWAY_APP_KEY and REALTIME_OUTBOX_GATEWAY_APP_SECRET.
REALTIME_OUTBOX_GATEWAY_BASE_URL defaults to https://realtime.egensolve.com; override it
for your own deployment. Use HTTPS outside loopback development.
Bind the publisher explicitly in your application's service provider:
use Egensolve\Realtime\LaravelOutbox\Contracts\Publisher; use Egensolve\Realtime\LaravelOutbox\Transport\PublicationClientPublisher; $this->app->singleton(Publisher::class, fn ($app) => PublicationClientPublisher::fromConfig($app['config']->get('realtime-outbox.gateway')));
Construct a validated Egensolve\Realtime\Contracts\Envelope using the PHP SDK. Within the
same transaction as your application change, call
OutboxRecorder::recordAfterCommit($envelope, $channels). The row is inserted immediately;
only the optional queue nudge waits for commit. A rollback removes the row. Channel lists contain
1–16 valid protocol channels. Reusing an event ID with different content raises
OutboxIdentityConflict.
Operate
Schedule realtime:outbox:publish as a required retry/crash-recovery fallback, even when enabling
REALTIME_OUTBOX_DISPATCH_VIA_QUEUE. Schedule realtime:outbox:prune for published-row retention;
dead letters are retained. Monitor realtime:outbox:health --max-oldest-pending-seconds=300.
Choose the threshold for your application; it is not a delivery guarantee.
The queue is an optional latency optimization. On Laravel 10, do not combine queue dispatch with the synchronous queue driver when relying on after-commit ordering. Use a database queue or the scheduled publisher. Keep leases longer than the expected publication attempt and account for batch duration. A crash after acceptance can cause a retry with the same event ID.
Transient failures use bounded retries with jitter; permanent failures become dead letters. Metrics are optional, bounded and fail-open. Stored failure details exclude publisher exception text and event bodies. Never log credentials, signed requests or raw event contents.
The package includes Testing\FakeTransport for application tests. It is a recording fake;
do not bind it in production.
Migrating from the previous package name
Replace the Composer requirement egensolve/realtime-laravel-outbox with
egensolve/realtime-laravel and regenerate the application's lockfile. The packages conflict
deliberately: do not install both copies of the same PHP classes. PHP namespaces, service provider,
realtime-outbox configuration, environment variables and command names are unchanged.
Keep the existing table name and rows; this naming change requires no database migration.
License
MIT. See LICENSE.