Incoming messages only processed when sending messages
See original GitHub issueI am new to AMQP and amqpnetlite, but have been struggling with some fairly basic functionality. I am trying to implement a basic pub/sub API using AMQP, and I keep having problems with message only being received as part of sending a message, either immediately or after a short delay.
I have boiled it down to a very small example, with a dummy “chat” app, that I have made available here: https://github.com/petertiedemann/amqpnetlite-repro
The repo includes detailed repro steps, and ready-to-run code, but overall workflow is this:
var factory = new ConnectionFactory();
if ( options.Trace ) {
Trace.TraceLevel = TraceLevel.Frame;
Trace.TraceListener = ( _, format, objects ) => Console.WriteLine( Format( format, objects ) );
}
var connection = await factory.CreateAsync( new Address( options.Uri ) );
var session = new Session( connection );
var receiver = new ReceiverLink(
session,
"receiver",
options.Key );
var sender = new SenderLink( session, "sender", options.Key );
void OnMessage( IReceiverLink link, Message message ) {
Console.WriteLine( $"{DateTime.Now.ToLongTimeString()} > INCOMING:{message.GetBody<string>()}" );
link.Accept( message );
}
receiver.Start( 100, OnMessage );
while ( true ) {
Console.WriteLine( "Enter a message, 'exit' to quit" );
var message = Console.ReadLine();
if ( IsNullOrWhiteSpace( message ) ) {
Console.Error.WriteLine( "Try again!" );
continue;
}
if ( message == "exit" ) {
break;
}
await sender.SendAsync( new Message( message ), TimeSpan.FromSeconds( 5 ) );
Console.WriteLine( $"{DateTime.Now.ToLongTimeString()} > SENT: {message}" );
The behavior I see depends a bit on the broker, but the general pattern is that at some point the client stops receiving incoming messages, but that as soon as the client sends a message, the callback is processed.
My guess is that there is something simple that I missed (and perhaps isn’t documented?) Perhaps related to link credit?
Issue Analytics
- State:
- Created 2 years ago
- Comments:12 (12 by maintainers)
The pump is just while(true) loop statement that’s reading bytes from the socket. If it receives enough data to parse a complete frame it deserializes it and invokes the client-specific code like your
OnMessage
callback. If you block inside this callback the pump cannot read any new bytes. So your app gets stuck.The same applies when you are sending a message. When the other side receives it, it sends back ack frame that completes this operation from your POV (again there’s callback that completes
TaskCompletionSource
). If you run some blocking code as a continuation, you end up with the same problem as above because you’re again blocking the pump.In my producer example I manually control completion via my own
TaskCompletionSource
. So I can instruct it to run the continuation on the thread pool and make sure that I don’t block the pump.I hope that answers your question.
@xinchen10 I will close this issue and am just writing up a small PR for the docs.