Notifications overview for VSTS

Core Objects

There are three fundamental objects in the notification system:

Object Storage
Event stored in tbl_ClientEvent
Subscription stored in tbl_EventSubscription
Notification stored in tbl_EventNotification

Workflow

The actual flow can be expressed simply as well:

  • Some part of the product fires an event (WIT, Git, Gallery, etc.)
  • The notification system writes a record to tbl_ClientEvent with the event payload and starts the appropriate event processing job for the event type.
  • The event processing job reads the pending events from tbl_ClientEvent and loads subscriptions for the matching event types from tbl_EventSubscription as well as builtin and contributed subscriptions.
  • Each event is matched against each subscription. If there is a match, a notification is created. After each batch of events (up to 1000 at a time by default), the notifications are flushed to tbl_EventNotification and the appropriate notification delivery job(s) are started.
  • The delivery job reads pending notifications in batches (up to 100 by default) and delivers them.
    • Email messages are delivered in parallel (up to 8 at a time by default)
    • Service Hooks notifications are batched up and sent to the Service Hooks service for actual delivery unless...
    • ...the subscription is for Azure Service Bus for specific hosts/subscriptions - these are delivered directly from the host service without calling to the Service Hooks service at all

Additional Tables

Table Name Usage
tbl_DefaultSubscriptionAdminConfig Admin control over group subscriptions
tbl_DefaultSubscriptionUserOptOut User opt out of group subscriptions
tbl_NotificationLog Notification Diagnostic Logs
tbl_NotificationStatistics Continuously aggregated statistics

Notification Diagnostic Logs

Beginning with M131 and TFS 2018 Update 2

Extended diagnostic logs are now stored in tbl_NotificationLog. These logs can get large so they are cleaned up every few days. However, they are easily accessible via a REST navigate in a web browser. Logs are identified by LogSource and LogId. LogSource is typically a well known ID and LogId is a particular instance of that LogSource. If you happen to know the LogSource and LogId, you can refer to the log directly. Otherwise, you can specify a date range. The format of the REST API URL is:

<your host>/_apis/notification/DiagnosticLogs/LogSource/entries/LogId

or

<your host>/_apis/notification/DiagnosticLogs/LogSource/entries?startTime=time1&endTime=time2

Job Logging

Looking at the result message in Job History can be a big help when troubleshooting what's happening with event processing and notification delivery. However, it is limited to 8k and really isn't structured in any way - it is essentially a sequence of trace messages. Extended diagnostics are recorded for every single job run. The JobId is used as the LogSource and each run of the job gets a unique LogId - it's just a GUID with no further meaning. The result message in JobHistory contains the URL for that particular run.

To get the diagnostic log for the Work Item Processing job (915F48F2-1B64-40D9-A43F-FE2528B4F296) with a LogID of 68DE62E0-AA65-47BB-9369-FCD534B9A69A:

https://mseng.visualstudio.com/_apis/notification/DiagnosticLogs/915F48F2-1B64-40D9-A43F-FE2528B4F296/entries/68DE62E0-AA65-47BB-9369-FCD534B9A69A

If you don't know the LogId, you can ask for entries using a date range like this:

https://mseng.visualstudio.com/_apis/notification/DiagnosticLogs/915F48F2-1B64-40D9-A43F-FE2528B4F296/entries?startTime=2018-03-01T01:05:21.2253819Z&endTime=2018-03-01T12:05:21.2253819Z

This will return an array of logs. There can be a lot of logs and they can be on the larger size of things so the smaller you can make the date range the better.

Subscription Diagnostics Logging

We can enable even more diagnostic logging for a particular subscription. It can be enabled for even processing and/or notification delivery. The format for the LogSource is the subscription ID encoded into a well known GUID.

For event processing the LogSource is 08675309-EEEE-0000-0000-nnnnnnnnnnnn and for notification delivery the format is 08675309-DDDD-0000-0000-nnnnnnnnnnnn where nnnnnnnnnnnn is a leading zero padded subscription Id in decimal. The Job History result message and the diagnostic log will have a list of URLs for all of the subscription diagnostic logs that it generated. Once enabled, subscriptions diagnostics for 25 events for up to an hour and for 25 deliveries for an hour.

You can enable access to subscription diagnostics in the browser by appending diagnostics=true to the notifications page you are viewing. For example, on your personal subscriptions:

<your host>/_notifications?diagnostics=true

This will add an option to the "..." menu to allow you to enable/disable diagnostics for a particular subscription.

These settings are exposed via a REST API as well.

 

To enable processing and delivery diagnostics for a subscription, make an HTTP PUT call with the following body:

 {
  "evaluationTracing": { "enabled": true },
  "deliveryTracing": { "enabled": true }
}

The URL format is:< yourhost>/_apis/notification/subscriptions/SubscriptionId/diagnostics?api-version=4.1-preview.1

