Wait for Recieve Fails to recieve message when called from .Net sqlClient

I have been building out an application and Service Broker has been working great but I have this one nagging problem.

There are some scenarios that involve users waiting for a response so I call a stored procedure that sends a message on a service and then waits for a responses on the conversation handle on which it sent the request.

When I call the stored procedure from a query window inside management studio it works perfectly.

When I call it from a .NET application it times out waiting for the response.  If I set a long timeout I can see that the response  was returned and is sitting in the queue but the waitfor receive just sits there until it times out. 

as soon as it times out if I execute a receive it succeeds and receives the message.

This seems to be a bug in the conversation locking mechanism which only happens if called from .NET.  If my understanding is accurate the conversation lock should block others but not the session that created the conversation.< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

What is really baffling is why it works in some scenarios and not in others.

Jim




Answer this question

Wait for Recieve Fails to recieve message when called from .Net sqlClient

  • opop

    Not at all the same problem but I think I know what your issue is.

    Waitfor command will wait forever however when you create a command in .NET you spearately set the command timeout.

  • Rob Reiss

    Hi, even if I Specify a timeout I get the same error:

    "Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding."

    WAITFOR (RECEIVE CONVERT(NVARCHAR(max), message_body) AS message

    FROM ReceiverQueue), TIMEOUT -1 (or a very big value)


  • usna91

    I was able to reproduce the behavior and find it mysterious. I am currently investigating the issue.

    Thanks,
    Rushi

  • jonbruce_ddt

    I cannot see anything obviously broken in your scripts. (The one thing I did notice was that you are not setting the CommandTimeout property of the SqlCommand object and hence ADO.NET may timeout the command before the server returns a result set). There could be something else in the environment that is holding a lock. Inspect 'select * from sys.dm_tran_locks' while your ADO.NET program is blocked to investigate the issue.



    I tried to setup a repro of your scenario using simpler scripts. These work on my machine. Could you test it on your system



    use tempdb

    go



    create procedure requestreply

    as

    declare @dh uniqueidentifier;

    begin transaction;

    begin dialog @dh

    from service s1

    to service 's2';

    send on conversation @dh (N'Request');

    commit;

    begin transaction

    waitfor (

    receive conversation_handle, message_type_name,

    convert(nvarchar(max), message_body)

    from q1 where conversation_handle = @dh), timeout 10000;

    if (@@rowcount = 0)

    begin

    rollback;

    return;

    end

    end conversation @dh

    commit;

    go



    create procedure replyrequest

    as

    declare @dh uniqueidentifier;

    declare @mt sysname;

    while (1=1)

    begin

    begin transaction;

    waitfor (

    receive top(1) @dh=conversation_handle, @mt=message_type_name

    from q2), timeout 10000;

    if (@@rowcount = 0)

    begin

    commit;

    break;

    end

    if (@mt = 'DEFAULT')

    send on conversation @dh (N'Reply');

    else

    end conversation @dh;

    commit

    end

    go



    create queue q1;

    create queue q2 with activation (

    status = on, procedure_name = replyrequest, max_queue_readers=1, execute as self);

    go

    create service s1 on queue q1;

    create service s2 on queue q2 ([DEFAULT]);

    go



    And the ADO.NET program used was:



    using System;

    using System.Data.SqlClient;



    class Program

    {

    static void Main(string[] args)

    {

    SqlConnection conn = new SqlConnection("Server=xxx; Database=tempdb; Integrated Security=SSPI;");

    conn.Open();

    SqlCommand cmd = conn.CreateCommand();

    cmd.CommandText = "requestreply";

    cmd.CommandType = System.Data.CommandType.StoredProcedure;

    cmd.CommandTimeout = 0;

    using (SqlDataReader reader = cmd.ExecuteReader())

    {

    while (reader.Read())

    {

    Console.WriteLine("{0}: {1}, {2}", reader.GetGuid(0), reader.GetString(1), reader.GetString(2));

    }

    }

    Console.WriteLine("Press any key to continue...");

    Console.ReadLine();

    }

    }

  • Sushil Sharma

    Strange thing is that this problem seems to be somewhat transient but right now for this example it is very repeatable in my environment.  I have attached the stored procedure and test harnes that reproduces the problem.  It is just a simple call using ExecuteReader.

    We had this issue on another very similar service scenario once before and changing from ExecuteNonQuery to ExecuteReader even though in that case we did not need a result set fixed the problem now the problem has popped up again.

    Also we are now on the Sept. CTP and the other time I saw this we were on Beta 2.


    [/code]



  • allez

    Exactly! 

  • jwf

    We have tested request/reply scenarios using ADO.NET like the one you described. Do you execute the stored proc from ADO.NET in a transaction Can you provide more information such as the stored proc as well as the ADO.NET code that calls the stored proc



    Thanks,

    Rushi

  • jmargey

    Hi

    I have the same problem:

    If I run a WAIT FOR on SQL Management Studio it waits indefinetly
    IF I run the same via SQL Client I get timeout error.

    How can I fix it How to give "RECEIVE" right to the user (but I'm connecting as dbo....)

    SQL:

    WAITFOR (RECEIVE CONVERT(NVARCHAR(max), message_body) AS message

    FROM ReceiverQueue)

    Thanks for helping


  • Mystagogue

    My reply appears before yours (even though it was sent later) so I just wanted to put a note here so that you would see it and you can scroll up to read it.

    Rushi

  • emilylin56

    I actually figured this out last night!  I still think it is possibly a bug but it has nothing to do with .NET client.

    We run our .NET apps on connections with least privilege and rely on Ownership chaining for access to the base objects.  So the user only has execute permissions on the stored procedure and the owner of both the stored procedures and objects in the database is dbo so the procedures all get access to underlying objects through ownership chaining.

    The funny thing is that ownership chaining seems to work for sending on a service but not for receiving from a queue.  Worse then that is that it does not throw an error.

    So if you take your stored procedure and run it with a user that has execute permissions on the procedure but does not have receive permissions on the queue it will send, enter the waitfor and sit there till it times out.

    giving the user receive permission on the queue makes it work fine.

    Is this by design  
    Why does ownership chaining work for send but not receive
    Maybe there is still a small gap in my understanding

    Thanks for your attention to this issue, sorry to lead you down the wrong path initially but I think we are near a full understanding of the issue now. 

    Jim



  • threna

    Damn! That was the commantimeout on the SqlCommand object.

    Big Smile

  • spyork

    Great.  I look forward to your findings.

    For now we have a simple workaround which is to just explicitly grant recieve rights on the queue.

    Jim

  • Andreas Johansson

    We have filed a bug for the issue but it will probably not be fixed for RTM. The workaround is to grant RECEIVE to the user or to make your stored proc execute as owner.



    Thank you,

    Rushi

  • AJ Software

    In terms of transactions, When called from .NET we do not create any transaction.  If you begin a transaction and call the stored procedure then the service never recieves the request because until you commit the outer transaction it is not available to be recieved.

    In this failure scenario the message is recieved by the service and a response is sent.  Selecting from the respons queue shows the response message in the queue but trying to recieve the message while the procedure is waiting does not receive the message.  Once the procedure times out then I can recieve the message from the queue.

    Jim



  • Wait for Recieve Fails to recieve message when called from .Net sqlClient