Av rating:
Total votes: 16
Total comments: 16


Robyn Page and Phil Factor
Process Delegation Workbench
07 June 2007

/*
Here is a way of designing part of a SQL Server Database application so
it seems faster to the user. 

Often, when you are designing a database-intensive application or website,
you will often merely want the application layer to signal that a job should
be started, and return back immediately without blocking. How nice to have
a secure system that buffers up routines that aren't time-critical and
irons out peaks in demand, all without having to use Service Broker.

This is done by delegating processes that  aren't time-critical to 
another database connection. As a by-product,  you can then tighten up 
security, so that back-office functions are never done by user logins. 

The technique is to delegate as much processing as possible on to another
'back-office' process under a different connection login via a queue. This
is quite a commonly-used technique, and uses the Alerts and Jobs
 within
SQL Server Agent.

In this Workshop, Phil and I will show how it is done, using user-defined 
alerts in either SQL Server 2000 or SQL Server 2005. It is, of course, 
more convenient to use SSMS interactively to set up alerts and jobs but here
we'll script them so you can try it out more quickly and easily.
 

For the technical background to User-Defined Alerts, you might like to read
SQL Server 2000: User Settable Object (Catchy title?) or The SQL 2005 version

Here is a skeletal system that is designed for the dispatch of email 
information from a database-driven website. It can be used for almost any 
time-intensive or security-sensitive process that does not require the 
immediate return of the results to the user, such as processing an invoice, 
printing out a dispatch note, doing a trade confirmation or trade settlement, 
resizing an uploaded image, or indexing text.

the first thing we must do is to create the log, queue and queue parameter
table. The log is necessary to tell us how the queue is getting on, and to
contain errors and warnings. we need a queue parmeter table because each
process that we add will have different parameters.


The steps in the process:
 . The user calls a function to send an email
 . The function puts an entry in the queue table to say he wants an email sent
 . the procedure puts the parameters into a paramter table.
 . The procedure sets a user-counter to 1 to fire an alert
 . the user returns
 . the alert fires and runs a job
 . The job step runs a procedure that empties the queue, running every task
       that has been put in the queue, including sending the email


Firstly, you must create a database called BackOfficeDemo


Then run this script....(should run in either SQL 2000 or SQL 2005

*/
--------------------------------Start of build script

USE BackOfficeDemo


SET NUMERIC_ROUNDABORT OFF
GO
SET ANSI_PADDINGANSI_WARNINGSCONCAT_NULL_YIELDS_NULL
               
ARITHABORTQUOTED_IDENTIFIERANSI_NULLS ON
GO
IF EXISTS (SELECT FROM tempdb..sysobjects 
       
WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error INT)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
PRINT N'Creating login ''TypicalUser'''
/* first off, we create our user with the minimal permissions*/
IF NOT EXISTS (SELECT FROM master.dbo.syslogins 
               
WHERE loginname N'TypicalUser')
   
EXEC sp_addlogin N'TypicalUser''typical'
GO  --we'll use him to make the request in the demo
--and now we'll grant him access to the database
IF NOT EXISTS (SELECT sid FROM sysusers WHERE sid 
   
(SELECT sid FROM master.dbo.syslogins
       
WHERE isntname 
           
AND loginname 'TypicalUser') AND hasdbaccess 1)
   
EXEC sp_grantdbaccess N'TypicalUser'N'TypicalUser'
GO
BEGIN TRANSACTION
GO
PRINT N'Creating [dbo].[log]'
/* firrstly we create a log table that we will use to see the progress
of the procedure, and report errors etc. */
GO
IF EXISTS (SELECT FROM sysobjects --delete it if it exists
       
WHERE id=OBJECT_ID('log')) 
               
DROP TABLE [Log]