If you issue an HTTP GET, you will receive the current status. The results will look like this:

 {
  "evaluationTracing": {
    "enabled": true,
    "endDate": "2018-03-01T20:03:59.929866Z",
    "startDate": "2018-03-01T19:03:59.929866Z",
    "maxTracedEntries": 25
  },
  "deliveryTracing": {
    "enabled": true,
    "endDate": "2018-03-01T20:03:59.929866Z",
    "startDate": "2018-03-01T19:03:59.929866Z",
    "maxTracedEntries": 25
  }
}

Notifications Jobs

Job IDs (as of TFS 2018)

Job Id Job Type Scope(s) Schedule
915f48f2-1b64-40d9-a43f-fe2528b4f296 Event Processing WIT on demand
9a688110-9e33-4cdc-affd-75d16303e7f1 Event Processing Git on demand
a4804dcf-4bb6-4109-b61c-e59c2e8a9ff7 Event Processing Any other publisher on demand
631f49b3-46e1-42ec-8fff-081bd176c18a Email Delivery WIT on demand
8833fc71-42ca-441b-ab12-25314877772d Email Delivery Git on demand
68063fb6-64c6-4b56-924f-501406d6e7e7 Email Delivery System generated on demand
a96d6177-beef-477a-a2ee-2c31433214d0 Email Delivery Any other publisher on demand
b7494ac7-dee6-4342-ad43-5d6944576645 Service Hooks Delivery Non-Service Bus WIT on demand
d745068c-7dab-4135-8665-6a7e1c20f29c Service Hooks Delivery Non-Service Bus Git on demand
a0c22f34-652e-4b9c-a06b-3f4afe4be458 Service Hooks Delivery Non-Service Bus Any other publisher on demand
ce76d8b3-3e04-4758-8430-4e9266d38938 Service Hooks Delivery Service Bus (limited use) WIT on demand
1214f948-151c-4f98-9ae2-1c9816db1eea Service Hooks Delivery Service Bus (limited use) Git on demand
c1c9013c-c4a9-4bb1-acca-7cd6b5ba5126 Service Hooks Delivery Service Bus (limited use) Any other publisher on demand
d6be0cce-5320-45de-9297-596a9be68a37 Group Service Hooks Delivery Any publisher on demand
007b33d4-c189-4576-96dd-36178e2f6803 SOAP Delivery All publishers on demand
0d30ca11-162c-4134-9ba8-42582f3890A5 Notification and Event Cleanup Job Any events, notifications, statistics, diagnostic logs daily
5ec103d2-7505-4705-b78e-2faf19127a12 Subscription Cleanup Job Subscriptions marked for deletion daily
eab3ce0c-a4f4-4460-82a0-6cf6e8bf0a8b Backlog status Notifications and Events on demand

SQL JobHistory Filters

Processing Job

JobId in ('915f48f2-1b64-40d9-a43f-fe2528b4f296', '9a688110-9e33-4cdc-affd-75d16303e7f1', 'a4804dcf-4bb6-4109-b61c-e59c2e8a9ff7')

Email Delivery Jobs

JobId in ('631f49b3-46e1-42ec-8fff-081bd176c18a', '8833fc71-42ca-441b-ab12-25314877772d', 'a96d6177-beef-477a-a2ee-2c31433214d0')

Service Hooks Delivery Jobs

Non Service Bus

JobId in ('b7494ac7-dee6-4342-ad43-5d6944576645', 'd745068c-7dab-4135-8665-6a7e1c20f29c', 'a0c22f34-652e-4b9c-a06b-3f4afe4be458')

Service Bus

JobId in ('ce76d8b3-3e04-4758-8430-4e9266d38938', '1214f948-151c-4f98-9ae2-1c9816db1eea', 'c1c9013c-c4a9-4bb1-acca-7cd6b5ba5126')

Groups

JobId in ('d6be0cce-5320-45de-9297-596a9be68a37')

Notifications Legacy Delivery

JobId in ('007b33d4-c189-4576-96dd-36178e2f6803')

Event Type groupings

WIT Email and Service hooks

JobId in ('915f48f2-1b64-40d9-a43f-fe2528b4f296', '631f49b3-46e1-42ec-8fff-081bd176c18a', 'b7494ac7-dee6-4342-ad43-5d6944576645', 'ce76d8b3-3e04-4758-8430-4e9266d38938')

Git Email and Service hooks

JobId in ('9a688110-9e33-4cdc-affd-75d16303e7f1', '8833fc71-42ca-441b-ab12-25314877772d', 'd745068c-7dab-4135-8665-6a7e1c20f29c', '1214f948-151c-4f98-9ae2-1c9816db1eea')

Any other events Email and Service hooks

JobId in ('a4804dcf-4bb6-4109-b61c-e59c2e8a9ff7', 'a96d6177-beef-477a-a2ee-2c31433214d0', 'a0c22f34-652e-4b9c-a06b-3f4afe4be458', 'c1c9013c-c4a9-4bb1-acca-7cd6b5ba5126')