ProducerController
Esta página aún no está disponible en tu idioma.
ProducerController wraps a sender’s outgoing messages,
assigning sequence numbers + holding them until acked by
the consumer.
import { Props, ProducerController } from 'actor-ts';
const producer = system.spawn( Props.create(() => new ProducerController<OrderEvent>({ producerId: 'orders', // stable identity consumer: consumerRef, windowSize: 16, // flow-control window resendTimeoutMs: 500, })), 'producer',);
producer.tell({ kind: 'reliable-delivery.send', body: { orderId: 'o-1' } });Internally:
- Assigns seq 1 to the first message, 2 to the next, …
- Sends each via wrapped tell to the consumer.
- Holds in a buffer until acked.
- Retransmits if no ack within
resendTimeoutMs.
Configuration
Section titled “Configuration”interface ProducerControllerSettings<T> { consumer: ActorRef<Delivery<T>>; resendTimeoutMs?: number; // default 500 windowSize?: number; // default 16 producerId?: string; // auto-generated if omitted}| Field | Purpose |
|---|---|
consumer | The ConsumerController ref to deliver to. |
resendTimeoutMs | How long to wait for an ack before retransmitting. |
windowSize | Flow-control window — pauses queueing after N unacked messages in flight. |
producerId | Stable identifier used by the consumer to dedup across restarts. Auto-generated if omitted, but for persisted producers you’ll want a stable string so recovery matches up. |
Backpressure
Section titled “Backpressure”windowSize: 16The producer holds up to 16 unacked messages in flight. Beyond that,
incoming { kind: 'reliable-delivery.send' } messages are queued — the
caller’s tell succeeds, but actual sending pauses until the
consumer’s acks free up the buffer.
For senders that need to know about pressure:
const result = await producer.ask({ kind: 'reliable-delivery.send', body, replyTo: ... }, 30_000);// ^ replies after the message is at least sentask-style sends wait for the producer’s “I sent it” reply,
giving you a natural backpressure signal.
Retransmission
Section titled “Retransmission”When an ack doesn’t arrive within resendTimeoutMs:
seq 5 sent at t=0seq 5 ack never arrivesat t=500 → retransmit seq 5at t=1000 → retransmit seq 5... until ack arrives or producer stopsRetransmits use the same seq as the original. The consumer dedups based on the seq.
State + restart
Section titled “State + restart”// Without persistence:producer crashes → buffer lost → unacked messages are gone// On restart, send resumes from seq 1 (no resume)
// With ProducerController + PersistentActor wrapper:producer crashes → recovery rebuilds buffer + last-acked-seq// On restart, send resumes from the right seqFor full durability, wrap the producer in a PersistentActor
pattern — persist outgoing messages before sending; on
restart, replay any unacked.
The framework’s plain ProducerController is in-memory —
sufficient for ephemeral streams. For durable streams, layer
persistence on top.
Multiple consumers
Section titled “Multiple consumers”// One producer per consumer:const p1 = system.spawnAnonymous(Props.create(() => new ProducerController({ consumer: c1Ref, ... })));const p2 = system.spawnAnonymous(Props.create(() => new ProducerController({ consumer: c2Ref, ... })));Each ProducerController is 1:1 with one ConsumerController. For fan-out, multiple producers send to different consumers.
For routing-based fan-out (one logical stream split across N consumers), you’d write a custom router on top.
Cluster-aware
Section titled “Cluster-aware”ProducerController’s consumer ref can point at a remote
consumer (different cluster node). The cluster transport
serializes envelopes; retransmissions work the same.
The producer holds the buffer locally — on producer-host crash, those messages are lost unless persisted.
Comparison with raw tell
Section titled “Comparison with raw tell”ref.tell(msg): ProducerController:- No seq, no ack, no retransmit - Reliable delivery contract- Lost on dead recipient - Survives transient failures- Sub-microsecond cost - ~50µs per message overheadUse the controller only for streams where loss is unacceptable;
raw tell for everything else.
Where to next
Section titled “Where to next”- Delivery overview — the bigger picture.
- ConsumerController — the receiver side.
- Ack semantics — when acks fire and what they mean.
- PersistentActor — for durable producer state.