CREATE TABLE [dbo].[log]
(/* this table is used to track what happens. we'll be able to see
what happens, when, using which login*/
[log_ID] [int] NOT NULL IDENTITY(11),
[type] [int] NOT NULL,
[LogString] [varchar] (7000)  NOT NULL,
[InsertionDate] [datetime] NOT NULL 
   
CONSTRAINT [DF_log_InsertionDate] DEFAULT (GETDATE()),
[User_ID] [int] NULL,
[CurrentUser] [nvarchar] (50)  NOT NULL 
   
CONSTRAINT [DF_log_CurrentUser] 
           
DEFAULT (CONVERT(NVARCHAR(50),USER_NAME())),
[SPid] INT  NOT NULL 
   
CONSTRAINT [DF_log_SPid] 
           
DEFAULT (@@SPid),
[LoginName] [nvarchar] (50)  NOT NULL 
   
CONSTRAINT [DF_Log_LoginName] 
           
DEFAULT (CONVERT(NVARCHAR(50),SUSER_SNAME())),
/* normally, you will also store the key to the user's session for audit 
purposes, particularly on a website where all users will be using the 
same login */
[Comment] [varchar] (30)  NULL
)
GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=BEGIN INSERT INTO #tmpErrors (Error
                           
SELECT BEGIN TRANSACTION END
GO
PRINT N'Creating primary key [PK_log] on [dbo].[log]'
GO
ALTER TABLE [dbo].[log] 
   
ADD CONSTRAINT [PK_log] PRIMARY KEY CLUSTERED  ([log_ID])
GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=BEGIN INSERT INTO #tmpErrors (Error
   
SELECT BEGIN TRANSACTION END
GO
PRINT N'Creating [dbo].[QueuedProcess]'
/*
Here we have a very simple queue, so we can pass requests to the 
'backoffice' process.
*/
GO
IF EXISTS (SELECT FROM sysobjects 
       
WHERE id=OBJECT_ID('QueuedProcess')) DROP TABLE [QueuedProcess]
CREATE TABLE [dbo].[QueuedProcess]
(
[QueuedProcess_ID] [int] NOT NULL IDENTITY(11),
[insertionDate] [datetime] NOT NULL 
   
CONSTRAINT [DF_QueuedProcess_insertionDate] 
       
DEFAULT (GETDATE()),--the time the task was inserted
[CompletionDate] [datetime] NULL,--when the job was done
[Process] [int] NOT NULL --this is just an integer for now (normally FK)
   
CONSTRAINT [DF_QueuedProcess_Process] DEFAULT (1),
[Comment/error] [varchar] (2000)  NULL--in case..(useful for debugging)
)

GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=
   
BEGIN 
   INSERT INTO 
#tmpErrors (ErrorSELECT 
   
BEGIN TRANSACTION 
   END
GO
PRINT N'Creating primary key [PK_QueuedProcess] on [dbo].[QueuedProcess]'
GO
ALTER TABLE [dbo].[QueuedProcess] 
   
ADD CONSTRAINT [PK_QueuedProcess] 
       
PRIMARY KEY CLUSTERED  ([QueuedProcess_ID])
GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=
   
BEGIN 
   INSERT INTO 
#tmpErrors (ErrorSELECT 
   
BEGIN TRANSACTION 
   END
GO
PRINT N'Creating [dbo].[QueuedProcessParameter]'
GO
/*
Because processes can have different parameters, we'll place them in a 
separate table. This allows us to use the same queuing mechanism for a 
lot of different processes
*/
IF EXISTS (SELECT FROM sysobjects 
       
WHERE id=OBJECT_ID('QueuedProcessParameter')) 
               
DROP TABLE [QueuedProcessParameter]
CREATE TABLE [dbo].[QueuedProcessParameter]
(
[QueuedProcessParameter_ID] [int] NOT NULL IDENTITY(11),
[QueuedProcess_ID] [int] NOT NULL,
[parameter] [varchar] (50) NULL,--simple name of parameter
--this would normally be a FK and you'd be able to check... 
[value] [sql_variant] NULL--the actual value passed
)

GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=BEGIN INSERT INTO #tmpErrors (Error
                                   
SELECT BEGIN TRANSACTION END

