RxJava retry based on logic - retrofit

Here is the case, I have an API call using Retrofit that might fail due to a network error. If it fails we will show an error message with a retry button. When the user presses the retry button we need to retry the latest Observable again.
Possible Solutions:
Retry: Retry should be used before subscribing to the observable and it will immediately resubscribe again if an error happens and that is what I don't want, I need to resubscribe only if the user pressed the Retry button.
RetryWhen: It Will keep trying as you emit items until you emit an Observable error then it will stop. Same issue here, I need to not start the retry process unless the user decides to.
Resubscribe to the same Observable: This solution will start emitting the Observable items, the problem with this is that we are using the cache operator, so if one Observable failed, we got the failed item cached and when we do subscribe again, we got the same error again.
Are there any other solutions to go with?

You can go with retryWhen, which parameter - Func1 - returns an Observable which indicates when a retry should happen. For example :
PublishSubject<Object> retryButtonClicked = PublishSubject.create();
Observable
.error(new RuntimeException())
.doOnError(throwable -> System.out.println("error"))
.retryWhen(observable -> observable.zipWith(retryButtonClicked, (o, o2) -> o))
.subscribe();
retryButtonClicked.onNext(new Object());
every time retryButtonClicked emmits an event, Observable will be retried
Here's also an example - https://gist.github.com/benjchristensen/3363d420607f03307dd0

Related

Rebus with secondLevelRetriesEnabled enable retries doesn't stop retrying on IFailed<T> handler

I'm having an issue with rebus (that I'm sure it's me the problem) and here's the issue:
I have second level retries enabled.
In the normal handler I throw a FailFastException
In the IFailed handler I got the message and I do a kind of "delayed" retry (I defer 10 times with a delay of 30s)
After all 10 re-tries, I want to finish (aka send to error queue) and for this I'm just throwing a new exception and it "kinda" works.
The issue is in the last step, when I throw the last exception, rebus still retries 5 times (default). So actually I'm retrying 10 times (defer) + 5 times(rebus default fast retry).
Is there any way I can only do the 10 (deferred) times? I can forward to the dead letter queue manually but... it seems hacky.
Also, I use fleet manager, does forwarding the message to the error queue means the message will also be in the fleet manager?
Is there any way I can only do the 10 (deferred) times? I can forward to the dead letter queue manually but... it seems hacky.
Yes, but it requires a little bit of manual work 🙂 you can do something like this in your 2nd level retry handler:
try
{
await TrySomethingAlternativeAsync();
}
catch(Exception exception)
{
// bummer, it still fails!
//
// just deadletter the message now then
await bus.Advanced.TrandportMessage.Deadletter(exception);
}
Also, I use fleet manager, does forwarding the message to the error queue means the message will also be in the fleet manager?
Yes 🙂

Can a saga has multiple timeout handlers

We have implemented a saga that has a timeout method and worked as expected. Later we wanted to add one more timeout method. So, I have added it to the same saga but the second timeout is not getting called. These two messages will be called at a time. Can we have two IHandlerTimeouts in a single saga?
public class SagaPolicy1 : Saga<SagaPolicyData>,
IAmStartedByMessages<OrderPlacedCommand>,
IHandleTimeouts<TimoutMsg1>,//timespan 20min
IHandleTimeouts<TimoutMsg2>
await RequestTimeout<TimoutMsg1>(context, TimeSpan.FromSeconds(1200));
await RequestTimeout<TimoutMsg2>(context, TimeSpan.FromSeconds(360));
The short answer is yes. The documentation explicitly calls it out. Remember that a timeout can be queued after its saga has been completed (using MarkAsComplete()). Because a timeout is tied to a specific saga instance, it will be ignored once the saga instance is completed.

grpc client completion queue not shutting down

My code performs the following:
1)Create grpc channel
2)start monitoring completion queue in a different thread
3)Issue shutdown on completion queue
After executing step 3, I expect "(cq.Next(&tag, &ok)" to return false as there are no pending events with above 3 steps. But it is observed that "(cq.Next(&tag, &ok)" never returns false. Please let me know if I am missing something.
Thanks,
Ikshu
In order to get channel state notification, a tag was being added to the queue and that use to always post some events. so the cq->next() never returned false. I fixed this issue by achieving same functionality by using already existing standard API for channel state. So closing the bug.

Firestore Timeout [duplicate]

We are building a real-time chat app using Firestore. We need to handle a situation when Internet connection is absent. Basic message sending code looks like this
let newMsgRef = database.document(“/users/\(userId)/messages/\(docId)“)
newMsgRef.setData(payload) { err in
if let error = err {
// handle error
} else {
// handle OK
}
}
When device is connected, everything is working OK. When device is not connected, the callback is not called, and we don't get the error status.
When device goes back online, the record appears in the database and callback triggers, however this solution is not acceptable for us, because in the meantime application could have been terminated and then we will never get the callback and be able to set the status of the message as sent.
We thought that disabling offline persistence (which is on by default) would make it trigger the failure callback immediately, but unexpectedly - it does not.
We also tried to add a timeout after which the send operation would be considered failed, but there is no way to cancel message delivery when the device is back online, as Firestore uses its queue, and that causes more confusion because message is delivered on receiver’s side, while I can’t handle that on sender’s side.
If we could decrease the timeout - it could be a good solution - we would quickly get a success/failure state, but Firebase doesn’t provide such a setting.
A built-in offline cache could be another option, I could treat all writes as successful and rely on Firestore sync mechanism, but if the application was terminated during the offline, message is not delivered.
Ultimately we need a consistent feedback mechanism which would trigger a callback, or provide a way to monitor the message in the queue etc. - so we know for sure that the message has or has not been sent, and when that happened.
The completion callbacks for Firestore are only called when the data has been written (or rejected) on the server. There is no callback for when there is no network connection, as this is considered a normal condition for the Firestore SDK.
Your best option is to detect whether there is a network connection in another way, and then update your UI accordingly. Some relevant search results:
Check for internet connection with Swift
How to check for an active Internet connection on iOS or macOS?
Check for internet connection availability in Swift
As an alternatively, you can check use Firestore's built-in metadata to determine whether messages have been delivered. As shown in the documentation on events for local changes:
Retrieved documents have a metadata.hasPendingWrites property that indicates whether the document has local changes that haven't been written to the backend yet. You can use this property to determine the source of events received by your snapshot listener:
db.collection("cities").document("SF")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("Error fetching document: \(error!)")
return
}
let source = document.metadata.hasPendingWrites ? "Local" : "Server"
print("\(source) data: \(document.data() ?? [:])")
}
With this you can also show the message correctly in the UI

Queue of Future in dart

I want to implement a chat system.
I am stuck at the point where user sends multiple messgaes really fast. Although all the messages are reached to the server but in any order.
So I thought of implementing a queue where each message shall
First be placed in queue
Wait for its turn
Make the post request on its turn
Wait for around 5 secs for the response from server
If the response arrives within time frame and the status is OK, message sent else message sending failed.
In any case of point 5, the message shall be dequeued and next message shall be given chance.
Now, the major problem is, there could be multiple queues for each chat head or the user we are talking to. How will I implement this? I am really new to dart and flutter. Please help. Thanks!
It sounds like you are describing a Stream - a series of asynchronous events which are ordered.
https://www.dartlang.org/guides/language/language-tour#handling-streams
https://www.dartlang.org/guides/libraries/library-tour#stream
Create a StreamController, and add messages to it as they come in:
var controller = StreamController<String>();
// whenever you have a message
controller.add(message);
Listen on that stream and upload the messages:
await for(var messsage in controller.messages) {
await uploadMessage(message);
}

Resources