Producing messages with the PHP core

Last updated:

Producing is two steps: build the canonical envelope, then encode it to JSON and publish the bytes with your broker client.

From a typed job

Implement BabelQueue\Contracts\PolyglotJob — a URN plus a pure-array payload:

use BabelQueue\Contracts\PolyglotJob;

final class OrderCreated implements PolyglotJob
{
    public function __construct(public int $orderId) {}

    public function getBabelUrn(): string
    {
        return 'urn:babel:orders:created';
    }

    public function toPayload(): array
    {
        return ['order_id' => $this->orderId];
    }
}
use BabelQueue\Codec\EnvelopeCodec;

$envelope = EnvelopeCodec::fromJob(new OrderCreated(1042), 'orders');
$json     = EnvelopeCodec::encode($envelope);
// publish $json onto the "orders" queue with your transport (below)

From a raw URN + data

When you don’t have a job object, build it directly:

$envelope = EnvelopeCodec::make('urn:babel:orders:created', ['order_id' => 1042], 'orders');
$json     = EnvelopeCodec::encode($envelope);

make(string $urn, array $data = [], string $queue = 'default', ?string $traceId = null, array $meta = []) returns the envelope as a plain PHP array. A fresh trace_id (v4 UUID) is stamped automatically; pass $traceId to continue an existing trace, or implement BabelQueue\Contracts\HasTraceId on your job.

Publish

encode() produces the exact UTF-8 JSON bytes every other SDK reads — see Transports for the reference Redis/RabbitMQ publishers, or move the string with any broker client you already use.

{
  "job": "urn:babel:orders:created",
  "trace_id": "…",
  "data": { "order_id": 1042 },
  "meta": { "id": "…", "queue": "orders", "lang": "php", "schema_version": 1, "created_at": 1749132727000 },
  "attempts": 0
}

Extension (meta) keys

make() takes an optional meta: array for your own meta entries:

$envelope = EnvelopeCodec::make(
    'urn:acme:orders:created',
    ['order_id' => 1042],
    'orders',
    meta: ['ext' => ['acme' => ['tier' => 'gold']]],
);

A key that collides with a core meta key (id, queue, lang, schema_version, created_at) or a forbidden one (max_retries, attempts, source, ts) throws InvalidEnvelopeException. encode() throws the same exception for a forbidden key (timestamp, urn, meta.max_retries, meta.attempts, meta.source, meta.ts) instead of stripping it.

Keep vendor data under a single meta.ext.<vendor> block and use snake_case keys (ADR-0031). The entries are written next to the core meta keys and survive every retry, dead-letter and redrive hop. See Extension keys in the envelope spec.

Next: Consuming messages.