Closed JeffreyMcJeffFace closed 3 years ago
Hello! Sorry for such a delay.
In general, an action of subscribing is decoupled from the flow of the SDK for many reasons (i.e. handling many subscriptions at once, delay because of other subscribe actions happening). This is the reason why the exception doesn't happen on the callsite of pn.subscribe
method.
To prevent that, there is a mechanism in the SDK that allows to declare what exceptions are "recoverable from" (by default this mechanism is disabled, therefore if a subscription fails for any reason it throws - reasoning is that its better to find and diagnose exceptions early in the development cycle instead of masking them from the beginning).
This mechanism relies on few concepts:
supervisor
is a module thats responsible for handling exceptions as they happen.diagnostic
is an abstraction of an exception - while exceptions tell you what went wrong, diagnostic is means to say why something went wrong (i.e. exception is "publish failed", diagnostic is "network is down").strategy
is an abstraction of an action that we can do in response of an exception (characterized by a diagnostic). In case of a "network is down" diagnostic our strategy can be "wait 10 seconds and retry".resolution
is a concrete action that the strategy can recommend the SDK to do (resolutions are things like "wait 10 seconds", "retry", "give up", "notify other components that network is down").In our current SDK we have a built-in "automatic request retrial" mechanism that can be enabled by passing correct configuration to the PubNub instance, but this mechanism can be extended by custom behaviour.
In your case you could use this mechanism in few steps:
supervisor
during app setup.I can create a Gist with the example code and you can modify it and use it in your application if you'd like. Let me know if this is something that can help you.
Here is the aforementioned Gist: https://gist.github.com/are/31c7a39d1798fc4a591b56b37e870e3b
Let me know if this is something that works for you or if I can help you in any other way.
Also, I skipped over one important detail - a lot of subscribe errors are sent through the subscription.messages
stream. The default Dart behaviour is that if there is no error handler attached to the stream, the exceptions will be considered unhandled. But adding an onError: (exception) {}
handler to the listen
function will properly catch those exceptions and they will no longer break the whole flow.
This is great information, thank you!
We put together an architecture for our specific use case and set the task aside until we have the available bandwidth with our backend developer. This explanation and the Gist is an excellent explanation/example. Thanks!
@are thanks for the gist it is helpfull , as you mentioned In our current SDK we have a built-in "automatic request retrial" mechanism that can be enabled by passing correct configuration to the PubNub instance, but this mechanism can be extended by custom behaviour.
as i need a custom excpetion interface from where i can caught up 403 status exception and needs to retry that function from that common place can you help me here?
@Brinfotech1407 Sure! What are you having problems with in particular? What have you tried previously?
@are i have used your gist classes and registered the following supervisior
pubnub.supervisor.registerDiagnostic(AccessDeniedDiagnostic.handler); pubnub.supervisor.registerStrategy(AccessDeniedStrategy());
Now i have basically two methods 1) fetch history 2) publish a message
For fetching a message via history i am doing the following
try {
final BatchHistoryResult result =
await _client!.batch.fetchMessages(
channelSet,
count: totalMessages <= 25 ? totalMessages : 25,
end: Timetoken(BigInt.from(endTimeToken)),
start: startTimeToken == null
? null
: Timetoken(BigInt.from(startTimeToken)),
reverse: false,
);
} on PubNubException catch (e) {
if (e.message == 'Forbidden because Token is expired.') {
log.i('PubNubException retrying for new token , Token is expired');
await getPubnubAccessToken();
_handleHistory(); // function for retry again history
}
}
And for publishing a message i am doing the following
try {
await _client!.publish( channelID!, json );
} on PubNubException catch (e) {
if (e.message == 'Forbidden because Token is expired.') {
log.i('PubNubException retrying for new token , Token is expired');
await getPubnubAccessToken();
retryPublishMessage(); // function for retry again publishing a message
}
}
As above both function is communicating with pubnub and i need to catch a manual exception on everyfunction i just want a common interface where we can caught a exception and retry the request after fetching a new token is there any thing we can do like that ?
Yes! This should be possible to do using this mechanism, however there maybe one piece missing so I'm going to work on a quick release to add this feature.
@are let us know if there is an update at your end.
Yes! This should be possible to do using this mechanism, however there maybe one piece missing so I'm going to work on a quick release to add this feature.
@are I see some connection related discussion in the latest issues, so when you are planning for this quick release?
pubnub version: pubnub: ^4.0.0-beta.0
While trying to implement access management (PAM), I repeatedly had an issue where I would receive an RequestFailureException. The thrown Exception occurs in subscribe_loop.dart here:
In my case it was caused by trying to subscribe to a channel too quickly after my backend had applied the appropriate grants. Effectively, I was making the subscribe call before PubNub had applied the grants.
To Reproduce:
Please provide guidance on whether I need to do something different or there is an actual bug. There are two specific items I'm trying to do:
Connection Failure Handling Know when a connection failure occurs so I can contact my backend server again to re-apply grants. It's not clear how I should implement the client to know when to handle a situation like this.
I tried wrapping subscribe call in a try/catch like this while trying to figure out what was going on, and the catch block was never hit.
Subscribing Too Soon After Grant Applied When my Flutter client initiates chat, I first make a call to my backend server to generate an auth key, apply grants, and then return the key to the client where it then creates the PubNub object and subscribes. This subscribe call frequently fails.
This appears to be caused by some side of PubNub-side delay. If I put a break point on my backend code (C#) after it makes the grant call to PubNub and then allow to return API call to the Flutter client after a few moments, the Flutter client can successfully subscribe to the channel.
I'm not sure this will be an issue once deployed as the latency from an end user to our servers to PubNub and back might be long enough to prevent this from happening. However, because of inability to detect connection failure, I'm not sure how handle this situation other than putting in an explicit delay client-side before attempting the subscribe call.