Microsoft service bus - Receive messages from Bus with OnMessage() method - c#

My application has to receive a message every time new message is posted. So I'm using OnMessage() method as mentioned in Microsoft documentation.
When new messages are posted the OnMessage() method does not seem to be working. To resolve this, I've placed the code into a separate task with infinite loop. This seems totally wrong.
public void ReceiveMessageFromSubscription(string topicName, string subscriptioName)
{
Task.Factory.StartNew(() =>
{
while (true)
{
SubscriptionClient Client = SubscriptionClient.CreateFromConnectionString(connectionString, topicName, subscriptionName);
Client.OnMessage((message) =>
{
try
{
var message = brokerMessage.GetBody<MessageDto>();
newMessage.AnnounceNewMessage(message);
message.Complete();
}
catch (Exception ex)
{
message.Abandon();
}
});
}
});
}
Whenever there is a message in Subscription the OnMessage() method has to be called. Can anyone please help me with this.

OnMessage API is an asynchronous process that receives messages in an event-driven message pump. It doesn't stop receiving until you either dispose the client or the code that is running it is terminated. The code above is wrong. You should not instantiate a subscription client in a tight loop and register your callback each time. What you should be doing is creating your client, registering a callback with a desired concurrency, and hold on to that client until you no longer need to receive messages.
Remember, it's a message pump that has to run all the time. Official documentation is a bit dry, perhaps this post will help.
In addition to that, I would strongly recommend not to use the legacy client WindowsAzure.ServiceBus which you're using. Instead, prefer the new Microsoft.Azure.ServiceBus client.

Related

When using Channels with SignalR server-to-client streaming, is the server-side Complete guaranteed to be delivered to the client?

I'm doing SignalR server-to-client streaming using System.Threading.Channel with a .NET client. The usage is fairly basic, similar to what is described in the introductory docs.
The hub code is similar to this:
public ChannelReader<byte[]> Retrieve(Guid id, CancellationToken cancellationToken)
{
var channel = Channel.CreateBounded<byte[]>(_limit);
_ = WriteItemsAsync(channel.Writer, id, cancellationToken);
return channel.Reader;
}
private async Task WriteItemsAsync(ChannelWriter<byte[]> writer, Guid id, CancellationToken cancellationToken)
{
Exception localException = null;
try
{
//loop and write to the ChannelWriter until finished
}
catch (Exception ex)
{
localException = ex;
}
finally
{
writer.Complete(localException);
}
}
And client similar to this:
var channel = await hubConnection.StreamAsChannelAsync<byte[]>("Retrieve", _guid, cancellationTokenSource.Token);
while (await channel.WaitToReadAsync())
{
while (channel.TryRead(out var data))
{
//handle data
}
}
When my hub method is done streaming, it calls Complete() on its ChannelWriter. SignalR, presumably, internally sees the Complete call on the corresponding ChannelReader, translates that into an internal SignalR message and delivers that to the client. The client's own ChannelReader is then marked as complete by SignalR and my client code wraps up its own work on the stream.
Is that "completed" notification, from server to client, guaranteed to be delivered? In other cases where the hub is broadcasting non-streaming messages to clients, it generally "fires and forgets", but I've got to assume that calling Complete on the streaming Channel has acknowledged delivery, otherwise the client could be in a state where it is holding a streaming ChannelReader open indefinitely while the server sees the stream as closed.
Less important to the question, but the reason I ask is that I am trying to narrow down just such a scenario where a data flow pipeline that consumes a SignalR streaming interface very occasionally hangs, and it seems that the only point where it is hanging is somewhere in the SignalR client.
I asked the devs over on github: https://github.com/dotnet/aspnetcore/issues/30128.
Here is a quick summary:
"Messages over SignalR are as reliable as TCP. Basically what this means is that either you get the message, or the connection closes. In both cases the channel on the client side will be completed."
And:
"Right it should never hang forever. It'll either send the complete message or disconnect. Either way, a hang would be a bug in the client"

how i should wait for a message reply from another actor in akka.net?

Im new to akka.net and i have learned that in order to use the async and await pattern you would have to use the Ask() Method but as far as im understanding it , you can only await a task only if you fire a method within that actor or some object method, but is it possible to await a task that sends a message to another actor ?
let me illustrate by a simple example :
lets say ActorA received an Message and he needs some informations from ActorB, ActorA code would like this :
class ActorA :ReceiveActor
{
public ActorA ()
{
Receive<string>(Message => ActorB.Ask<string>());
}
}
lets say i want to stall waiting for a reply from actor B. i dont want to process any other messages. ActorB listens for the request, process the message and then finnally replies.
the thing is when ActorB replies it must reply of the form ActorA.tell(replymessage), and this way ActorA might never get to process the reply because the replyMessage should go to ActorA mailbox.
Am i missing something !
If you need request-response messaging in Akka.NET, you can use the Ask keyword and ReceiveAsync:
class ActorA :ReceiveActor
{
public ActorA ()
{
ReceiveAsync<string>(async message => {
var resp = await ActorB.Ask<string>("some input");
// do some work
});
}
}
This will have your actor asynchronously wait until it receives a response before it moves on - but it's worth noting that this will block your actor from processing any other messages prior to the await call completing.
If you wanted to use one-way messaging to allow for interleaving of messages, you could also write it this way:
class ActorA :ReceiveActor
{
public ActorA ()
{
Receive<MessageType>(message => {
// some work
ActorB.Tell("some command");
});
Receive<string>(message => {
// receive response from ActorB
});
}
}
The difference is, there's no timeout or verification that the sender processed the message and sent a reply in the second model. But, it also requires fewer allocations and it allows ActorA to keep processing other messages in the background while the work is being done.
You can use either approach - I'd recommend the first if you absolutely need to guarantee that the message gets processed.

