Service Broker: Asynchrone Ausführung von Stored Procedures
Mai
9
Written by:
09.05.2009 07:21
Service Broker: Asynchrone Ausführung von Stored Procedures
Normalerweise läuft in einer DBMS alles immer synchron in einer Transaktion ab; so ist es gedacht.
In Ausnahmefällen kommt es aber auch mal vor, dass man eine SP anstarten will, die sehr lange läuft und man nicht unbedingt warten will, bis sie fertig ist.
Zeitgesteuert gibt es mehrere Möglichkeiten wie ein SQL Server Agent Job, der regelmäßig nachsieht, ob es etwas zu tun gibt oder mit dem Windows Taskplaner + SqlCmd.
Möchte man es aber asynchron direkt anstarten, stellt der Service Broker ein gut Möglichkeit dar.
Man legt eine Queue an, die bei Eintreffen einer Nachricht eine Stored Procedure startet, die dann die ToDo’s abarbeitet. Mit Beendigung könnte die SP dann eine Nachricht über Beendigung & Ergebnis in weitere Queue senden, um den Aufrufer zu benachrichtigen.
Hier mal ein kleines Bespiel, dazu wird die Demo-Datenbank „AdventureWorks“ verwendet, natürlich ginge es auch mit anderen DBs.
Zunächst erst mal die Vorbereitung, Service Broker aktivieren
USE master;
GO
-- Service Broker aktivieren
ALTER DATABASE AdventureWorks SET ENABLE_BROKER;
GO
USE AdventureWorks
GO
IF NOT OBJECT_ID('AsyncWorkerHist', N'U') IS NULL
DROP TABLE AsyncWorkerHist
GO
-- Tabelle mit der Hist der erledigten Aufträge
CREATE TABLE AsyncWorkerHist
(LogDate datetime,
LogAction varchar(50),
LogMessage varchar(50),
LogBody varchar(50));
GO
-- Nachrichtentyp mit Uri-Adresse anlegen
-- WELL_FORMED_XML, auch wenn vorerst der Inhalt der
-- Nachrichten egal ist
CREATE MESSAGE TYPE [//AWDB/AsyncWork/Message]
VALIDATION = WELL_FORMED_XML;
GO
-- Vertrag festlegen
CREATE CONTRACT [//AWDB/AsyncWork/myContract]
([//AWDB/AsyncWork/Message]
SENT BY ANY);
GO
-- Queue für Initiator anlegen
-- wird benötigt, aber nicht verwendet
CREATE QUEUE InitAsyncWorkerQueue;
GO
CREATE SERVICE [//AWDB/AsyncWork/InitService]
ON QUEUE InitAsyncWorkerQueue
([//AWDB/AsyncWork/myContract]);
GO
Nun kommt das wichtigste, nämlich die Stored Procedure, die aktiviert und die Nachrichten abarbeiten soll; da sie für die Queue-Definition bereits vorhanden sein muss, kommt sie hier an der Stelle. Sie holt mittels des Befehls „RECEIVE“ eine Nachricht aus der Queue ab. Handelt es sich um eine bekannte Nachricht, wird die entsprechende Aktion ausgeführt.
Natürlich ist das hier nur ein Mini-Beispiel, man sollte alles in eine Transaction einbetten, Error-Handling fehlt, etc.
IF NOT OBJECT_ID('spQueueWorkerTest', N'P') IS NULL
DROP PROCEDURE spQueueWorkerTest
GO
-- SP fürs abarbeiten der Warteschlange erstellen
CREATE PROCEDURE spQueueWorkerTest
AS
BEGIN
DECLARE @RecvReqDlgHandle UNIQUEIDENTIFIER;
DECLARE @RecvReqMsg NVARCHAR(100);
DECLARE @RecvReqMsgName sysname;
-- Erste Nachricht abholen und je Lauf
-- auch nur eine abarbeiten (alternative WHILE Schleife)
RECEIVE TOP(1)
@RecvReqDlgHandle = conversation_handle,
@RecvReqMsg = message_body,
@RecvReqMsgName = message_type_name
FROM AsyncWorkerQueue
--Nachricht auch für mich gedacht?
IF @RecvReqMsgName = N'//AWDB/AsyncWork/Message'
BEGIN
-- Aktivität protokollieren
INSERT INTO AsyncWorkerHist
(LogDate, LogAction, LogMessage, LogBody)
VALUES (GetDate(), 'Started', @RecvReqMsgName, @RecvReqMsg);
-- 2 min so tun, als sein man mächtig beschäftigt
WAITFOR DELAY '00:02';
-- Aktivität protokollieren
INSERT INTO AsyncWorkerHist
(LogDate, LogAction, LogMessage, LogBody)
VALUES (GetDate(), 'Finished', @RecvReqMsgName, @RecvReqMsg);
-- Jetzt könnte man eine Nachricht zurück senden
END
END;
GO
Zum Schluss der Definition noch die Queue und der Service:
-- Queue anlegen
CREATE QUEUE AsyncWorkerQueue
WITH STATUS = ON,
RETENTION = OFF,
ACTIVATION(STATUS = ON,
PROCEDURE_NAME = spQueueWorkerTest,
MAX_QUEUE_READERS = 1,
EXECUTE AS Owner);
GO
-- und den Dienst dazu
CREATE SERVICE [//AWDB/AsyncWork/TargetService]
ON QUEUE AsyncWorkerQueue
([//AWDB/AsyncWork/myContract]);
GO
Nun muss man nur noch eine Nachricht in die Queue stellen und abwarten, was passiert:
DECLARE @InitDlgHandle UNIQUEIDENTIFIER;
DECLARE @RequestMsg NVARCHAR(100);
-- Nachrichtentext
SELECT @RequestMsg =
N'<RequestMsg>StartAsyncJob</RequestMsg>';
-- Dialog beginnen
BEGIN DIALOG @InitDlgHandle
FROM SERVICE [//AWDB/AsyncWork/InitService]
TO SERVICE N'//AWDB/AsyncWork/TargetService'
ON CONTRACT [//AWDB/AsyncWork/myContract]
WITH ENCRYPTION = OFF;
-- Senden
SEND ON CONVERSATION @InitDlgHandle
MESSAGE TYPE [//AWDB/AsyncWork/Message]
(@RequestMsg);
-- Und beenden
END CONVERSATION @InitDlgHandle
GO
-- Gestartet/Fertig?
SELECT *
FROM AsyncWorkerHist
ORDER BY LogDate
6 comment(s) so far...
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
Verwenden Sie Ihre Tipps für die Arbeit an Ihrem Projekt zu verbessern online pokern.
By Aster on
25.03.2010 18:36
|
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
Hi this code is most useful for me meilleur casino
By stewbiff on
29.06.2010 15:09
|
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
hi, den code kann ich sehr gut für meine diplomarbeit gebraucht, danke poker
By tobias on
30.09.2010 13:29
|
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
die kommentare im code sind sehr hilfreich und gut geschrieben, ich glaube ohne sie würde ich den code nicht so einfach kapieren, danke! kostenlose spiele
By matthias on
03.10.2010 22:42
|
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
Best code for me after à lonh search on internet Poker en ligne en français
By Blackblox on
14.02.2011 16:49
|
Re: Service Broker: Asynchrone Ausführung von Stored Procedures
hi, den code kann ich sehr gut für meine diplomarbeit gebraucht, danke Winamax
By Blackblox on
14.02.2011 16:50
|