Hi:
My service broker is working with 2 different instances in local server.But could not able to get working on 2 different servers because of Conversation ID cannot be associated with an active conversation error which I have posted.
After I receive the message successfully...in the end I get this message sent...
<Error xmlns="http://schemas.microsoft.com/SQL/ServiceBroker/Error">
<Code>-8462</Code>
<Description>The remote conversation endpoint is either in a state where no more messages can be exchanged, or it has been dropped.</Description>
</Error>
Why am i gettting this error after the conversation.
Thanks,
Pramod
Pramod
You have not shared enough information for us to be able to help you. There are legitimate reasons why you might receive this error. If in fact, the remote conversation endpoint has been dropped and the local service sends another message on this same conversation, you should get this. Another less obvious way to get a message of this nature would be if the remote database was restored to an earlier time prior to the existence of the conversation being used.
For us to help you debug why you are getting this message, you will need to share more about your specific usage. It would also be interesting to know if the two services that are communicating on the conversation are taking turns in a half-duplex fashion (one side, then the other, but never simultaneously) or if both are sending to each other potentially at the same time (full-duplex).
|||Gerald:
I have 3 stored procedures. Initiator will have 2 procedures one to send message and receive acknowledgement.
Target will have 1 stored procedure to receive and send acknowledgement.
Initiator Sproc:
-
SP 1:
ALTER PROCEDURE [dbo].[usp_SendMessage]
@.userID int AS
BEGIN
DECLARE @.dialog_handle uniqueidentifier,
@.msg XML
BEGIN DIALOG CONVERSATION @.dialog_handle FROM SERVICE CLIENTSERVICE
TO SERVICE 'SERVERSERVICE' ON CONTRACT MainContract WITH ENCRYPTION = OFF ;
SET @.msg =(select queue.userid,queue.Friendlyname,queue.TemplateName,filters.columnkey,filters.datatype,
criteria.leftarg,criteria.logop,criteria.rightarg, fields.field, fields.datatype, fields.grouporder, fields.summed, fields.averaged, fields.counted from queue LEFT OUTER JOIN filters on queue.id=filters.reportid LEFT OUTER JOIN criteria on filters.id = criteria.filterid LEFT OUTER JOIN fields on queue.id =fields.reportid where queue.id=@.userID FOR XML AUTO);
-- Now Sending a message note we are using
-- SendMessageType since it is defined in the contract
-- that it is to be sent only by initiater
SEND ON CONVERSATION @.dialog_handle MESSAGE TYPE SendMessageType (@.msg);
END
SP 2:
-
ALTER PROCEDURE [dbo].[usp_OnReceiveMessage] AS
declare @.message_type int
declare @.dialog uniqueidentifier,
@.ErrorSave INT,
@.ErrorDesc NVARCHAR(100),
@.message_body XML;
while (1 = 1)
begin
begin transaction -- Receive the next available message from the queue
WAITFOR (
RECEIVE top(1) -- just handle one message at a time
@.message_type=message_type_id, --the type of message received @.message_body=message_body, -- the message contents
@.dialog = conversation_handle -- the identifier of the dialog this message was received on
FROM CLIENTQUEUE ), TIMEOUT 30000 -- if the queue is empty for three second, give UPDATE and go away If we didn't get anything, bail out
if (@.@.ROWCOUNT = 0)
BEGIN
Rollback Transaction
BREAK
END
-- Check for errors in Receive
SET @.ErrorSave = @.@.ERROR ;
IF (@.ErrorSave <> 0)
BEGIN
ROLLBACK TRANSACTION ;
SET @.ErrorDesc = N'An error has occurred.' ;
END CONVERSATION @.dialog
WITH ERROR = @.ErrorSave DESCRIPTION = @.ErrorDesc ;
INSERT INTO messages_log VALUES(@.ErrorDesc,NULL) END
ELSE -- Check for the End Dialog message.
If (@.message_type <> 2) -- End dialog message
BEGIN-- Log Message in Database
INSERT INTO messages_log VALUES('Successfully Received:TEST',@.message_body);
-- Send the message back to the sender.
SET @.message_body = '<msg>Aknowledge message sent </msg>';
SEND ON CONVERSATION @.dialog -- send it back on the dialog we received the message on MESSAGE TYPE SendMessageType (@.message_body);
-- Must always supply a message type the message contents are XML
END CONVERSATION @.dialog WITH CLEANUP
END
ELSE
BEGIN-- End Conversation and Notify other side of the conversation
END CONVERSATION @.dialog WITH CLEANUP
END -- Commit the transaction. At any point before this, we could roll -- back - the received message would be back on the queue and the response -- wouldn't be sent.
commit transaction
end
-
TARGET SPROC:
-
ALTER PROCEDURE [dbo].[usp_OnReceiveMessage]
AS
declare @.message_type int
declare @.dialog uniqueidentifier,
@.ErrorSave INT,
@.ErrorDesc NVARCHAR(100),
@.message_body XML;
while (1 = 1)
begin
begin transaction
-- Receive the next available message from the queue
WAITFOR (
RECEIVE top(1) -- just handle one message at a time
@.message_type=message_type_id, --the type of message received
@.message_body=message_body, -- the message contents
@.dialog = conversation_handle -- the identifier of the dialog this message was received on
FROM SERVERQUEUE
), TIMEOUT 3000 -- if the queue is empty for three second, give UPDATE and go away
-- If we didn't get anything, bail out
if (@.@.ROWCOUNT = 0)
BEGIN
Rollback Transaction
BREAK
END
-- Check for errors in Receive
SET @.ErrorSave = @.@.ERROR ;
IF (@.ErrorSave <> 0)
BEGIN
ROLLBACK TRANSACTION ;
SET @.ErrorDesc = N'An error has occurred in client.' ;
END CONVERSATION @.dialog
WITH ERROR = @.ErrorSave DESCRIPTION = @.ErrorDesc ;
INSERT INTO messages_log VALUES(@.ErrorDesc,NULL)
END
ELSE
-- Check for the End Dialog message.
If (@.message_type <> 2) -- End dialog message
BEGIN
-- Log Message in Database
INSERT INTO messages_log VALUES('Successfully Received',@.message_body);
-- Send the message back to the sender.
SET @.message_body = '<msg>Sending the acknowledgement to client</msg>';
SEND ON CONVERSATION @.dialog -- send it back on the dialog we received the message on
MESSAGE TYPE ReceiveMessageType -- Must always supply a message type
(@.message_body); -- the message contents are XML
--END CONVERSATION @.dialog
END
ELSE
BEGIN
-- End Conversation and Notify other side of the conversation
END CONVERSATION @.dialog
END
-- Commit the transaction. At any point before this, we could roll
-- back - the received message would be back on the queue and the response
-- wouldn't be sent.
commit transaction
end
--
When I ran these with 2 different dbs in same instances...i get the acknowledge correctly. But when i using b/w 2 instances of db...I dont get the acknowledgement but the error code is there in target queue.
You are using ENd DIALOG ... WITH CLEANUP. You should nevere do so. This explains all the problems you described so far in your posts. See this blog post too: http://blogs.msdn.com/remusrusanu/archive/2006/01/27/518455.aspx
HTH,
~ Remus
I suspect that the "it works within an instance, but not across instances" is a classic race condition. In other words, by introducing more latency (ie. the network calls), the app runs with slightly different timing thereby allowing an existing bug to manifest itself. It probably isn't occurring when they are in the same instance because of optimizations our code base can take advantage of given its one instance. That doesn't mean it cannot happen there, just that it hasn't yet.
Having said that, I haven't had time to look at your code in depth, but one thing that is obviously wrong is your usage of END CONVERSATION WITH CLEANUP. END CONVERSATION WITH CLEANUP should not be used in application code as a rule. END CONVERSATION and END CONVERSATION WITH ERROR should be used in application code.
END CONVERSATION WITH CLEANUP is an administrative last resort to excise CONVERSATIONS and their undelivered messages from a database when there is no hope of delivery occurring. For example, the database containing the targetted remote service was dropped without properly ending conversations first.
So, for sure change that. I'll look at it more in-depth as well.
|||Gerald , Remus:
Thank you...it worked
Pramod
No comments:
Post a Comment