What is the difference between WebSocket4Net's MessageReceived or DataReceived events?
I identified some differences between MessageReceived or DataReceived event. When server is sending messages in bytes format it will receive in DataReceived event. But if messages is coming in string format it will receive in MessageReceived event.
Related
I am using bidirectional grpc between my client and server. I would like to implement async bidi on both client and server i.e., client opens a stream and starts sending arbitrary messages to server, while another thread continues receiving server responses. This example below demonstrates the server side async bidi https://groups.google.com/forum/m/#!topic/grpc-io/DuBDpK96B14.
Has anyone tried async bidi on client side?
There's a codelab for it with both client and server at https://grpc.io/docs/tutorials/async/helloasync-cpp/
Async client
To use an asynchronous client to call a remote method, you first create a channel and stub, just as you do in a synchronous client. Once you have your stub, you do the following to make an asynchronous call:
Initiate the RPC and create a handle for it. Bind the RPC to a CompletionQueue.
CompletionQueue cq;
std::unique_ptr<ClientAsyncResponseReader<HelloReply> > rpc(
stub_->AsyncSayHello(&context, request, &cq));
Ask for the reply and final status, with a unique tag
Status status;
rpc->Finish(&reply, &status, (void*)1);
Wait for the completion queue to return the next tag. The reply and status are ready once the tag passed into the corresponding Finish() call is returned.
void* got_tag;
bool ok = false;
cq.Next(&got_tag, &ok);
if (ok && got_tag == (void*)1) {
// check reply and status
}
You can see the complete client example in greeter_async_client.cc.
I have questions on Rebus retry policy below:
Configure.With(...)
.Options(b => b.SimpleRetryStrategy(maxDeliveryAttempts: 2))
.(...)
https://github.com/rebus-org/Rebus/wiki/Automatic-retries-and-error-handling#customizing-retries
1 Can it be used for both Publiser (enqueue messages) and Subscriber (dequeue messages)?
2 I have a subscriber that is unable to dequeue the message. Thus the message is sent to error queue.
Below is error for when putting the message to error queue. But I cannot see the loggings for the retry.
[ERR] Rebus.Retry.PoisonQueues.PoisonQueueErrorHandler (Thread #9): Moving messa
ge with ID "<unknown>" to error queue "poison"
Rebus.Exceptions.RebusApplicationException: Received message with empty or absen
t 'rbs2-msg-id' header! All messages must be supplied with an ID . If no ID is p
resent, the message cannot be tracked between delivery attempts, and other stuff
would also be much harder to do - therefore, it is a requirement that messages
be supplied with an ID.
Is it possible to define and store custom logging for each retry, not within IErrorHandler?
3 How long does each retry wait in between be default?
4 Is it possible to define custom wait time for each retry (not within IErrorHandler)? If so, is Polly supported for this scanario? like below:
Random jitterer = new Random();
Policy
.Handle<HttpResponseException>() // etc
.WaitAndRetry(5, // exponential back-off plus some jitter
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
+ TimeSpan.FromMilliseconds(jitterer.Next(0, 100))
);
https://learn.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/implement-http-call-retries-exponential-backoff-polly
Update
How can I test the retry policy?
Below is what I tried based on the code below:
public class StringMessageHandler : IHandleMessages<String>
{
public async Task Handle(String message)
{
//retry logic with Polly here
}
}
I sent an invalid message of string type to the string topic, however, the Handle(String message) is not invoked at all.
Rebus' retry mechanism is only relevant when receiving messages. It works by creating a "queue transaction"(*), and then if message handling fails, the message gets rolled back to the queue.
Pretty much immediately thereafter, the message will again be received and attempted to be handled. This means that there's no delay between delivery attempts.
For each failed delivery, a counter gets increased for that message's ID. That's why the message ID is necessary for Rebus to work, which also explains why your message with out an ID gets immediately moved to the dead-letter queue.
Because of the disconnected nature of the delivery attempts (only a counter per message ID is stored), there's no good place to hook in a retry library like Polly.
If you want to Pollify your message handling, I suggest you carry out individual operations with Polly policies – that way, you can easily have different policies for dealing with failing web requests, failing file transfers on network drives, etc. I do that a lot myself.
To avoid not being able to properly shut down your bus instance if it's in the process of a very long Polly retry, you can pass Rebus' internal CancellationToken to your Polly executions like this:
public class PollyMessageHandler : IHandleMessages<SomeMessage>
{
static readonly IAsyncPolicy RetryPolicy = Policy
.Handle<Exception>()
.WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(10));
readonly IMessageContext _messageContext;
public PollyMessageHandler(IMessageContext messageContext)
{
_messageContext = messageContext;
}
public async Task Handle(SomeMessage message)
{
var cancellationToken = _messageContext.GetCancellationToken();
await RetryPolicy.ExecuteAsync(DoStuffThatCanFail, cancellationToken);
}
async Task DoStuffThatCanFail(CancellationToken cancellationToken)
{
// do your risky stuff in here
}
}
(*) The actual type of transaction depends on what is supported by the transport.
With MSMQ, it's a MessageQueueTransaction object that has Commit() and Rollback() methods on it.
With RabbitMQ, Azure Service Bus, and others, it's a lease-based protocol, where a message becomes invisible for some time, and then if the message is ACKed within that time, then the message is deleted. Otherwise – either if the message or NACKed, or if the lease expires – the message pops up again, and can again be received by other consumers.
With the SQL transports, it's just a database transaction.
I have web app on Azure with 2 slots.
Whenever the slot swap happens, all SignalR clients are disconnected and not even notified about the connection loss.
SignalR events such a Close, Error, Reconnected are never fired on the client.
How to prevent this or at least know when disconnect happens? (of course I need to avoid polling)
How to prevent this or at least know when disconnect happens?
We could enable SignalR tracing to view diagnositc infomration about events in your SignalR application. How to enable and configure tracing for SignalR servers and clients, we could refer to this document.
Detecting the reason for a disconnection
SignalR 2.1 adds an overload to the server OnDisconnect event that indicates if the client deliberately disconnected rather than timing out. The StopCalled parameter is true if the client explicitly closed the connection. In JavaScript, if a server error led the client to disconnect, the error information will be passed to the client as $.connection.hub.lastError.
C# server code: stopCalled parameter
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
if (stopCalled)
{
Console.WriteLine(String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId));
}
else
{
Console.WriteLine(String.Format("Client {0} timed out .", Context.ConnectionId));
}
return base.OnDisconnected(stopCalled);
}
JavaScript client code: accessing lastError in the disconnect event.
$.connection.hub.disconnected(function () {
if ($.connection.hub.lastError)
{ alert("Disconnected. Reason: " + $.connection.hub.lastError.message); }
});
More details we could refer to Detecting the reason for a disconnection.
How to prevent this?
We could continuously reconnect it.
In some applications you might want to automatically re-establish a connection after it has been lost and the attempt to reconnect has timed out. To do that, you can call the Start method from your Closed event handler (disconnected event handler on JavaScript clients). You might want to wait a period of time before calling Start in order to avoid doing this too frequently when the server or the physical connection are unavailable. The following code sample is for a JavaScript client using the generated proxy.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
More details we could refer to How to continuously reconnect
I'm struggling to find any good examples on how to implement error handling with Spring WebFlux.
The use case I want to handle is notifying HTTP clients that a stream has terminated unexpectedly. What I have found it that with the out of the box behaviour, when a stream is terminated, for example by raising a RuntimeException after x items have been processed, is handled too gracefully! The client is flushed all items up until the exception is raised, and then the connection is closed. As far as the client is concerned the request was successful. The following code shows how this has been setup:
public Mono<ServerResponse> getItems(ServerRequest request) {
Counter counter = new Counter(0);
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(operations.find(query, Document.class, "myCollection")
.map(it -> {
counter.increment();
if(counter.getCount() > 500) {
throw new RuntimeException("an error has occurred");
}
return it;
}), Document.class);
}
What is the recommended way to handle the error and notify the HTTP client that the stream terminated unexpectedly?
It really depends on how you'd like to communicate that failure to the client. Should the client display some specific error message? Should the client reconnect automatically?
If this is a "business error" that doesn't prevent you from writing to the stream, you could communicate that failure using a specific event type (look at the Server Sent Events spec).
Spring WebFlux supports ServerSentEvent<T>, which allows you to control various fields such as event, id, comment and data (the actual data). Using an Flux::onErrorMap operator, you could write a specific ServerSentEvent that has an "error" event type (look at the ServerSentEvent.builder() for more).
But this is not transparent to the client, as you'd have to subscribe to specific events and change your JavaScript code otherwise you may display error messages as regular messages.
I have SignalR working with an Angular client, but I can't get proxy.on() to work if the connection is established before I subscribe to events.
My server method invokes the client method pushToClient on both hubs.
var connection1 = $.hubConnection(); //Works fine since I started connection AFTER subscribing
var proxy1 = connection1.createHubProxy('clientPushHub');
proxy1.on('sendToClient', function (message) {
console.log('This will work: ' + message);
});
connection.start();
var connection2 = $.hubConnection(); // Doesn't work when I start the connection BEFORE subscribing
var proxy2 = connection2.createHubProxy('clientPushHub');
connection2.start();
proxy2.on('sendToClient', function (message) {
console.log('This will not work: ' + message);
});
If I change things so that proxy2 subscribes to pushToClient before starting connection2, it works fine. Also tried doing the 'on' subscription in the start().done() callback but that did not work.
I've downloaded and verified this example works as I expected when subscribing after connecting, and this ASP.NET article/section specifically mentions you can do things in this order if you don't use a generated proxy, which I haven't.
What worked for the asker in this SO question does not work for me.
Any ideas where I might have gone wrong?
Based on this post, it sounds like you have to have at least one event listener prior to calling start. From there you can add more event handlers using the 'on' functionality.
EDIT:
Try this.
proxy2.on('foo',function(){});
connection2.start();
proxy2.on('sendToClient', function (message) {
console.log('This will not work: ' + message);
});
Also this is from the article you linked you for post:
Note: Normally you register event handlers before calling the start method to establish the connection. If you want to register some event handlers after establishing the connection, you can do that, but you must register at least one of your event handler(s) before calling the startmethod. One reason for this is that there can be many Hubs in an application, but you wouldn't want to trigger the OnConnected event on every Hub if you are only going to use to one of them. When the connection is established, the presence of a client method on a Hub's proxy is what tells SignalR to trigger the OnConnected event. If you don't register any event handlers before calling the start method, you will be able to invoke methods on the Hub, but the Hub'sOnConnected method won't be called and no client methods will be invoked from the server.