egensolve/realtime-laravel

Transactional Laravel outbox for ERS publications.

Maintainers

Package info

github.com/Egensolve/realtime-laravel

pkg:composer/egensolve/realtime-laravel

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.2.1 2026-08-27 12:31 UTC

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.