简体   繁体   中英

RXJS RetryWhen - continue error downstream while attempting retry

The steps:

  1. I have a source stream (observable) that is a web socket connection.

  2. When the connection is disconnected or errors the source emits a error on the stream.

  3. Downstream from the source I use retryWhen to attempt a reconnect to the web socket connection after every x seconds.

    • Up to this point everything works as I want.
  4. Further downstream I have a catchError that sets a default value. This allows the application to know the up-to-date status of the connection.

Example code (a very simplistic example of my code):

connect(): Observable<any> {
  return this.websocket() // source stream that errors when it disconnects
    .pipe(
      retryWhen( errors => 
        errors.pipe(
         delay( 2000 ) // delay retry
        )
      )
    )
}

connectionStatus(): Observable<boolean>{
  return this.connect().pipe(
    catchError( () => of( false ) ), // this does not trigger with the retryWhen
    map( () => true )
  )
}

The problem:

I want the downstream subscribers to know that it's disconnected while it is attempting the retryWhen . However, the downstream catchError is not triggered while retryWhen is happening.

Any ideas how I can attempt re-connecting for all subscribers (not just the connectionStatus), but also when notify downstream when the connection is down (errors).

After re-connecting I want to continue streaming to all subscribers like nothing has happened.

Let me know if anything is unclear.

So writing this post helped me answer my own question.

/*
Basic stream handling no errors or retries..
*/
connect(){
  return this.websocket();
}

/*
Have a stream that is always connected for all subscribers
*/
alwaysConnected(){
  return this.connect().pipe(
    retryWhen( errors => {
      return errors.pipe(
        delay( 2000 )
      )
    })
  )
}

/*
use the continuous stream (no errors) and then in sub stream listen for the errors.
*/
connectionFails() {
  return this.alwaysConnected().pipe(
    switchMap( () => {
      return this.connect().pipe( // switch to stream that errors
        catchError( error => of( false ) ),
        filter(connection => connection === false )
      ) 
    })
  )
}

/*
Get a boolean for either a fail or success
*/
connectionStatus() {
  return merge(
    this.connectionFails(),
    this.alwaysConnected().pipe( map( () => true ))
  )
}

There were a couple of issues.

  1. handling retry and catcherror

  2. not completing a subscription when handling the error

There might be a simpler more elegant solution. Feel free to suggest.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM