서비스 브로커를 메시징 시스템으로 사용하여 작업을 예약하고 실행합니다. Eash 작업은 엔진이라고하는 여러 작업 또는 단계로 구성됩니다.Service Broker 외부 활성화가 여러 번 실행됩니다.
내 서비스 브로커 개체는 다음과 같습니다
- MessageTypes : SubmitJob, JobResponse, SubmitTask, TaskResponse
- 계약 : JobContract, TaskContract
- 대기열 : ClientQueue, JobQueue, EngineQueue, ExternalActivatorQueue
- 서비스 : ClientService, JobService, EngineService, ExternalActivatorService
- 이벤트 알림 : EventNotificationEngineQueue ,
는 I는 jobqueue에 내부 활성화 (저장 PROC)를 갖는다. SubmitJob MessageTypes의 경우 저장된 proc은 해당 작업의 첫 번째 작업을 가져 와서 EngineService와 대화 상자를 시작하고 해당 대기열 (StartTask)에 메시지를 보냅니다. TaskResponses MessageType의 경우이 작업에 대해 더 많은 작업이 있는지 확인합니다 다음이 작업에 대한 작업이 모두 훌륭한 일 것 같다 (메시지를 보내고 청소.)
완료하지 않을 경우 그들은는 EngineQueue에 제출받을 수 있습니다. 그러나 EngineQueue 메시지를 처리 할 외부 응용 프로그램 (엔진)이 필요합니다. 그래서 저는 Microsoft의 외부 활성화 메커니즘 (ssbeas.exe)을 사용하고 있습니다. 오랜 시간이 걸렸지 만 마침내 작동하게되었습니다. 메시지가 EngineQueue로 이동하면 EventNotificationEngineQueue가 내 애플리케이션을 실행하고 대기열을 배출합니다. 여태까지는 그런대로 잘됐다. 그러나, 내 애플 리케이션을 여러 번 실행하는 것 같다. 내 테스트 응용 프로그램이 완료되면 전자 메일을 보내도록 구성됩니다. 한 작업으로 하나의 작업 만 보내지 만 여러 전자 메일이 표시됩니다 (프로그램이 여러 번 실행되었음을 나타냄).
다음은 내 응용 프로그램 (vb.net)의 코드입니다 (브로커는 서비스 브로커 서비스를 캡슐화하는 개체입니다). (등, 수신, 전송) :.
While True
oBroker.tran = oBroker.cnn.BeginTransaction
oBroker.Receive("EMGQueue", msgType, msg, serviceInstance, dialogHandle)
If dialogHandle = System.Guid.Empty Then
'Console.WriteLine("An Error Occurred. Program Terminated.")
oBroker.tran.Commit()
Exit While
End If
ConsoleWriteLine("Received: " & msgType)
If (msg Is Nothing) Then
ConsoleWriteLine("commiting and exiting")
oBroker.tran.Commit()
Exit While
Else
Select Case (msgType)
Case "SubmitTask"
ProcessMsg(oBroker.cnn, oBroker.tran, msgType, msg, iTaskID, iTaskKey)
oBroker.Send(dialogHandle, "<TaskStatus>1</TaskStatus>'")
Case "http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog"
oBroker.EndDialog(dialogHandle)
Case "http://schemas.microsoft.com/SQL/ServiceBroker/Error"""
oBroker.EndDialog(dialogHandle)
End Select
End If
ConsoleWriteLine("commiting...")
oBroker.tran.Commit()
End While
을 나는 앱이 여러 번 실행하는 이유를 이해 해달라고하지만, 그 이상 내가 후속 버전이 여전히 큐에서 메시지를 볼 수있는 이유를 이해 해달라고 결국, 첫 번째 화신은 큐에 메시지를 잠궈 야합니다. 쿼리 관리자를 사용하여 테스트하여 응용 프로그램이 실행되고 차단 된 동안 메시지를 수신 할 수 있었기 때문에 큐를 잠급니다.
EAService.config의 동시성 값으로 재생 해 보았습니다. min = "0"및 max = "1"로 설정하면 앱이 두 번 실행되는 것처럼 보인 횟수를 줄였습니다 이전에는 min = "0"및 max = "10"을 사용하여 실행 중이었습니다 그것은 18 부 같았다.
길이에 대해 유감스럽게 생각합니다. 누구나 여기서 어떤 일이 일어나고 있는지 아이디어가 있습니까? 내 .net 앱 코딩에 실수를 한 적이 있습니까?
감사
편집 마틴 : 엔진이 실행 된 후 생성 로그 추가 :
2010-02-08 9시 31분 39초을 - 홈페이지
2010-02-08 9시 31분 : 39 - 수신 : SubmitTask
2010-02-08 9시 31분 39초 - ProcessMsg
2010-02-08 9시 31분 39초 - <Task><TaskID> 5</TaskID><TaskKey>2</TaskKey></Task>
2010-02-08 9시 31분 39초 - DoWork
을 2010-02-08 09:31:39 - 메일 보내기
2010-02-08 09:31:40 - 커미팅 ...
2010-02-08 09:31:40 - 잠자기
2010-02-08 09:32:10 - 잠자고 있습니다.
2010-02-08 09:32:10 - Main Complete
2010-02-08 09:32:10 - 외부 활성화 된 응용 프로그램이 지금 성공하고 종료됩니다.
2010-02-08 9시 32분 10초 - 홈페이지
2010-02-08 9시 32분 10초는 - 수신 : SubmitTask
2010-02-08 9시 32분 10초 - ProcessMsg
2010-02- 08 9시 32분 10초 - <Task><TaskID> 5</TaskID><TaskKey> 2</TaskKey></Task>
2010-02-08 9시 32분 10초 - DoWork
2010-02-08 9시 32분 10초 - 이메일
2010-02-08 9시 32분 10초 보내기 - 커밋 ...
2010-02-08 09:32:10 - 잠자기
2010-02-08 09:32:40 - 잠자고 있습니다.
2010-02-08 09:32:40 - Main Complete
2010-02-08 09:32:40 - 외부 활성화 된 응용 프로그램이 이제 성공하고 종료됩니다. 그 가져 여기에 (모든 문 debuggin 등) 저장 프로 시저의 최신 화신은 다음과 같습니다
당신은 그것을 두 번 전체 응용 프로그램을 통과 볼 수 있습니다
편집 2 (. 주, dowork, sendemail, 전체를 받았다) 작업이 대기열에 제출 될 때 활성화 :
ALTER PROCEDURE [dbo].[pr_ProcessJob] AS BEGIN
DECLARE @message_type_name sysname
DECLARE @dialog uniqueidentifier
DECLARE @message_sequence_number bigint
DECLARE @error_message_sequence_number bigint
DECLARE @message_body xml
DECLARE @cgid uniqueidentifier
DECLARE @JobID int
DECLARE @Params varchar(MAX)
DECLARE @ErrorNumber bigint
DECLARE @ErrorText nvarchar(MAX)
DECLARE @TaskID int
DECLARE @TaskService varchar(100)
DECLARE @TaskKey int
DECLARE @chEngine uniqueidentifier
DECLARE @Step int
DECLARE @NextStep int
DECLARE @jobch uniqueidentifier
DECLARE @EngineMsg XML
DECLARE @TimeStarted datetime
DECLARE @TaskStatus int
-- This procedure will just sit in a loop processing Task messages in the queue
-- until the queue is empty
SET NOCOUNT ON
SET @error_message_sequence_number = -100
PRINT 'pr_ProcessJob: Start'
WHILE (1=1) BEGIN
BEGIN TRY
PRINT 'pr_ProcessJob: BEGIN TRANSACTION'
BEGIN TRANSACTION
-- first lets get the conversation group id for the next message.
WAITFOR (
GET CONVERSATION GROUP @cgid FROM [JobQueue]
), TIMEOUT 1000
IF (@@ROWCOUNT = 0) BEGIN
PRINT 'pr_ProcessJob: ROLLBACK TRANSACTION (GET CONVERSATION)'
ROLLBACK TRANSACTION
BREAK
END
PRINT @CGID
-- Inner Loop (Message Processing)
WHILE (1=1) BEGIN
-- Receive the next available message
PRINT 'Receiving Message.'
WAITFOR (
RECEIVE top(1) -- just handle one message at a time
@message_type_name=message_type_name, --the type of message received
@message_body=CAST(message_body AS XML), -- the message contents
@message_sequence_number=message_sequence_number,
@dialog = conversation_handle -- the identifier of the dialog this message was received on
FROM [JobQueue]
WHERE [email protected]
), TIMEOUT 3000 -- if the queue is empty for three seconds, give up and go away
-- If we didn't get anything, the queue is empty so bail out
IF (@@ROWCOUNT = 0) BEGIN
PRINT 'pr_ProcessJob::WaitFor - No messages for conversation group bailing out'
BREAK
END --IF (@@ROWCOUNT = 0)
PRINT 'Message Received: ' + @message_type_name
SAVE TRANSACTION MessageReceivedSavePoint
-- Handle the End Conversation Message
IF (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') BEGIN
-- When we receive an End Dialog, we need to end also.
PRINT 'ENDING CONVERSATION'
END CONVERSATION @dialog
END -- IF (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog') BEGIN
ELSE BEGIN
-- Handle the Conversation Error Message
IF (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/Error') BEGIN
-- We can't return anything here because the dialog at the other end is closed so just log
-- an error and close our end of the conversation.
PRINT 'ENDING CONVERSATION w/Error'
END CONVERSATION @dialog
END -- (@message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
ELSE BEGIN
IF (@message_type_name = 'SubmitJob') BEGIN -- Process normal Job messages..
PRINT 'pr_ProcessJob:: Message Type SubmitJob received.'
-- Pull the information out of the task message with XQuery
SELECT @JobID = @message_body.value('(/Job/JobID)[1]', 'int'),
@Params = @message_body.value('(/Job/Params)[1]', 'varchar(MAX)')
PRINT 'pr_ProcessJob::@JobID = ' + cast(@jobID as varchar(10))
PRINT 'pr_ProcessJob::@Params = ' + @Params
SELECT @ErrorNumber = 0, @ErrorText = N''
-- Do something with the job
-- save state
-- we are looking for the first step
SET @Step=1
PRINT 'Selecting from JobTask'
---------------------------------------------------------
-- Get the next task
---------------------------------------------------------
SELECT TOP 1
@TaskID=task.TaskID,
@TaskService=tt.TaskService,
@TaskKey =Task.TaskKey
FROM JobTask task INNER JOIN TaskType tt
ON task.TaskTypeID = tt.TaskTypeID
WHERE [email protected] AND task.enabled=1 and task.step>[email protected]
ORDER BY Task.step
---------------------------------------------------------
PRINT 'Selecting from JobTask: complete'
PRINT 'Step='+cast(@step as varchar(max))
PRINT 'TaskID='+cast(@TaskID as varchar(max))
PRINT 'TaskService='+cast(@TaskService as varchar(max))
PRINT'TaskKey='+cast(@TaskKey as varchar(max))
PRINT 'BEGIN DIALOG with ' + @TaskService
BEGIN DIALOG @chEngine
FROM SERVICE [JobService]
TO SERVICE @TaskService
ON CONTRACT [TaskContract]
WITH [email protected];
PRINT 'BEGIN DIALOG with ' + @TaskService+' completed.'
SET @EngineMsg = CAST('<Task><TaskID>'+ str(@TaskID)+'</TaskID><TaskKey>'+ str(@Taskkey)+'</TaskKey></Task>' as XML);
PRINT CAST(@EngineMsg as varchar(max))
PRINT 'Sending Message Type SubmitTask to Engine.';
SEND ON CONVERSATION @chEngine
MESSAGE TYPE SubmitTask
(@EngineMsg)
PRINT 'Inserting into jobstate'
INSERT INTO JobState(cgid, jobch, jobID, step) VALUES(@cgid, @dialog, @jobid, @step)
END -- IF (@message_type_name = 'SubmitJob')
ELSE BEGIN
IF (@message_type_name = 'TaskResponse') BEGIN
PRINT 'Processing MessageType TaskResponse'
SELECT @TaskStatus = @message_body.value('(/TaskStatus)[1]', 'int')
PRINT 'pr_ProcessJob::@TaskStatus = ' + cast(@TaskStatus as varchar(10))
PRINT 'Loading State'
--LoadState
SELECT @JobID=jobid,
@Step=Step,
@jobch=jobch,
@TimeStarted=sysdate
FROM Jobstate
WHERE [email protected]
PRINT 'Loading State complete'
PRINT @jobch
PRINT 'Selecting from JobTask'
---------------------------------------------------------
-- Get the next task
---------------------------------------------------------
SELECT TOP 1
@TaskID=task.TaskID,
@TaskService=tt.TaskService,
@TaskKey =task.TaskKey,
@NextStep = task.Step
FROM JobTask task INNER JOIN TaskType tt
ON task.TaskTypeID = tt.TaskTypeID
WHERE [email protected] AND task.enabled=1 and task.step>@step
ORDER BY Task.step
---------------------------------------------------------
PRINT 'Selecting from JobTask: complete'
PRINT 'NextTask: ['[email protected]+']'
if (@TaskService is null) BEGIN
PRINT '@TaskService is NULL: BEGIN'
-- no more tasks
--END CONVERSATION @jobch
PRINT 'Removing from state table'
DELETE FROM JobState
WHERE @cgid=cgid
PRINT @@ROWCOUNT
PRINT 'Removing from state table-completed'
DECLARE @ResponseDoc xml
-- Send a response message saying we're done
DECLARE @Time nvarchar(100)
SET @Time = cast(getdate() as nvarchar(100))
DECLARE @TimeStartedText nvarchar(100)
SET @TimeStartedText = cast(@TimeStarted as nvarchar(100))
SET @ResponseDoc = N'<Job/>'
SET @ResponseDoc.modify(
'insert (<JobID>{ sql:variable("@JobID") }</JobID>,
<JobStatus>{ sql:variable("@ErrorNumber") }</JobStatus>,
<ErrorNumber>{ sql:variable("@ErrorNumber") }</ErrorNumber>,
<ErrorText>{ sql:variable("@ErrorText") }</ErrorText>,
<TimeStarted>{ sql:variable("@TimeStartedText") }</TimeStarted>,
<TimeCompleted>{ sql:variable("@Time") }</TimeCompleted>)
as last into /Job [1]');
SEND ON CONVERSATION @jobch
MESSAGE TYPE [JobResponse] (@ResponseDoc)
END CONVERSATION @jobch
PRINT '@TaskService is NULL: END'
END --if (@TaskService is null) BEGIN
ELSE BEGIN
-- there are more tasks
PRINT '@TaskService is not null: BEGIN'
PRINT 'BEGIN DIALOG with ' + @TaskService
--another task
BEGIN DIALOG @chEngine
FROM SERVICE [JobService]
TO SERVICE @TaskService
ON CONTRACT [TaskContract]
WITH [email protected];
SET @EngineMsg = CAST('<Task><TaskID>'+ str(@TaskID)+'</TaskID><TaskKey>'+ str(@Taskkey)+'</TaskKey></Task>' as XML);
PRINT 'SEND ' +cast(@EngineMsg as varchar(max));
SEND ON CONVERSATION @chEngine
MESSAGE TYPE SubmitTask (@EngineMsg)
PRINT 'SAVING State: ' +str(@step)
-- save state
Update JobState
SET step = @NextStep
FROM JobState
WHERE [email protected]
PRINT '@TaskService is not null: END'
END -- ELSE (@TaskService is NOT NULL)
PRINT 'Processing MessageType TaskResponse...Complete'
END -- IF (@message_type_name = 'TaskCompleted')
END -- ELSE IF (@message_type_name <> 'JobRequest')
END -- ELSE (@message_type_name <> 'http://schemas.microsoft.com/SQL/ServiceBroker/Error')
END -- ELSE (@message_type_name <> 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
END -- WHILE (1=1) BEGIN
PRINT 'COMMIT TRANSACTION'
COMMIT TRANSACTION
END TRY
BEGIN CATCH
--rollback transaction
DECLARE @ErrNum int
DECLARE @ErrMsg varchar(max)
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_SEVERITY() AS ErrorSeverity
,ERROR_STATE() AS ErrorState
,ERROR_PROCEDURE() AS ErrorProcedure
,ERROR_LINE() AS ErrorLine
,ERROR_MESSAGE() AS ErrorMessage;
PRINT 'pr_ProcessJob: ROLLBACK (CATCH)'
if (error_number()=1205) BEGIN
-- a deadlock occurred. We can try it again.
PRINT 'pr_ProcessJob: ROLLBACK TRANSACTION (CATCH)'
ROLLBACK TRANSACTION
--CONTINUE
END --if (error_number()=1205)
ELSE BEGIN
if (error_number()=9617) BEGIN
PRINT 'pr_ProcessJob: ROLLBACK TRANSACTION (CATCH)'
ROLLBACK TRANSACTION
END
ELSE BEGIN -- (error_number()<>9617)
-- another error occurred. The message cant be procesed sucessfully
PRINT 'pr_ProcessJob: ROLLBACK TRANSACTION to MessageReceivedSavePoint (CATCH)'
ROLLBACK TRANSACTION MessageReceivedSavePoint
END --ELSE (error_number()<>9617)
END -- if (error_number()<>1205)
END CATCH
END -- while loop
PRINT 'pr_ProcessJob: Complete'
END -- CREATE PROCEDURE [dbo].[ProcessJobProc]
그리고 이러한 작업 메시지를 보내는 논리는 무엇입니까? –
안녕하세요 당신은이 문제를 해결 했습니까? 비슷한 문제가 생겼습니다. 대기열에 제출합니다. 내부 활성 자 프로세스는 작업 대기열에서 들어오는 모든 외부 활성기로 통지를 사용하여 작업 대기열로 보냅니다.하지만 모든 것이 여러 번 실행됩니까? –