A purely additive patch on top of 3.4.0 that introduces two new
capability layers — a gRPC-lite typed RPC stack and the
Laravel Messaging Platform (service discovery, sagas-as-a-facade,
typed-message dispatch, dead-letter management, declarative retry,
monitoring dashboard, causation IDs, MessageStore, and an async
Laravel-event bridge).
No migration required. Every new feature is opt-in; existing
publish/consume code, handler signatures, configuration layouts, and
the public surface from 3.4.0 continue to work unchanged.
Compatibility
- PHP: 7.3 through 8.5 (PHP 8+ required to use
#[Retry]attributes). - Laravel: 8.x through 13.x (Lumen 8.x+).
- PHPUnit:
^9.6on PHP 7.3/7.4;^10.5|^11.5|^12.0on PHP 8.0+. - Every new file under
src/parses as PHP 7.3 — verified by
scripts/check-php73-compat.php(curated) and
scripts/check-php73-compat-all-src.php(entire tree) using
nikic/php-parser.
gRPC-lite RPC
A typed, service-oriented RPC layer that feels like gRPC but rides on
RabbitMQ. Built as a thin abstraction over the existing
Request/Consumer::reply() RPC primitive — no new dependencies, no
new transports.
-
Service contract & DTOs
Bschmitt\Amqp\Rpc\RpcService— abstract contract with
queue(),methods()(mapping request DTO → handler method), and
optionalname()/exchange()/routingKey()overrides.Bschmitt\Amqp\Rpc\RpcRequest/Bschmitt\Amqp\Rpc\RpcResponse
DTOs with amake(array $payload)factory built on the existing
TypedMessagereflection hydration.RpcRequest::responseClass()lets a request declare its typed
reply soRpc::call()hydrates the response automatically.
-
Rpcfacade & dispatcherBschmitt\Amqp\Rpc\RpcDispatchercoordinates symmetric
call()/serve()/register()flow withx-rpc-serviceand
x-rpc-requestheaders for routing and tracing.Bschmitt\Amqp\Facades\Rpcauto-registered viacomposer.json
(Rpc::call(UserService::class, GetUserRequest::make([...]))).Amqp::rpcDispatcher()accessor for non-facade contexts.- Container-resolvable handler FQCNs (
Rpc::register(UserService::class, UserServiceHandler::class)->serve(UserService::class)).
-
Error & timeout typing
Bschmitt\Amqp\Rpc\RpcException— remote-handler errors carry
the original exception class name and message.Bschmitt\Amqp\Rpc\RpcTimeoutException— distinct type so callers
can branch on "no reply" vs "remote error".- Server-side handler exceptions are caught, wrapped into an
_rpc_errorenvelope, and surfaced to the client as the typed
exceptions above.
-
Configurable per-call
- Global
Rpc::defaultTimeout($seconds). - Per-call
timeoutand extra publish properties:
Rpc::call(UserService::class, GetUserRequest::make([...]), 5, ['exchange' => 'rpc.svc']).
- Global
Laravel Messaging Platform
Higher-level building blocks that turn the package from "an AMQP
client" into a Laravel-first microservice toolkit. Every item below is
purely additive and ships with unit-test coverage.
-
Service discovery (
Rpc::service('payments'))Bschmitt\Amqp\Rpc\ServiceRegistry— register short names → service
FQCNs (Rpc::services()->register('payments', PaymentsService::class)).autodiscover([...])honours an opt-inpublic static function alias()
method onRpcServicesubclasses.Bschmitt\Amqp\Rpc\ServiceCaller— fluent caller withtimeout()
andwithProperties()chaining;
Rpc::service($alias|$fqcn)->call($request).
-
Saga facade +
compensate()syntaxSaga::make()static factory and a new top-levelSagafacade
(auto-registered viacomposer.json).- Fluent compensation:
->step('reserve', $reserve)->compensate($release). - Backwards-compatible: the old three-argument
step($name, $action, $compensation)form still works.
-
Message contract dispatch
TypedMessage::make(array $payload)and
TypedMessage::dispatch(array $payload, array $properties = [])
static helpers.TypedMessage::dispatchLater(array $payload, int $delayMs)mirrors
the delayed publisher.- Resolves the
Amqpsingleton from the Laravel container; throws a
clearRuntimeExceptionwhen called outside Laravel.
-
Dead-letter management (
Amqp::deadLetters())Bschmitt\Amqp\Support\DeadLetterManagerfluent API:
for($queue)->count()/messages($limit)/replayTo($target, $limit)
/purge().- Inspection uses the Management API; replay and purge use the AMQP
channel directly so they work even when the management plugin is
disabled.
-
#[Retry]attribute +RetryStrategyBschmitt\Amqp\Attributes\Retry(attempts, strategy, delayMs, maxDelayMs, jitter)with PHP 8+ attribute target.Bschmitt\Amqp\Support\RetryStrategy::{FIXED|EXPONENTIAL|LINEAR|NONE}
string constants (PHP 7.3-safe — uses class constants, not enums).RetryPolicy::fromAttribute($class, $method = null)reflection
helper builds an existingRetryPolicyfrom the attribute.- PHP 7.x silently ignores the attribute marker (parsed as a
comment), so the package still loads on older runtimes — only the
reflection lookup requires PHP 8+.
-
Monitoring dashboard +
amqp:monitorBschmitt\Amqp\Support\MonitoringDashboardaggregates
MetricsCollector(in-process counters) and Management API queue
stats into a single JSON-safe snapshot.Amqp::dashboard($queues)->snapshot()returns
['process' => ..., 'queues' => ..., 'overview' => ..., 'generated' => ...].php artisan amqp:monitor --queue=orders [--queue=...] [--json] [--connection=]
Artisan command (Bschmitt\Amqp\Console\Commands\AmqpMonitorCommand)
for ops / CI / scrape targets.
-
Causation ID propagation
CorrelationContextnow tracks a causation id alongside the
correlation id withsetCausation()/getCausation()and a new
CAUSATION_HEADERconstant.CorrelationContext::inheritFromMessage($incoming)captures the
inboundmessage_idas the causation id of anything published
next — letting downstream services trace
"this happened because of that" through a chain.applyToPublishProperties()adds anx-causation-idheader
alongside the existing correlation headers.
-
MessageStore (
Bschmitt\Amqp\Contracts\MessageStoreInterface)- Append-only log API:
append() / find() / all($filters) / count($filters) / purge(). Bschmitt\Amqp\Support\InMemoryMessageStoredefault
implementation (good for tests and small workloads).Amqp::setMessageStore($store)/Amqp::messageStore()accessors;
publish and consume both auto-record when a store is attached.- Foundation for durable replay / event-sourcing-style audit trails
— implement the interface against Eloquent / Redis / files / S3
for production use.
- Append-only log API:
-
Async Laravel events (
ShouldPublishToAmqpInterface)- Marker interface for Laravel events that should auto-publish to
RabbitMQ — mark the event,event(new OrderCreated(...))becomes
a publish. Bschmitt\Amqp\Events\AmqpEventListenerwildcard listener
handles routing key, payload, and exchange resolution with
overridableamqpRouting()/amqpPayload()/amqpExchange()
hooks on the event.- Disabled by default; opt-in with
amqp.broadcast_laravel_events => true.
- Marker interface for Laravel events that should auto-publish to
New & Updated Public Surface
- New classes:
Bschmitt\Amqp\Rpc\{RpcDispatcher, RpcService, RpcRequest, RpcResponse, RpcMessage, RpcException, RpcTimeoutException, ServiceCaller, ServiceRegistry}Bschmitt\Amqp\Facades\{Rpc, Saga}Bschmitt\Amqp\Attributes\RetryBschmitt\Amqp\Support\{RetryStrategy, DeadLetterManager, InMemoryMessageStore, MonitoringDashboard}Bschmitt\Amqp\Contracts\{MessageStoreInterface, ShouldPublishToAmqpInterface}Bschmitt\Amqp\Events\AmqpEventListenerBschmitt\Amqp\Console\Commands\AmqpMonitorCommand
- New
Amqpfacade methods:rpcDispatcher(),deadLetters(),
dashboard($queues),setMessageStore(),messageStore(). - Extended classes (backwards-compatible):
Bschmitt\Amqp\Support\{Saga, TypedMessage, RetryPolicy, CorrelationContext},
Bschmitt\Amqp\Rpc\RpcDispatcher,Bschmitt\Amqp\Providers\AmqpServiceProvider.
New & Updated Documentation
- New pages:
docs/content/grpc-lite-rpc.mddocs/content/messaging-platform.md
- New sidebar entries (
docs/app.js) and feature cards
(docs/index.html). README.mdgains a "gRPC-lite RPC" section and a
"Laravel Messaging Platform" section with full usage examples for
every item above.
Tests
- 11 new unit-test files added under
test/Unit/:
Rpc/RpcDispatcherTest,Rpc/RpcMessageTest,
Rpc/ServiceRegistryTest,Rpc/ServiceCallerTest,
SagaFacadeTest,DeadLetterManagerTest,
InMemoryMessageStoreTest,MonitoringDashboardTest,
RetryAttributeTest,CausationContextTest,
AmqpEventListenerTest. - New fixtures under
test/Support/Fixtures/Rpc/:
UserService,UserServiceHandler,GetUserRequest,
GetUserResponse,CreateUserRequest. - Total unit suite: 444 tests / 1004 assertions (was 405 / 925 in
the 3.4.0 baseline). - Full suite passes on PHP 7.3 through 8.5. Deprecation warnings on
PHP 8.4+ continue to come exclusively from the vendored Mockery
library and predate this release.
Migration
No migration required. Everything below is opt-in:
- The new
RpcandSagafacades are auto-registered via
composer.jsonaliases — they only become visible to user code when
imported. TypedMessage::make()/dispatch()/dispatchLater()are new
static helpers; the existing instance-based publish path is
untouched.DeadLetterManager,MonitoringDashboard, andMessageStoreare
attached only when their factory methods are called or
setMessageStore(...)is invoked.- The
#[Retry]attribute is read only when application code asks
for it viaRetryPolicy::fromAttribute(...); existingRetryPolicy
factories continue to work as before. CorrelationContextkeeps its previous API; the new
setCausation()/getCausation()/CAUSATION_HEADERconstants
andx-causation-idheader only appear when callers actively
populate the causation slot (e.g. viainheritFromMessage()).- The async-Laravel-events bridge is only registered when
amqp.broadcast_laravel_eventsis set totrueinconfig/amqp.php.
What's Changed
- Patch Release by @zfhassaan in #137
Full Changelog: v3.4.0...v3.4.1