Skip navigation.

CometD JavaScript Message Batching

JavaScript CometD API: Message Batching

It is often needed by an application to send several messages to possibly different channels.

One, naive, way of doing it is the following:

cometd.handshake();

// Warning: non-optimal code
cometd.publish('/channel1', { product: 'foo' });
cometd.publish('/channel2', { notificationType: 'all' });
cometd.publish('/channel3', { update: false });

You may think that the 3 publishes will leave the client one after the other, but that's actually not the case.
Remember that publish() is asynchronous (so it returns immediately), so the 3 publish() calls in sequence may return well before a single byte hits the network.

What happens is that the first publish() will be executed immediately, and the other 2 will be put in a queue, waiting for the first publish() to complete.
A publish() is complete when the server received it, the server sent back the meta response, and the client received the meta response for that publish.
When the first publish is completed, the second publish is executed and waited to complete. After that, finally the third publish() is executed.

Since CometD 1.1.2, a new configuration parameter called autoBatch can be set to true, allowing the implementation to automatically batch messages that have been queued up.
So, in the example above, the first publish() will be executed immediately, and when it completes, the implementation will batch the second and third publish() into one request to the server.
The autoBatch feature may be interesting for those systems where events received asynchronously and unpredictably, either at a fast rate or in bursts, end up in generating a publish() to the server: in such cases, using the batching API is not effective (as each event would generate only one publish()).
A bursts of events on the client will generate a bursts of publish() to the server, but this mechanism batches them automatically, making the communication more efficient.

This queueing mechanism is needed to avoid to queue a publish() behind a long poll. If not for this mechanism, the browser would receive 3 publish requests but only has 2 connections available, and one is already occupied by the long poll request. So the browser may decide to round robin the publish requests, so that the first publish goes on the second connection (remember that the first connection is already busy with the long poll request), which is free and it is actually sent over the network, schedule the second publish to the first connection (after the long poll returns), and schedule the third publish again to the second connection, after the first publish returns.
The result is that if you have a long poll timeout of 5 minutes, the second publish request may arrive to the server 5 minutes later than the first and the third publish request.

You can optimize the 3 publish using batching, which is a way to group messages together so that a single Bayeux message actually carries the 3 publish messages.

cometd.handshake();

cometd.batch(function()
{
    cometd.publish('/channel1', { product: 'foo' });
    cometd.publish('/channel2', { notificationType: 'all' });
    cometd.publish('/channel3', { update: false });
});

// Alternatively, but not recommended
cometd.startBatch()
cometd.publish('/channel1', { product: 'foo' });
cometd.publish('/channel2', { notificationType: 'all' });
cometd.publish('/channel3', { update: false });
cometd.endBatch()

Note how the 3 publish() calls are now within a function passed to batch().
Alternatively, but less recommended, you can surround the 3 publish() calls between startBatch() and endBatch().

Warning
Remember to call endBatch() after having called startBatch().
If you don't, for example because an exception is thrown in the middle of the batch, your messages will continue to queue up, and your application will not work as expected.

Function batch() already does the correct batching for you (also in case of errors), so it's the recommended way to do message batching.

When a batch is started, subsequent API calls are not sent to the server, but instead queued up, until the batch is ended.
The end of the batch packs up all the queued messages into one single Bayeux message and send it over the network to the Bayeux server.

Message batching allow an efficient utilization of the network, as instead of making 3 requests/responses cycles, batching makes only one request/response cycle.

Batches can be made up of different API calls:

var _subscription;

cometd.batch(function()
{
    cometd.unsubscribe(_subscription);
    _subscription = cometd.subscribe('/foo', function(message) { ... });
    cometd.publish('/bar', { ... });
});

Batched messages will be processed by the Bayeux server in the order they are sent.

If you still want to risk and use the startBatch() and endBatch() calls, remember that they must be done from the same context of execution; message batching has not been designed to span multiple user interactions.
So, for example, it would be wrong to start a batch in, say, functionA (triggered by user interaction), and ending the batch in functionB (also triggered by user interaction and not called by functionA).
Similarly, it would be wrong to start a batch in functionA and then schedule (using setTimeout()) the execution of functionB to end the batch.