How to periodically check live connection using rxjs?

冷暖自知 提交于 2020-01-15 09:52:10

问题


I use rxjs to handle a websocket connection

var socket = Rx.Observable.webSocket('wss://echo.websocket.org')
socket.resultSelector = (e) => e.data

I want to periodically (5s) sent a ping message and wait 3s to receive a pong response and subscribe to the a stream if no response has been receive.

I try that without success. I admit I'm a bit lost will all the operator available to handle timeout, deboune or throttle.

// periodically send a ping message
const ping$ = Rx.Observable.interval(2000) 
  .timeInterval()
  .do(() => socket.next('ping'))

const pong$ = socket  
  .filter(m => /^ping$/.test(`${m}`))  
  .mergeMap( 
    ping$.throttle(2000).map(() => Observable.throw('pong timeout'))
  ) 

 pong$.subscribe(
   (msg) => console.log(`end ${msg}`),
   (err) => console.log(`err ${err}`),
   () => console.log(`complete`)
 )

But unfortunately, no ping are send.

I've also try to achieved that using without success.

const ping$ = Rx.Observable.interval(2000) 
  .timeInterval()
  .do(() => socket.next('ping'))


const pong$ = socket  
  .filter(m => /^ping$/.test(`${m}`)) 

const heartbeat$ = ping$
  .debounceTime(5000) 
  .mergeMap(() => Rx.Observable.timer(5000).takeUntil(pong$))

heartbeat$.subscribe(
  (msg) => console.log(`end ${msg}`),
  (err) => console.log(`err ${err}`),
  () => console.log(`complete`)
)

Any help appreciated.


回答1:


You can use race() operator to always connect only to the Observable that emits first:

function sendMockPing() {
  // random 0 - 5s delay
  return Observable.of('pong').delay(Math.random() * 10000 / 2);
}

Observable.timer(0, 5000)
  .map(i => 'ping')
  .concatMap(val => {
    return Observable.race(
      Observable.of('timeout').delay(3000),
      sendMockPing()
    );
  })
  //.filter(response => response === 'timeout') // remove all successful responses
  .subscribe(val => console.log(val));

See live demo: https://jsbin.com/lavinah/6/edit?js,console

This randomly simulates response taking 0 - 5s. When the response takes more than 3s than Observable.of('timeout').delay(3000) completes first and the timeout string is passed to its observer by concatMap().




回答2:


I finally found a solution based on mergeMapand takeUntil

My initial mistake was to use ping$ as an input for my heartBeat$ where I should use $pong

// define the pong$
const pong$ = socket  
  .filter(m => /^ping$/.test(`${m}`)) 
  .share() 

//use share() because pong$ is used twice

const heartbeat$ = pong$
  .startWith('pong') // to bootstrap the stream
  .debounceTime(5000) // wait for 5s after the last received pong$ value
  .do(() => this.socket.next('ping')) // send a ping
  .mergeMap(() => Observable.timer(3000).takeUntil(pong$))
// we merge the current stream with another one that will 
// not produce value while a pong is received before the end of the 
// timer

heartbeat$.subscribe(
  (msg) => console.log(`handle pong timeout`),
)



回答3:


Below heartbeat$ function return an observable which you can continuously listen to

1) the latency value of each round trip (time of socket.receive - socket.send) in every 5000ms

or

2) -1 if the round trip goes beyond the threshold (e.g. 3000ms)

You will keep receiving latency value or -1 even though -1 has been emitted which gives you the flexibility to decide what to do ^.^

heartbeat$(pingInterval: number, pongTimeout: number) {
  let start = 0;

  const timer$ = timer(0, pingInterval).pipe(share());

  const unsub = timer$.subscribe(() => {
    start = Date.now();
    this.ws.next('ping');
  });

  const ping$ = this.ws$.pipe(
    switchMap(ws =>
      ws.pipe(
        filter(m => /^ping$/.test(`${m}`)),
        map(() => Date.now() - start),
      ),
    ),
    share(),
  );

  const dead$ = timer$.pipe(
    switchMap(() =>
      of(-1).pipe(
        delay(pongTimeout),
        takeUntil(ping$),
      ),
    ),
  );

  return merge(ping$, dead$).pipe(finalize(() => unsub.unsubscribe()));
}

heartbeat$(5000, 3000).subscribe(
  (latency) => console.log(latency) // 82 83 82 -1 101 82 -1 -1 333 ...etc
)


来源:https://stackoverflow.com/questions/42115698/how-to-periodically-check-live-connection-using-rxjs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!