I've created a service to handle a WebSocket connection to send and receive messages, where I'm handling a few cases when a disconnection might happen and how to recover from them, but I'm missing the case where the browser itself (so to speak) goes offline it automatically retries when the navigator.onLine
emits a true
value again.
So far, by using the retryWhen
operator, I'm able to create a new session and restart it (if something goes wrong on the server side), until it reaches a maximum number of retries. But, by using the navigator.onLine
(as unreliable as it is, I know, but it works for the browsers we are using) I can restart the reconnection process, when the client goes offline.
I have this online checker observable:
private onlineCheck: Observable<boolean>;
this.onlineCheck = merge(
of(navigator.onLine),
fromEvent(window, 'online').pipe(mapTo(true)),
fromEvent(window, 'offline').pipe(mapTo(false)));
And this is how I'm creating a WebSocket (and handling a reconnection if needed):
public connect(): void {
// no more than one connection simultaneously
if (!(this.socket == null)) {
this.socket.complete();
}
this.socket = new WebSocketSubject(this.config);
this.socket
.pipe(
retryWhen((errors) => {
return errors.pipe(
tap((error) => { console.log('Error: ', error); }),
concatMap((e, i) =>
iif(
() => i < this.reconnectAttempts,
of(e).pipe(delay(this.reconnectInterval)),
throwError('Max amount of retries reached')
)));
}))
.subscribe(
(message: MessageEvent) => { this.onMessage(message); },
(error: Event) => { this.onError(error); },
() => { console.log('completed'); });
}
How can I combine an onlineCheck
subscription with the retryWhen
operator, in order to retry it, if the client went offline (and the maximum connection retries is reached) and is now back? If this is not the best approach, could you please suggest another?
Here's a complete StackBlitz example (check the console logs for better feedback): https://stackblitz.com/edit/angular-f4oa3y
Inside your iif
true condition, use this observable instead of of(e).pipe(delay(this.reconnectInterval))
:
timer(this.reconnectInterval) // wait for reconnect interval
.pipe(
concatMap(() => onlineCheck),
first(Boolean) // now wait for online to be true
)
That will emit an observable that will produce a single value after reconnectInterval and onlineCheck is true
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.