IF EXISTS (SELECT * FROM sysobjects
WHERE id = object_id('dbo.check_for_blocks')
AND sysstat & 0xf = 4)
DROP PROCEDURE dbo.check_for_blocks
GO
CREATE PROCEDURE check_for_blocks
@taskName VARCHAR(30) = "Block Monitor",
@userName VARCHAR(30) = "<your important user>",
@mailTo VARCHAR(30) = "DBA"
AS
/* see if any important users are blocked */
DECLARE @CMD VARCHAR(255),
@CMDstub VARCHAR(255),
@CMDstatus INT,
@localCMDstatus INT,
@spid SMALLINT,
@dbid SMALLINT,
@blocker SMALLINT,
@blockersuid SMALLINT
SET NOCOUNT ON
/* only allow one instance of the block monitor to run */
IF (SELECT COUNT(*)
FROM master..sysprocesses
WHERE spid <> @@SPID
AND program_name LIKE ("SQLEXEC - TSQL Task #%")
AND CONVERT(INT,SUBSTRING(RTRIM(program_name),
CHARINDEX("#", program_name) + 1,
DATALENGTH(program_name) - CHARINDEX("#", program_name)))
IN (SELECT id FROM msdb..systasks
WHERE name = (@taskName))) = 0
BEGIN
/* get the process id and user id for the first block encountered */
SELECT @spid = spid, @dbid = dbid, @blocker = blocked
FROM master..sysprocesses
WHERE blocked <> 0
AND suid = SUSER_ID(@userName)
/* if no blocks, we're done */
IF @spid IS NOT NULL
BEGIN
/* wait five seconds, if still blocked take action */
WAITFOR DELAY "00:00:10"
SELECT @spid = spid, @dbid = dbid, @blocker = blocked
FROM master..sysprocesses
WHERE blocked <> 0
AND suid = SUSER_ID(@userName)
IF @spid IS NOT NULL
BEGIN
SELECT @blockersuid = suid FROM master..sysprocesses WHERE spid = @blocker
SELECT @CMDstatus = 0
SELECT @CMDstub = "Login " + UPPER(@UserName) + " (spid " + CONVERT(VARCHAR(3),@spid) +
") blocked in database " + UPPER(DB_NAME(@dbid)) + " by login " +
UPPER(SUSER_NAME(@blockersuid)) + " (spid " + CONVERT(VARCHAR(3),@blocker)
+ "). [admin.check_for_blocks] " + CONVERT(VARCHAR(20), getdate())
SELECT @CMD = "net send bwunder " + @CMDstub
EXEC @localCMDstatus = master..xp_cmdshell @CMD, no_output
IF (@localCMDStatus <> 0) SELECT @CMDstatus = @CMDstatus + 1
/* add more folks if you want them to get the message */
/*
SELECT @CMD = "net send xxxxxxx " + @CMDstub
EXEC @localCMDstatus = master..xp_cmdshell @CMD, no_output
IF (@localCMDStatus <> 0) SELECT @CMDstatus = @CMDstatus + 1
*/
IF (@CMDstatus <> 0) -- failed
BEGIN
SELECT @CMD = CONVERT(CHAR(1),@CMDStatus) +
" block alert network broadcast messages FAILED!" +
" (admin..check_for_blocks)"
RAISERROR(@CMD,1,2) WITH LOG
END
/* send a report of the blocking hierarchy */
EXEC master..xp_sendmail @recipients = @mailTo,
@subject = 'Blocking Report',
@message = @CMDstub,
@query = 'admin..find_blocker'
/* wait one minute so the block messages don't flood
the network with messages */
WAITFOR DELAY "00:01:00"
END -- send messages
END -- blocks found
END -- block monitor already running
EXEC msdb..sp_purgehistory @taskName -- system procedure, see BOL
GO