Timer in ForkJoin

1.1k Views Asked by At

I have an API with 3 GET calls.

  1. Get environments
  2. Get products
  3. Get status for specific product in specific environment

What I am trying to do is to poll the status of each product in each environment every 5 minutes, so that I can display the data in a table which is refreshed.

The call to fetch envs and products should be executed once, since this is static information.

let envs = this.http.get('http://my-api/envs);
let products = this.http.get('http://my-api/products);

forkJoin([envs, products]).subscribe(results => {
  //the code below should be executed every 5 mins and store the results in array
  results[0].forEach(env => {
    results[1].forEach(product => {
      this.http.get('http://my-api/status/${env}/${product}')
    })
  })
})

Any help would be appreciated.

1

There are 1 best solutions below

11
On BEST ANSWER

Not sure what this accomplishes, but it runs the code in the subscription every five minutes. Well, more accurately it calls the forkJoin every 5 minutes. If the forkJoin takes a variable amount of time to execute that might shift the time a bit. Otherwise, you could call forkJoin early and delay the results to the five-minute mark with delay and some math on Date()

const fiveMinutes = 1000 * 60 * 5;
timer(0, fiveMinutes).pipe(
  switchMap(_ => forkJoin({
     envs: this.http.get('http://my-api/envs'),
     products: this.http.get('http://my-api/products')
  }))
).subscribe(({envs, products}) => {
  envs.forEach(env => {
    products.forEach(product => {
      // This http call doesn't do anything ?
      this.http.get('http://my-api/status/${env}/${product}') 
    })
  })
});

Update # 1: interval on final calls.

This one calls your this.http.get('http://my-api/status/${env}/${product}') calls every 5 minutes and sends the results to the subscription as an array.

This isn't tested for obvious reasons. But it should provide a good starting point.

const fiveMinutes = 1000 * 60 * 5;
forkJoin({
  envs: this.http.get('http://my-api/envs'),
  products: this.http.get('http://my-api/products')
}).pipe(
  map(({env, products}) => 
    envs.map(env =>
      products.map(product =>
        this.http.get('http://my-api/status/${env}/${product}') 
      )
    ).flat()
  ),
  mergeMap(statusCalls => timer(0, fiveMinutes).pipe(
    mergeMap(_ => forkJoin(statusCalls))
  ))
).subscribe(statusCallsResults => {
  //** Update your view with results **//
})

If you really want your subscription as set up before, that might look like this:

const fiveMinutes = 1000 * 60 * 5;
forkJoin({
  envs: this.http.get('http://my-api/envs'),
  products: this.http.get('http://my-api/products')
}).pipe(
  mergeMap(res => timer(0, fiveMinutes).pipe(
    map(_ => res)
  ))
).subscribe(({envs, products}) => {
  // This is called every five minutes
  envs.forEach(env => {
    products.forEach(product => {
      // This http call doesn't do anything ?
      this.http.get('http://my-api/status/${env}/${product}') 
    })
  })
});

Update # 2: Error Handling

forkJoin will fail if any of its inner observables fail. You can deal with this in many ways. The most basic is to transform an errored stream into a stream that emits null and completes successfully. Then forkJoin will have null in every array position with an error.

That might look like this:

const fiveMinutes = 1000 * 60 * 5;
forkJoin({
  envs: this.http.get('http://my-api/envs'),
  products: this.http.get('http://my-api/products')
}).pipe(
  map(({env, products}) => 
    envs.map(env =>
      products.map(product =>
        this.http.get('http://my-api/status/${env}/${product}').pipe(
          catchError(err => of(null))
        )
      )
    ).flat()
  ),
  mergeMap(statusCalls => timer(0, fiveMinutes).pipe(
    mergeMap(_ => forkJoin(statusCalls))
  ))
).subscribe(statusCallsResults => {
  //** Update your view with results **//
})

Error code 500 isn't very descriptive. You might look into the retry operator to retry the request when it fails. That can be combined with catchError.

Not getting that error from the server in the first place is up to you.