PRINT 
N'Creating [dbo].[spEmailSomething]'
GO
IF EXISTS (SELECT FROM sysobjects 
       
WHERE id=OBJECT_ID('spEmailSomething')) 
               
DROP PROCEDURE [spEmailSomething]

/* now we have the basic tables, we'' write a dummy procedure that
would ultimately run the task you wanted. It is dummy so as to 
allow us to debug and check the plumbing. This is later fleshed 
out to provide the functionality.*/
GO
CREATE PROCEDURE spEmailSomething (@queuedProcess_ID INT)
AS
DECLARE 
@Parameters VARCHAR(8000)
DECLARE @Rowcount INT

SELECT 
@parameters=COALESCE(@parameters,'')
                   +
parameter+'='+CONVERT(VARCHAR(2000),value)+', '
FROM QueuedProcessParameter 
WHERE queuedProcess_ID=@QueuedProcess_ID
IF @rowcount=0
   
BEGIN
   INSERT INTO 
[log] ([type]logstring)
       
SELECT 23,'no parameters sent to spEmailSomething for process '
                               
+CONVERT(VARCHAR(10),@QueuedProcess_ID)
   
RETURN 1
   
END
INSERT INTO 
[log] ([type]logstring)
   
SELECT 21,'sending email: '+@parameters 
       
+' for queued process '+CONVERT(VARCHAR(10),@QueuedProcess_ID)
/* Here we add the code to actually send the email */
INSERT INTO [log] ([type]logstring)
   
SELECT 22,'Successful email sent for queued process '
       
+CONVERT(VARCHAR(10),@QueuedProcess_ID)
RETURN 0

GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=BEGIN INSERT INTO #tmpErrors (Error
       
SELECT BEGIN TRANSACTION END
GO

PRINT N'Creating [dbo].[spExecuteQueuedActions]'
GO
IF EXISTS (SELECT FROM sysobjects 
       
WHERE id=OBJECT_ID('spExecuteQueuedActions')) 
               
DROP PROCEDURE [spExecuteQueuedActions]
GO
/* the next job is the routine that services the queue. This will actually be
run by the agent and you will be able to assign a login to the task. It will
be allowed to do heap powerful magic. At the moment it will just write out
diagnostic information. Note that it will need to empty the entire queue as we
will prevent the alert triggering more than a certain number of times */
CREATE PROCEDURE spExecuteQueuedActions
AS
DECLARE 
@error INT
DECLARE 
@rc INT
DECLARE 
@nextprocess_ID INT
DECLARE 
@process INT
EXECUTE 
sp_user_counter1 0   --set the user counter to zero
--whatever we do, we want to prevent premature reentrancy. The agent task
--will only run once, and will not run again until the first one finishes
WHILE 1=--for ever until a break
   
BEGIN
   SELECT TOP 
@nextProcess_ID=queuedProcess_ID,@process=process
      
FROM queuedProcess WHERE completionDate IS NULL
      
