Skip to main content

nexus-serialization-msgpack

Binary MessagePack serialization for Nexus messages — a MessageSerializer producing compact binary payloads, with a dual-backend codec that uses the native ext-msgpack extension when available and falls back to the pure-PHP rybakit/msgpack library otherwise.

What's in this package

ClassPurpose
MessagePackMessageSerializerMessageSerializer implementation: MessagePack encoding, Valinor type-safe decoding, TypeRegistry-backed type names
MsgpackCodecInternal dual-backend pack/unpack codec (native ext-msgpack or pure-PHP rybakit/msgpack)

Install

terminal
composer require nexus-actors/serialization-msgpack

The pure-PHP rybakit/msgpack backend is a hard dependency, so the package works on any PHP 8.5+ install. The native extension is optional:

terminal (optional, faster packing)
pecl install msgpack

When ext-msgpack is loaded, MsgpackCodec selects it automatically — no configuration needed. Both backends produce wire-compatible bytes, so producers and consumers may run different backends.

Quick example

src/Serialization/MsgpackSetup.php
use Monadial\Nexus\Serialization\Msgpack\MessagePackMessageSerializer;
use Monadial\Nexus\Serialization\TypeRegistry;

$registry = new TypeRegistry();
$registry->registerFromAttribute(OrderPlaced::class);

$serializer = new MessagePackMessageSerializer($registry);

$bytes = $serializer->serialize(new OrderPlaced('ord-1', 99.99)); // binary string
$msg = $serializer->deserialize($bytes, 'order.placed');

Serialization requires the message class to be registered in the TypeRegistry (via #[MessageType] + registerFromAttribute() or explicit register()) and throws MessageSerializationException otherwise. Deserialization resolves $type through the registry first and falls back to treating it as a literal class name; malformed bytes or structurally wrong payloads throw MessageDeserializationException.

Objects are normalized to arrays with Valinor's array normalizer — the symmetric partner of the mapper used for hydration — before packing. Because both directions share Valinor's type rules, enums, DateTimeInterface, and nested value objects round-trip faithfully, unlike a naive json_encode()/json_decode() normalization.

Codec fallback and trailing-byte safety

new MsgpackCodec() auto-detects the backend; pass new MsgpackCodec(false) to force the pure-PHP path or new MsgpackCodec(true) to force the extension. Two behavioral notes:

  • Trailing bytes: the pure-PHP path rejects payloads with unexpected bytes after the MessagePack value (UnexpectedValueException). The native extension does not perform this check — a truncation/concatenation bug can go unnoticed with ext-msgpack where the pure path would fail loudly.
  • Non-array payloads: both paths reject decoded values that are not arrays.

Choosing a serialization format

PhpNativeSerializerValinorMessageSerializer (JSON)MessagePackMessageSerializer
Wire formatPHP serialize()JSON textMessagePack binary
Payload sizeVerboseBaselineSmallest — no field quoting, braces, or whitespace
Interoperable (non-PHP consumers)NoYesYes (msgpack libs exist for every major language)
Human-readable on the wireNoYesNo
Deserialization safetyAllow-list required (CWE-502)Valinor strict mappingValinor strict mapping
TypeRegistry requiredNoYesYes
Best forSame codebase both ends, trusted dataDebugging, cross-language, text-only transportsHigh-volume queues over binary-safe transports

Transport caveat: binary-safe brokers only

MessagePack bodies are raw binary. Redis Streams, AMQP/RabbitMQ, and database transports with a BLOB column carry them untouched. Text-oriented transports — Amazon SQS most prominently, which rejects message bodies outside a limited character set — will refuse or corrupt binary payloads. On such transports, use the JSON serializer or base64-encode the body at the transport boundary.

Observing serialization

Wrap the serializer in TracingMessageSerializer to record a span per operation and the nexus.serialization.* metrics — the bytes histogram makes the msgpack payload-size drop directly measurable.

See also