Events

iModelHub sends IModelHubEvents for operations that occur on a particular iModel.

To receive events, the user has to:

  1. Subscribe to events from a single iModel, specifying types of events they want to receive.
  2. Get an EventSAS token, that is used to authenticate to Events service. See getting events.
  3. Send a request to get and delete the first event from that subscription's queue. See getting events.

Instead of repeating steps 2 and 3, it's possible to create a listener that continuously receives events from a subscription.

Event Types

When a user subscribes to events, they have to provide EventTypes of IModelHubEvents they want to receive. iModelHub sends these events:

Type Description
AllCodesDeletedEvent All HubCodes for a Briefcase are deleted.
AllLocksDeletedEvent All Locks for a Briefcase are deleted.
BriefcaseDeletedEvent A Briefcase was deleted.
ChangeSetPostPushEvent A ChangeSet was successfully pushed.
ChangeSetPrePushEvent A ChangeSet push has started.
CodeEvent One or more HubCodes were updated.
IModelDeletedEvent An iModel was deleted.
LockEvent One or more Locks were updated.
VersionEvent A new named Version was created.

CodeEvent and LockEvent includes every updated HubCode or Lock value, so it tends to be quite chatty. It's recommended to not subscribe to these events, unless they are necessary for your workflow.

Creating Events Subscription

To receive IModelHubEvents, user has to create an EventSubscription. Creating a subscription requires the user to specify an array of event types they want to receive.

Creating subscription requires user to have an access token and have a valid iModel id.

Example:

  const subscription: EventSubscription = await imodelHubClient.events
    .subscriptions.create(authorizedRequestContext, imodelId, ["ChangeSetPostPushEvent", "VersionEvent"]);

After creating the subscription, subscription.wsgId can be used when subscription id is requested.

Each subscription contains its own queue of events. Subscriptions expire after an hour of inactivity.

Getting events

First user has to get an EventSAS token.

  const sasToken: EventSAS = await imodelHubClient.events.getSASToken(authorizedRequestContext, imodelId);

Then they can get the first event from their subscription's queue. This will immediately delete the event from the queue.

  const event: IModelHubEvent | undefined = await imodelHubClient.events
    .getEvent(requestContext, sasToken.sasToken!, sasToken.baseAddress!, subscription.wsgId, 60);

If EventHandler.getEvent is called with a timeout duration specified, this request will perform long polling. If this request didn't find an event on the queue, it would wait until one is available or the timeout expires. This way the event reaches the client faster and less requests are sent between the client and the service.

EventHandler.getEvent can fail because EventSAS has expired. It can also return undefined if no events have been found.

Creating Events Listener

EventHandler.createListener can be used to handle repeated calls to EventHandler.getEvent and EventHandler.getSASToken.

Authentication callback example, similar to getting access token. AuthorizationToken could be retrieved from credentials stored somewhere else or refreshed before it expires.

async function authenticate(): Promise<AccessToken> {
  const requestContext = new ClientRequestContext();
  const authorizationToken: AuthorizationToken = await authorizationClient
    .getToken(requestContext, userCredentials);
  return imodelHubClient.getAccessToken(requestContext, authorizationToken);
}

Listener callback example. This callback just logs the type of the IModelHubEvent received.

function processEvent(event: IModelHubEvent): void {
  Logger.logInfo("example", `Event of the type ${typeof event} received.`);
}

To create the listener itself, user has to have an iModel id and have an event subscription.

  const deleteCallback = await imodelHubClient.events  // tslint:disable-line:await-promise
    .createListener(requestContext, authenticate, subscription.wsgId, imodelId, processEvent);

Deleting the listener after it's no longer necessary is just calling the callback received when creating it.

  deleteCallback();

Event listener will work in the background, continuously getting events for a specific EventSubscription. Once an IModelHubEvent is received, all registered listener callbacks for that subscription are called. If EventSAS expires, EventHandler.getSASToken will be called automatically. If AccessToken expires, authentication callback will be called to refresh that token.

Event listener will stop if there's an error getting events for that subscription or when all listeners for it are deleted. In the latter case, any outstanding long polling requests could still complete.

Listeners for the same subscription will only make a single event request at a time. Listeners for different subscriptions work independently.

Last Updated: 13 June, 2024