By:Nisarg Upadhyay | Last Updated: 2018-11-20 || Related Tips:More > Replication
ProblemHow can I send an automated email notification when SQL Server data replication latency between a publisher and subscriber is higher than 60 seconds?
SolutionTo monitor SQL Server replication, we can use a Tracer Token. The Tracer Token measures the latency between the Publisher and Distributor and the Distributor to Subscribers. This tip explains briefly about tracer tokens , how they work and how to configure them.
In this tip, I am going show how to send an email notification when latency between the Publisher and Distributor or the Publisher and Subscriber is higher than 60 seconds.
To set this up, we must create aSQL Server Agent Job that executes every fifteen minutes. The SQL Server Agent Job executes astored procedure which performs the following tasks:
Creates a new tracer token in the publication database using system stored procedure named " sp_posttracertoken ". Populates tracer token IDs using system stored procedure named " sp_helptracertokens " and stores it in #TracerToken table. Populates a recent tracer token ID from the # TracerToken table and store it in " @LiTokenID " variable. Passes the tracer token ID, stored in " @LiTokenID " to the sp_helptracertokens procedure and saves the output in #Latency table . Check the value of latency in " OVERALL_LATENCY " column of #Latency table. If it is higher than 1 minute than it sends an email notification. Replication ConfigurationFirst, let's review the replication configuration. To do that execute the following query on the publisher database.
SELECTDistributionAgent.subscriber_db [Subscriber DB],
DistributionAgent.publication [PUB Name],
RIGHT(LEFT(DistributionAgent.NAME, Len(DistributionAgent.NAME) - (Len(DistributionAgent.id) + 1 )),
Len(LEFT(DistributionAgent.NAME, Len(DistributionAgent.NAME) - (Len(DistributionAgent.id) + 1 ))) - (
10 + Len(DistributionAgent.publisher_db) + (
CASE
WHEN DistributionAgent.publisher_db = 'ALL'
THEN 1
ELSE Len(DistributionAgent.publication) + 2 END ) )) [SUBSCRIBER],
(CASE
WHEN DistributionAgent.subscription_type = '0' THEN 'Push'
WHEN DistributionAgent.subscription_type = '1' THEN 'Pull'
WHEN DistributionAgent.subscription_type = '2' THEN 'Anonymous'
ELSE Cast(DistributionAgent.subscription_type AS VARCHAR)
END ) [Subscrition Type],
DistributionAgent.publisher_db + ' - '
+ Cast(DistributionAgent.publisher_database_id AS VARCHAR) [Publisher Database],
DistributionAgent.NAME [Publisher - PublisherDB - Publication - SubscriptionName - AgentID]
FROM distribution.dbo.msdistribution_agents DistributionAgent
WHERE DistributionAgent.subscriber_db <> 'virtual'
This screen shot below is the output of the above query.

Replication Latency Check - Code Explanation
The following explains the code used to check for replication latency issues. Further down in the article is a complete code listing you can use. Also, this example uses the AdventureWorks2014 database. You will need to update the code you use to reflect the database name you are using for replication.
The following code populates the publication name and stores it in the "@lsPublication" variable. This code block must be executed in the publication database.
DECLARE @lsPublication AS sysname;SET @lsPublication = (SELECT name FROM AdventureWorks2014..syspublications WHERE name = 'Customer_Publication')
This code creates a tracer token in the publication database.
EXEC AdventureWorks2014.sys.sp_posttracertoken@Publication = @lsPublication,
@tracer_token_id = @liTokenID OUTPUT;
This INSERT command stores the information of recently created tracer tokens in the temp table.
INSERT #tracer_tokens (tracer_id, publisher_commit)EXEC AdventureWorks2014.sys.sp_helptracertokens @Publication = @lsPublication;
The following code block stores the recent tracer token ID of in " @LiTokenID " variable.
SET @liTokenID =(
SELECT TOP 1 tracer_id
FROM #tracer_tokens
ORDER BY publisher_commit DESC
)
DROP TABLE #tracer_tokens
Below is code that creates a temp table to store the latency results of a tracer token.
CREATE TABLE #Latency(
DISTRIBUTOR_LATENCY INT,
SUBSCRIBER VARCHAR(255),
SUBSCRIBER_DB VARCHAR(255),
SUBSCRIBER_LATENCY INT,
OVERALL_LATENCY INT
)
Once the table gets created, the following code block populates the latency values of token ID, stored in the " @LiTokenID " variable using the "sp_helptracertokenhistory" stored procedure and inserts it into the #Latency table.
INSERT INTO #Latency (distributor_latency, subscriber, subscriber_db, subscriber_latency, overall_latency)EXEC AdventureWorks2014.sys.sp_helptracertokenhistory
@Publication = @lsPublication,
@tracer_id = @liTokenID;
The following code block populates the default SQL Server Database Mail profile and stores it in the "@ProfileName" variable.
DECLARE @DBMailProfile TABLE (ProfileID INT, ProfileName SYSNAME, [Description] NVARCHAR(4000))DECLARE @ProfileName SYSNAME
INSERT INTO @DBMailProfile (ProfileID, ProfileName, [Description])
EXEC msdb.dbo.sysmail_help_profile_sp @profile_id = 1
SET @ProfileName = (SELECT ProfileName FROM @DBMailProfile)
The following code block checks the value of the " overall_latency " column of the #Latency table. If the value is higher than 1 minute then an email is sent.
IF (SELECT MAX(ISNULL(OVERALL_LATENCY, 100)) FROM #Latency) >= 59BEGIN
SET @lsMessage =
'<p style="font-family:Arial; font-size:10pt">There is an error in database replication. ' +
'Latency has exceeded 1 minute. This can be caused by a patch, configuration or database error. ' +
'Please Login to publisher server, then use the following command to open <b>SQL Replication Monitor</b> to determine the error.' + '<br><br>' +
'<table border=1 cellspacing=0 cellpadding=0 bgcolor=#F2F2F2><tr><td><font face="Courier New" size=2>"C:\"Program Files (x86)"\"Microsoft SQL Server"\120\Tools\Binn\SqlMonitor.exe" </font></td></tr></table>' + '<br>' +
'<b>NOTE:</b> This alert will be generated every 15 minutes until replication is caught up for the AdventureWorks2014 databases on <b>all</b> subscribers. ' +
'</p>'
EXEC msdb.dbo.sp_send_dbmail
@recipients='<a href="/cdn-cgi/l/email-protection" data-cfemail="026c6b71637065777263666a7b637b3a35426d77766e6d6d692c616d6f">[email protected]</a>',
@<a href="