Keepalive

Keepalive is a repetitive signal firing at a predefined interval.

The observable should look like this:

--k--k--k--k--|

Where "k" is the keepalive event that fires at an interval of 20 frames.

Interval

The interval itself is achieved using Observable.interval. http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-interval

Suppose we abstract the logic for the keepalive (e.g. calling an API) within a service which returns an Observable: service.keepalive().

Then we use a simple switchMap to trigger the keepalive on an interval:

Observable
  .interval(KEEP_ALIVE_INTERVAL)
  .switchMap(() => service.keepAlive());

Initiation

We want to kick off the interval with another event:

START    ---s----------
INTERVAL -----k--k--k--

Suppose we use ngrx for our start action (KEEP_ALIVE_START):

@Effect() keepAlive$: Observable<Action> = updates$
  .whenAction(KEEP_ALIVE_START)
  .switchMap(() => {
    return Observable
      .interval(KEEP_ALIVE_INTERVAL)
      .switchMap(() => service.keepAlive());
  });

Stopping

Now we need to stop the keepalive interval. For this, we can use takeUntil which will complete an observable when a given observable fires an element. http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-takeUntil

START    ---s------------
INTERVAL -----k--k--k----
STOP     -------------x--
RESULT   -----k--k--k-|

Suppose we use ngrx for our stop action (KEEP_ALIVE_STOP):

@Effect() keepAlive$: Observable<Action> = updates$
  .whenAction(KEEP_ALIVE_START)
  .switchMap(() => {
    return Observable
      .interval(KEEP_ALIVE_INTERVAL)
      .switchMap(() => service.keepAlive())
      .takeUntil(updates$.whenAction(KEEP_ALIVE_STOP));
  });

Background

What if we want the keepalive to run in the background without emitting elements for every "ping"? For this, we use ignoreElements. http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-ignoreElements

START    ---s------------
INTERVAL -----k--k--k----
STOP     -------------x--
RESULT   -------------|
@Effect() keepAlive$: Observable<Action> = updates$
  .whenAction(KEEP_ALIVE_START)
  .switchMap(() => {
    return Observable
      .interval(KEEP_ALIVE_INTERVAL)
      .switchMap(() => {
        return service.keepAlive()
          .ignoreElements();
      })
      .takeUntil(updates$.whenAction(KEEP_ALIVE_STOP));
  });

Failures

What if we want to emit an element every time a keepalive ping fails?

In the exmaple below, the second ping fails:

START    ---s------------
INTERVAL -----k--k--k----
STOP     -------------x--
RESULT   --------f----|

We use catch to achieve this:

@Effect() keepAlive$: Observable<Action> = updates$
  .whenAction(KEEP_ALIVE_START)
  .switchMap(() => {
    return Observable
      .interval(KEEP_ALIVE_INTERVAL)
      .switchMap(() => {
        return service.keepAlive()
          .ignoreElements()
          .catch((response) => Observable.of(KEEP_ALIVE_FAIL));
      })
      .takeUntil(updates$.whenAction(KEEP_ALIVE_STOP));
  });

results matching ""

    No results matching ""