Microsoft.Azure.ServiceBus: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue

I've got a service bus topic triggered function which gets triggered whenever some data is pushed to the topic.
The function looks something like this:
[FunctionName("funcGetServiceBusEntities")]
public async Task Run([ServiceBusTrigger("sbtopic", "sbsub", Connection = "ServiceBusConnectionString")]Message message, MessageReceiver messageReceiver, [DurableClient] IDurableOrchestrationClient starter, ILogger log)
{
// perform processing on the data
//...
//...
// Complete since we don't want to process the message again
await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
//...
}
I' m not sure why I'm getting this error:
Microsoft.Azure.ServiceBus: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue. Reference:ab88d42f-5fed-4392-983a-921cc6eab776, TrackingId:7664c851-9f29-4b4f-a334-4038e0921810_B11, SystemTracker:sb-dev:Topic:sbtopic|sbsub, Timestamp:2020-03-31T12:09:32.
Is the implementation of CompleteAsync wrong?
This is what you faced now:
Please notice that after triggered the message will be removed. So you don't need to tag it and don't worry about process the message again. It has already been removed.

RestRequestAsyncHandle.Abort() won't trigger CancellationToken.IsCancellationRequested

I have two C# app running simultaneously. One is a C# console app that sends REST calls to the other and the other is running a Nancy self hosted rest server.
Here's a really basic view of some of the code of both parts.
RestsharpClient:
public async void PostAsyncWhile()
{
IRestClient RestsharpClient = new RestClient("http://localhost:50001");
var request = new RestRequest($"/nancyserver/whileasync", Method.POST);
var asyncHandle = RestsharpClient.ExecuteAsync(request, response =>
{
Console.WriteLine(response.Content.ToString());
});
await Task.Delay(1000);
asyncHandle.Abort();//PROBLEM
}
NancyRestServer:
public class RestModule : NancyModule
{
public RestModule() : base("/nancyserver")
{
Post("/whileasync", async (args, ctx) => await WhileAsync(args, ctx));
}
private async Task<bool> WhileAsync(dynamic args, CancellationToken ctx)
{
do
{
await Task.Delay(100);
if (ctx.IsCancellationRequested)//PROBLEM
{
break;
}
}
while (true);
return true;
}
}
The client sends a command to start a while loop on the server, waits for 1sec and aborts the async call.
The problem I'm having is that the asyncHandle.Abort(); doesn't seem to trigger the ctx.IsCancellationRequested on the server's side.
How am I supposed to cancel/abort an async call on a nancy host server using a restsharp client?
There's a couple of parts that go into cancelling a web request.
First, the client must support cancellation and use that cancellation to clamp the connection closed. So the first thing to do is to monitor the network packets (e.g., using Wireshark) and make sure RestSharp is sending a RST (reset), and not just closing its side of the connection. An RST is a signal to the other side that you want to cancel the request. Closing the connection is a signal to the other side that you're done sending data but are still willing to receive a response.
Next, the server must support detecting cancellation. Not all servers do. For quite a while, ASP.NET (pre-Core) did not properly support client-initiated request cancellation. There was some kind of race condition where it wouldn't cancel properly (don't remember the details), so they disabled that cancellation path. This has all been sorted out in ASP.NET Core, but AFAIK, it was never fixed in ASP.NET Legacy Edition.
If RestSharp is not sending an RST, then open an issue with that team. If Nancy is not responding to the RST, then open an issue with that team. If it's an ASP.NET issue, the Nancy team should know that (and respond informing you they can't fix it), in which case you're out of luck. :/

WebApi Controller - Send Mail Async

I have a WebApi Controller that one of the parts is sending emails to a set of users.
[HttpPost]
[Authorize]
[Route("{id}/Do")]
public async Task<HttpResponseMessage> Post(int id, Model model)
...
await _emailService.SendAsync(message);
...
Now the method that sends the emails (SendGrid)
public override async Task SendAsync(MailMessage message)
{
var client =
new SmtpClient(SendGridServerName, SendGridServerPort)
{
Port = SendGridServerPort,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false
};
var credentials = new NetworkCredential(SendGridUserName, SendGridPassword);
client.EnableSsl = true;
client.Credentials = credentials;
message.From = new MailAddress(FromAddress);
await client.SendMailAsync(message);
}
Everything works, but it's very slow. I was expecting it to be fast, but the await _emailService.SendAsync(message); does not appear to be async. It stops there for a while.
Any ideas?
Thanks
What async does is allowing your server to run other threads while your slow method is executed asynchronously. I.e., when you await for an async method, the server executes a different thread until the async method finishes execution, and then keep running the thread that called the async method. Async actions in a controller are treated exactly in the same way behind the scenes. So, the response from your async action to the browser will not happen until the async email sending has finished.
NOTE: for example, if there are connectivity problems to the email server, or the DNS resolution, you'll usually get a time out after 30 seconds, so your thread will be slept during 30 seconds, and only then will send the answer to the browser
If you want to return the response to your browser quickly, you need to implement a different idea, which is to start a new thread that sends the email, but don't wait for it to finish, so that your thread keeps running and inmediately returns the asnwer to the browser. That's known as fire and forget. To understand what I'm speaking about, please see this: Fire and forget approach. And then read this other carefully: Fire and Forget (Asynch) ASP.NET Method Call. Take into account that MVC itself is threaded and you need to have it into account when using the fire and forget approach.
Obvioulsy in fire and forget, the controller will not be able to detect errors during the email sending, beacause the new thread runs on its own while the main thread has already finished. So you have to implement something to at least log the possible error, and ideally let the user now what happened (for example which reports that he can see later on). Please, see this: ASP.NET Exception Handling in background threads

Categories