SELECT @error @@error@rc @@rowcount

   
IF (@rc=OR @error<>0BREAK    

   UPDATE queuedProcess SET completionDate=GETDATE() 
       
WHERE queuedprocess_ID=@nextProcess_ID
   
SELECT @error=@@Error
   
IF @Error<>BREAK
   IF 
@process=1
       
BEGIN
       EXECUTE 
@error=spEmailSomething @nextProcess_ID
       
END
   
--else if @process=2 execute spAnotherprocess
   --else if @process=3 execute spYetAnotherprocess
   
ELSE
   INSERT INTO 
[log] ([type]logstring)
       
SELECT 41,'Unknown process '+CONVERT(VARCHAR(10),@process)
   
IF @error=SELECT @error=@@Error
       
IF @Error<>BREAK
   END
IF 
@error<>0--if there has been an error it will appear in the
   
BEGIN   --agent history but it is nice to log it too
   
INSERT INTO [log] ([type]logstring)
       
SELECT 41,'Error '+CONVERT(VARCHAR(10),@error)
   
END
--because all the work is done
INSERT INTO [log] ([type]logstring)
       
SELECT 43,'Completed all tasks'

GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT=0
   
BEGIN 
   INSERT INTO 
#tmpErrors (Error
       
SELECT BEGIN TRANSACTION 
   END
GO
PRINT N'Creating [dbo].[spSendAnEmail]'
GO
IF EXISTS (SELECT FROM sysobjects 
       
WHERE id=OBJECT_ID('spSendAnEmail')) 
               
DROP PROCEDURE [spSendAnEmail]

GO
CREATE PROCEDURE spSendAnEmail
/* this is the test procedure to be run by the application using the
'typicalUser' login */
@To VARCHAR(30),
@From  VARCHAR(30),
@cc VARCHAR(30)='',
@bcc VARCHAR(30)='',
@Body VARCHAR(6000),
@isHTML INT=0,
@Comment VARCHAR(2000)='Dispatch a test email'
AS

DECLARE 
@queuedProcess_ID INT    
INSERT INTO 
Queuedprocess (process[Comment/Error]SELECT 1,@comment
SET @queuedProcess_ID=@@Identity
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'To',@To
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'From',@From
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'CC',@CC
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'BCC',@BCC
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'Body',@Body
INSERT INTO QueuedProcessParameter(QueuedProcess_ID,[Parameter],Value
   
SELECT @queuedProcess_ID'IsHTML',@IsHTML
INSERT INTO [log] ([type]logstring)
   
SELECT 23,'Inserted job into the queue to send an email'
EXECUTE sp_user_counter1 1   

GO
IF @@ERROR<>AND @@TRANCOUNT>ROLLBACK TRANSACTION
GO
GRANT EXECUTE ON [dbo].[spSendAnEmail] TO [TypicalUser]
IF @@TRANCOUNT=0
   
BEGIN INSERT INTO #tmpErrors (Error
               
SELECT 
   
BEGIN TRANSACTION 
   END
GO
IF EXISTS (SELECT FROM #tmpErrorsROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>BEGIN
PRINT 
'The database build succeeded'
COMMIT TRANSACTION
END
ELSE PRINT 
'The database build failed'
GO
DROP TABLE #tmpErrors
GO
/* now we create an agent Job that merely executes the stored procedure
 that execute all the queued jobs */
BEGIN TRANSACTION   
PRINT 
'creating the job'
         
  
DECLARE @JobID BINARY(16)  
  
DECLARE @ReturnCode INT    
  SELECT 
@ReturnCode 0     
IF (SELECT COUNT(*) FROM msdb.dbo.syscategories 
                       
WHERE name N'[Uncategorized (Local)]') < 
  
EXECUTE msdb.dbo.sp_add_category @name N'[Uncategorized (Local)]'
  
-- Delete the job with the same name (if it exists)
  
SELECT @JobID job_id     
  
FROM   msdb.dbo.sysjobs    
  
WHERE (name N'EmptyJobQueue')       
  
IF (@JobID IS NOT NULL)    
  
BEGIN  
  
-- Check if the job is a multi-server job  
  
IF (EXISTS (SELECT  
              
FROM    msdb.dbo.sysjobservers 
              
WHERE   (job_id @JobID) AND (server_id <> 0))) 
  
BEGIN 
    
-- There is, so abort the script 
    
RAISERROR (N'Unable to import job ''EmptyJobQueue'' since there is 
already a multi-server job with this name.'
161
    
GOTO QuitWithRollback  
  
END 
  ELSE 
    
-- Delete the [local] job 
    
EXECUTE msdb.dbo.sp_delete_job @job_name N'EmptyJobQueue' 
    
SELECT @JobID NULL
  
END 


BEGIN 
DECLARE 
@Username VARCHAR(100)
SELECT @username=SUSER_SNAME()
-- Add the job itself to the Agent. This job will be scheduled to
-- run whenever our alert hits its criterion (i.e. when the user 
-- counter 1 is greater than zero
  
EXECUTE @ReturnCode msdb.dbo.sp_add_job 
       
@job_id @JobID OUTPUT 
       
@job_name N'EmptyJobQueue'
       
@owner_login_name @username
       
@description N'Test of a Job that clears a job queue'
       
@category_name N'[Uncategorized (Local)]'
       
@enabled 1
       
@notify_level_email 0
       
@notify_level_page 0
       
@notify_level_netsend 0
       
@notify_level_eventlog 2@delete_level0
  
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback 
PRINT 'creating the job step'
  
-- Add the job steps
  
EXECUTE @ReturnCode msdb.dbo.sp_add_jobstep 
       
@job_id @JobID
       
@step_id 1
       
@step_name N'Execute Queued Actions'
       
@command N'execute spExecuteQueuedActions'
       
@database_name N'BackOfficeDemo'
       
@server ''
       
@database_user_name N'dbo'
       
@subsystem N'TSQL'
       
@cmdexec_success_code 0
       
@flags 0
       
@retry_attempts 0@retry_interval 1@output_file_name '',
       
@on_success_step_id 0@on_success_action 1
       
@on_fail_step_id 0@on_fail_action 2
  
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback 
  
EXECUTE @ReturnCode msdb.dbo.sp_update_job @job_id @JobID
                                                   
@start_step_id 

  
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback 

  
-- Add the Target Servers
  
EXECUTE @ReturnCode msdb.dbo.sp_add_jobserver 
       
@job_id @JobID
       
@server_name N'(local)' 
  
IF (@@ERROR <> OR @ReturnCode <> 0GOTO QuitWithRollback 

END
COMMIT TRANSACTION          
GOTO   
EndSave              
QuitWithRollback:
  
IF (@@TRANCOUNT 0ROLLBACK TRANSACTION 
EndSave: 
PRINT 'creating the alert'

/* Now we will create the alert called 'ThereAreJobsInTheQueue'*/
---- Delete the alert with the same name.
IF (EXISTS (SELECT name FROM msdb.dbo.sysalerts 
                           
WHERE name N'ThereAreJobsInTheQueue'))
  
EXECUTE msdb.dbo.sp_delete_alert @name N'ThereAreJobsInTheQueue' 
BEGIN 
EXECUTE 
msdb.dbo.sp_add_alert 
   
@name N'ThereAreJobsInTheQueue'
   
@message_id 0
   
@severity 0@enabled 1
   
@delay_between_responses 3
   
@performance_condition 
           
N'SQLServer:User Settable|Query|User counter 1|>|0'
   
@include_event_description_in 0
   
@job_name N'EmptyJobQueue'
   
@category_name N'[Uncategorized]'
END

GO
---------------------End of the build script


--we can enable or disable this alert very simply with this procedure
msdb.dbo.sp_update_alert @name N'ThereAreJobsInTheQueue',@enabled =1

/* now we log out, log back in as TypicalUser and run this procedure to 
sent an email (it should just write to the log in this test mode */
EXECUTE spSendAnEmail
   
@To='PhilipFactor@Simpler-talk.com'
   
@From='RobynPage@Simpler-talk.com',
   
@CC='TheEditor@Simpler-talk.com',
   
@Body='This is tremendous! It really works.'

-- if we then look at the log .

GRANT SELECT ON [dbo].[log] TO [TypicalUser]--sudt so 'TyplicalUser' can
--look at it
SELECT type,LogString,InsertionDate,CurrentUser  
   
FROM LOG ORDER BY insertionDate

--we'll see something like this..



/*if all has gone well, the spSendAnEmail procedure will have put a 
request in the queue which will have been picked up and executed by
the agent after a short period. Notice that the execution of the task
is done by DBO (we set it that way) rather than the TypicalUser (who
will have very few privileges) 

You will notice a latency before the Agent picks up the job, up to 
twenty seconds. This is because, in SQL Server 2000, the performance 
condition counters are only polled every twenty seconds.
As a belt-and-braces approach, one might want to have a scheduled task 
the same stored procedure that fires every minute ofr so, as it will do
no harm.*/

/* if it doesn't work 
. Make sure that the SQLServerAgent is running. 
. Check that you are using the latest SQL Server service pack. 
. Check the account the SQLServerAgent services runs under 
. Make sure the event is firing. If not, is it enabled?
. Check the alert properties to see the last time that the alert worked. 
. Check the SQL Server error log, and job history log */

/*
You can have up to ten of these mechanisms working independently, but 
We've never thought of a use for more than one per database.

However, User-defined counters are great for application -based figures
that need to be monitored as part of performance logging (such as 
people logged onto a site simultaneously, or average views per minute,
so don't use them up unnecessarily: they are too valuable.*/



This article has been viewed 5170 times.
Robyn Page and Phil Factor

Author profile: Robyn Page and Phil Factor

Robyn Page is a consultant with Enformatica and USP Networks. She is also a well known actress, being most famous for her role as Katie Williams, barmaid in the Television Series Family Affairs.

Phil Factor (real name withheld to protect the guilty), aka Database Mole, has 20 years of experience with database-intensive applications. Despite having once been shouted at by a furious Bill Gates at an exhibition in the early 1980s, he has remained resolutely anonymous throughout his career.

Search for other articles by Robyn Page and Phil Factor

Rate this article:   Avg rating: from a total of 16 votes.


Poor

OK

Good

Great

Must read
 
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: Nice but ...
Posted by: noeld (view profile)
Posted on: Thursday, June 07, 2007 at 12:44 PM
Message: I have used this process extensively in the past with different variations, user-defined alerts, xp_logevent, DTS, extended stored procs, etc ...

Today SQL 2005 does away with all that work by using "EXECUTE AS".

Cheers!


Subject: ???
Posted by: Adam Machanic (view profile)
Posted on: Monday, June 11, 2007 at 6:46 PM
Message: Noeld,

Can you show us how to use EXECUTE AS to do this? I am only aware of its uses in supporting impersonation...

Subject: Love it
Posted by: ACALVETT (view profile)
Posted on: Tuesday, June 12, 2007 at 9:14 AM
Message: I'd totally forgotten about the user counters and alerts.

Reading your article has helped me to come up with a quick and simple way to address a security issue in a distributed process i deployed recently.

So, i`m off to try it out.

Thanks!

Subject: alternatives
Posted by: Steve Laye (not signed in)
Posted on: Wednesday, June 13, 2007 at 4:08 AM
Message: why do all this work in TSQL when service broker brings it to the table for you. Simply construct a message in your users request and it pops into a queue. Your queue activator runs a stored procedure for you and alerts/success/outcome can be produced back to the user easily too. Its far more scalable and fun learning..

Subject: Alternatives
Posted by: Robyn Page (view profile)
Posted on: Wednesday, June 13, 2007 at 5:22 AM
Message: Steve,
Absolutely right, and we're hoping to do a workbench to show precisely this! I'm sorry we didn't make it clear that this, here, is a solution that is designed so that it would work in SQL Server 2000 as well. As well as being 'far more scalable and fun learning', it is also faster to respond too. However, we were keen to highlight the use of user-settable counters, and user-defined alerts, which we find fascinating...as well a providing cheer for those of us who are stuck with SQL 2000 databases.

Subject: Good For every one
Posted by: Simon Therang Maleleka (not signed in)
Posted on: Wednesday, June 13, 2007 at 6:09 AM
Message: This article has really helped me and Im goig to try it out. I developing a system and its my first time to use SQL server and By reading your article I feel like I know everything and Is really going to secure my system.

Thanks
maleleka@alumnidirector.com

Subject: Job Firing On Alert
Posted by: Kevin Boles (not signed in)
Posted on: Wednesday, June 13, 2007 at 7:56 AM
Message: IIRC, you can't start a job that is already running. Can a job started by an alert cause multiple copies of the job to run? If not, this will leave entries in the queue unprocessed - until the next queue entry comes along.

Subject: good
Posted by: kasi (view profile)
Posted on: Wednesday, June 13, 2007 at 10:23 AM
Message: Itis an excellent article.itis very usefull me.
you will be send another good articles as soon as possible.

thanks to simple talk.

Subject: re: Job firing on alert
Posted by: Phil Factor (view profile)
Posted on: Wednesday, June 13, 2007 at 10:23 AM
Message: As far as we can see from running the test harness, the alert cannot cause more than one copy of the job to run at the same time. The subsequent events are queued up and are all run after the original job terminates (without any delay). They are harmless, and it is precisely the 'safe' behaviour one wants from the system. I haven't ever come across a queue entry getting missed, thouh it would be nice if some malicious test engineer can try to prove me wrong..

Subject: re: Job firing on alert
Posted by: Anonymous (not signed in)
Posted on: Wednesday, June 13, 2007 at 10:37 AM
Message: I wasn't aware of the 'queuing' of alert-fired jobs, but it is logical and I think the correct thing to do in this case. I can think of cases where one would NOT want an alert-fired job to run again if it was currently executing, but it seems that would have to be programmed around.

Subject: ...and I thought I knew something about SQL.
Posted by: mctillett (view profile)
Posted on: Wednesday, June 13, 2007 at 10:44 AM
Message: Like noeld, I have used similar functionality ( I guess there ARE only so many ways to skin a cat ) in a couple of projects, to isolate two processes where real-time response wasn't neccessary ( a queue ) but what I didn't know was that SQL Server provided an implicit looping construct in variable assignment when assigning column values from multiple rows...neat. Nice job Robyn and Phil.

Kevin, the answer is No. You could always replace the invocation via alert with a tight schedule, although that does fill up the job log with useless 'empty' runs.


Subject: ...and I thought I knew something about SQL.
Posted by: mctillett (view profile)
Posted on: Wednesday, June 13, 2007 at 10:59 AM
Message: Like noeld, I have used similar functionality ( I guess there ARE only so many ways to skin a cat ) in a couple of projects, to isolate two processes where real-time response wasn't neccessary ( a queue ) but what I didn't know was that SQL Server provided an implicit looping construct in variable assignment when assigning column values from multiple rows...neat. Nice job Robyn and Phil.

Kevin, the answer is No. You could always replace the invocation via alert with a tight schedule, although that does fill up the job log with useless 'empty' runs.


Subject: re: Job firing on alert
Posted by: Phil Factor (view profile)
Posted on: Wednesday, June 13, 2007 at 2:06 PM
Message: In the test harness, we zeroed the counter on entry to the queue-emptying routine. I suspect that, if we did so at the end of the routine, then you would not get the queued jobs every time a new queue entry got added. We didn't do it as it seemed safer the way we did it.

Subject: GOOD
Posted by: qq1301771 (view profile)
Posted on: Wednesday, June 13, 2007 at 8:05 PM
Message: not understand

Subject: RE: Adam Machanic
Posted by: noeld (view profile)
Posted on: Thursday, June 14, 2007 at 1:16 PM
Message: I am sorry it took me long to get back to this thread, I've been busy lately.

I should have mention the EXECUTE AS does the "impersonation" part which has been most of the time my primary reason for using this technique. But it does not delegate the activity to a separated process. Sorry for all the confusion I may have caused.

-Noel

Subject: WATCH OUT!
Posted by: SAinCA (view profile)
Posted on: Monday, February 18, 2008 at 1:40 PM
Message: If you, for some VERY legitimate reason, need to disable the job that the alert kicks off, be prepared to run out of disk space in a hurry... We learned this the hard way when in under 48 hours the inability of the Alert to fire the job was incessantly logged to the SQLAgent.out file - to the tune of 65 GIGS!

DISABLE THE ALERT, then the job :-) One lives and learns...

Really helpful Workbench, BTW - MANY Thanks.

 









Phil Factor
Bunnikins!
 When an IT manager is selected as a victim of office politics of a large corporate, it is time for him to engage in... Read more...


RECENT BLOG POSTS: