Skip to content

Commit 154199f

Browse files
authored
Merge pull request #54 from pozil/pozil/publishBatch
feat: publish event batch
2 parents 95cee29 + 7031b88 commit 154199f

File tree

5 files changed

+371
-140
lines changed

5 files changed

+371
-140
lines changed

README.md

Lines changed: 131 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ See the [official Pub/Sub API repo](https://github.com/developerforce/pub-sub-ap
1515
- [Logging](#logging)
1616
- [Quick Start Example](#quick-start-example)
1717
- [Other Examples](#other-examples)
18-
- [Publish a platform event](#publish-a-platform-event)
18+
- [Publish a single platform event](#publish-a-single-platform-event)
19+
- [Publish a batch of platform events](#publish-a-batch-of-platform-events)
1920
- [Subscribe with a replay ID](#subscribe-with-a-replay-id)
2021
- [Subscribe to past events in retention window](#subscribe-to-past-events-in-retention-window)
2122
- [Subscribe using a managed subscription](#subscribe-using-a-managed-subscription)
@@ -24,6 +25,7 @@ See the [official Pub/Sub API repo](https://github.com/developerforce/pub-sub-ap
2425
- [Common Issues](#common-issues)
2526
- [Reference](#reference)
2627
- [PubSubApiClient](#pubsubapiclient)
28+
- [PublishCallback](#publishcallback)
2729
- [SubscribeCallback](#subscribecallback)
2830
- [SubscriptionInfo](#subscriptioninfo)
2931
- [EventParseError](#eventparseerror)
@@ -44,7 +46,7 @@ In v4 and earlier versions of this client:
4446
In v5:
4547

4648
- you pass your configuration with an object in the client constructor. The `.env` file is no longer a requirement, you are free to store your configuration where you want.
47-
- you connect with a unique `connect()` method.
49+
- you connect with a unique [`connect()`](#async-connect--promisevoid) method.
4850

4951
### Event handling
5052

@@ -206,34 +208,38 @@ Here's an example that will get you started quickly. It listens to up to 3 accou
206208
207209
// Prepare event callback
208210
const subscribeCallback = (subscription, callbackType, data) => {
209-
if (callbackType === 'event') {
210-
// Event received
211-
console.log(
212-
`${subscription.topicName} - ``Handling ${event.payload.ChangeEventHeader.entityName} change event ` +
213-
`with ID ${event.replayId} ` +
214-
`(${subscription.receivedEventCount}/${subscription.requestedEventCount} ` +
215-
`events received so far)`
216-
);
217-
// Safely log event payload as a JSON string
218-
console.log(
219-
JSON.stringify(
220-
event,
221-
(key, value) =>
222-
/* Convert BigInt values into strings and keep other types unchanged */
223-
typeof value === 'bigint'
224-
? value.toString()
225-
: value,
226-
2
227-
)
228-
);
229-
} else if (callbackType === 'lastEvent') {
230-
// Last event received
231-
console.log(
232-
`${subscription.topicName} - Reached last of ${subscription.requestedEventCount} requested event on channel. Closing connection.`
233-
);
234-
} else if (callbackType === 'end') {
235-
// Client closed the connection
236-
console.log('Client shut down gracefully.');
211+
switch (callbackType) {
212+
case 'event':
213+
// Event received
214+
console.log(
215+
`${subscription.topicName} - Handling ${event.payload.ChangeEventHeader.entityName} change event ` +
216+
`with ID ${data.replayId} ` +
217+
`(${subscription.receivedEventCount}/${subscription.requestedEventCount} ` +
218+
`events received so far)`
219+
);
220+
// Safely log event payload as a JSON string
221+
console.log(
222+
JSON.stringify(
223+
data,
224+
(key, value) =>
225+
/* Convert BigInt values into strings and keep other types unchanged */
226+
typeof value === 'bigint'
227+
? value.toString()
228+
: value,
229+
2
230+
)
231+
);
232+
break;
233+
case 'lastEvent':
234+
// Last event received
235+
console.log(
236+
`${subscription.topicName} - Reached last of ${subscription.requestedEventCount} requested event on channel. Closing connection.`
237+
);
238+
break;
239+
case 'end':
240+
// Client closed the connection
241+
console.log('Client shut down gracefully.');
242+
break;
237243
}
238244
};
239245
@@ -345,9 +351,12 @@ Here's an example that will get you started quickly. It listens to up to 3 accou
345351
346352
## Other Examples
347353
348-
### Publish a platform event
354+
### Publish a single platform event
349355
350-
Publish a `Sample__e` Platform Event with a `Message__c` field:
356+
> [!NOTE]
357+
> For best performances, use `publishBatch` when publishing event batches.
358+
359+
Publish a single `Sample__e` platform events with a `Message__c` field using [publish](#async-publishtopicname-payload-correlationkey--promisepublishresult):
351360
352361
```js
353362
const payload = {
@@ -359,6 +368,35 @@ const publishResult = await client.publish('/event/Sample__e', payload);
359368
console.log('Published event: ', JSON.stringify(publishResult));
360369
```
361370
371+
### Publish a batch of platform events
372+
373+
Publish a batch of `Sample__e` platform events using [publishBatch](#async-publishbatchtopicname-events-publishcallback):
374+
375+
```js
376+
// Prepare publish callback
377+
const publishCallback = (info, callbackType, data) => {
378+
switch (callbackType) {
379+
case 'publishResponse':
380+
console.log(JSON.stringify(data));
381+
break;
382+
}
383+
};
384+
385+
// Prepare events
386+
const events = [
387+
{
388+
payload: {
389+
CreatedDate: new Date().getTime(), // Non-null value required but there's no validity check performed on this field
390+
CreatedById: '005_________', // Valid user ID
391+
Message__c: { string: 'Hello world' } // Field is nullable so we need to specify the 'string' type
392+
}
393+
}
394+
];
395+
396+
// Publish event batch
397+
client.publishBatch('/event/Sample__e', events, publishCallback);
398+
```
399+
362400
### Subscribe with a replay ID
363401
364402
Subscribe to 5 account change events starting from a replay ID:
@@ -416,7 +454,7 @@ When working with high volumes of events you can control the incoming flow of ev
416454
This is the overall process:
417455
418456
1. Pass a number of requested events in your subscribe call.
419-
1. Handle the `lastevent` callback type from subscribe callback to detect the end of the event batch.
457+
1. Handle the `lastevent` [callback type](#subscribecallback) from subscribe callback to detect the end of the event batch.
420458
1. Subscribe to an additional batch of events with `client.requestAdditionalEvents(...)`. If you don't request additional events at this point, the gRPC subscription will close automatically (default Pub/Sub API behavior).
421459
422460
The code below illustrate how you can achieve event flow control:
@@ -429,20 +467,24 @@ try {
429467
430468
// Prepare event callback
431469
const subscribeCallback = (subscription, callbackType, data) => {
432-
if (callbackType === 'event') {
433-
// Logic for handling a single event.
434-
// Unless you request additional events later, this should get called up to 10 times
435-
// given the initial subscription boundary.
436-
} else if (callbackType === 'lastEvent') {
437-
// Last event received
438-
console.log(
439-
`${eventEmitter.getTopicName()} - Reached last requested event on channel.`
440-
);
441-
// Request 10 additional events
442-
client.requestAdditionalEvents(eventEmitter, 10);
443-
} else if (callbackType === 'end') {
444-
// Client closed the connection
445-
console.log('Client shut down gracefully.');
470+
switch (callbackType) {
471+
case 'event':
472+
// Logic for handling a single event.
473+
// Unless you request additional events later, this should get called up to 10 times
474+
// given the initial subscription boundary.
475+
break;
476+
case 'lastEvent':
477+
// Last event received
478+
console.log(
479+
`${eventEmitter.getTopicName()} - Reached last requested event on channel.`
480+
);
481+
// Request 10 additional events
482+
client.requestAdditionalEvents(eventEmitter, 10);
483+
break;
484+
case 'end':
485+
// Client closed the connection
486+
console.log('Client shut down gracefully.');
487+
break;
446488
}
447489
};
448490
@@ -541,16 +583,26 @@ Returns: Promise that holds the channel's [connectivity state](https://grpc.gith
541583
542584
#### `async publish(topicName, payload, [correlationKey]) → {Promise.<PublishResult>}`
543585
544-
Publishes a payload to a topic using the gRPC client.
586+
Publishes an payload to a topic using the gRPC client. This is a synchronous operation, use `publishBatch` when publishing event batches.
545587
546588
Returns: Promise holding a `PublishResult` object with `replayId` and `correlationKey`.
547589
548590
| Name | Type | Description |
549591
| ---------------- | ------ | ----------------------------------------------------------------------------------------- |
550-
| `topicName` | string | name of the topic that we're subscribing to |
551-
| `payload` | Object | |
592+
| `topicName` | string | name of the topic that we're publishing on |
593+
| `payload` | Object | payload of the event that is being published |
552594
| `correlationKey` | string | optional correlation key. If you don't provide one, we'll generate a random UUID for you. |
553595
596+
#### `async publishBatch(topicName, events, publishCallback)`
597+
598+
Publishes a batch of events using the gRPC client's publish stream.
599+
600+
| Name | Type | Description |
601+
| ----------------- | ----------------------------------- | ------------------------------------------------- |
602+
| `topicName` | string | name of the topic that we're publishing on |
603+
| `events` | [PublisherEvent](#publisherEvent)[] | events to be published |
604+
| `publishCallback` | [PublishCallback](#publishCallback) | callback function for handling publish responses. |
605+
554606
#### `async subscribe(topicName, subscribeCallback, [numRequested])`
555607
556608
Subscribes to a topic.
@@ -612,6 +664,35 @@ Request additional events on an existing managed subscription.
612664
| `subscriptionId` | string | managed subscription ID. |
613665
| `numRequested` | number | number of events requested. |
614666
667+
### PublishCallback
668+
669+
Callback function that lets you process batch publish responses.
670+
671+
The function takes three parameters:
672+
673+
| Name | Type | Description |
674+
| -------------- | ----------------------- | --------------------------------------------------------------------- |
675+
| `info` | `{ topicName: string }` | callback information |
676+
| `callbackType` | string | name of the callback type (see table below). |
677+
| `data` | [Object] | data that is passed with the callback (depends on the callback type). |
678+
679+
Callback types:
680+
681+
| Name | Callback Data | Description |
682+
| ----------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------- |
683+
| `publishResponse` | [PublishResponse](#publishresponse) | Client received a publish response. The attached data is the publish confirmation for a batch of events. |
684+
| `error` | Object | Signals an event publishing error or a gRPC stream error. |
685+
| `grpcKeepalive` | `{ schemaId: string, rpcId: string }` | Server publishes this gRPC keep alive message every 270 seconds (or less) if there are no events. |
686+
| `grpcStatus` | Object | Misc gRPC stream status information. |
687+
688+
#### PublishResponse
689+
690+
| Name | Type | Description |
691+
| ---------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------- |
692+
| `schemaId` | string | topic schema ID |
693+
| `rpcId` | string | RPC ID |
694+
| `results` | `{ replayId: string, correlationKey: string }[]` | Event publish confirmations. Each confirmation contains the replay ID and a correlation key. |
695+
615696
### SubscribeCallback
616697
617698
Callback function that lets you process incoming Pub/Sub API events while keeping track of the topic name and the volume of events requested/received.

0 commit comments

Comments
 (0)