Skip to content

Broadcast Guide ​

This guide explains how broadcast works in Vona within the Cabloy monorepo.

Why broadcast matters ​

Broadcast lets one worker emit a message that multiple worker processes can receive and act on.

This is important because some business logic is not point-to-point background work. It is multi-worker coordination work.

Create a broadcast ​

Example: create a broadcast named echo in module training-student.

bash
npm run vona :create:bean broadcast echo -- --module=training-student

Broadcast definition ​

Representative shape:

typescript
@Broadcast()
export class BroadcastEcho
  extends BeanBroadcastBase<TypeBroadcastEchoJobData>
  implements IBroadcastExecute<TypeBroadcastEchoJobData>
{
  async execute(data: TypeBroadcastEchoJobData, isEmitter?: boolean) {
    if (!isEmitter) {
      console.log(`pid: ${process.pid} message: ${data.message}`);
    }
  }
}

The isEmitter flag is especially important because it lets the current worker avoid duplicating work it already performed locally.

Emit a broadcast ​

Representative usage:

typescript
this.scope.broadcast.echo.emit({ message: 'Hello world' });

A practical interpretation is:

  • the emitter starts the fan-out
  • every receiving worker can execute the same logic
  • the emitter can skip duplicate local work by checking isEmitter

Broadcast options ​

Broadcast options include:

  • instance
  • transaction

Representative decorator pattern:

typescript
@Broadcast({
  instance: true,
  transaction: true,
})
class BroadcastEcho {}

This matters because broadcast behavior may depend on tenant initialization or transactional execution guarantees.

Configure broadcasts in app config ​

Broadcast options can also be overridden in app config.

Representative pattern:

typescript
config.onions = {
  broadcast: {
    'training-student:echo': {
      instance: true,
      transaction: true,
    },
  },
};

Broadcast vs queue vs election ​

Read this guide together with:

A practical split is:

  • use broadcast when many workers should all receive the same signal or perform the same category of work
  • use queue when one background execution path should process a job asynchronously
  • use election when only one worker, or a fixed small number of workers, should own the responsibility

This distinction matters because all three features are distributed primitives, but they solve different coordination problems.

Relationship to backend runtime initialization ​

Broadcast is not the same as startup.

A useful mental model is:

  • startup initializes backend capabilities and lifecycle hooks
  • election chooses the owner for singleton-like responsibilities
  • broadcast fans out a message to many workers after the runtime is active

That keeps runtime initialization separate from runtime signaling.

Inspection ​

The effective broadcast list can be inspected for debugging and operational clarity.

Representative pattern:

typescript
this.bean.onion.broadcast.inspect();

Implementation checks for multi-worker broadcast changes ​

When evaluating multi-worker coordination needs, ask:

  1. is this really a queue job, or is it a broadcast?
  2. should the emitter worker also execute the business logic?
  3. does the logic require instance initialization?
  4. should the execution run inside a transaction?
  5. is this actually a singleton-ownership problem that belongs to election instead?

That helps distribute the right kind of work through the right abstraction.

Released under the MIT License.