I'm trying to write a method that will poll for the status of an API operation, returning an observable that will emit the result of each status call (since it contains progress information I would like to display) until it gets a completion status, emits that status, and then it's done.
What I have so far is this:
pollStatus(identifier: string): Observable<OperationStatusResource> {
const obs = interval(1000)
.pipe(
startWith(0),
switchMap( () => this.apiService.operationStatus(identifier) ),
takeWhile( (value, index) => {
return value.status != OPERATION_STATUS.COMPLETE;
}, true)
)
return obs;
}
which works, and I understand it, but I think I can do better and I'm struggling to figure out how. This requests a new status every second and cancels the previous one if it hasn't completed yet. I DO want to cancel previous requests any time I send a new one to ensure that I never emit out of order due to internet shenanigans, but:
- I'd like the delay to apply starting after the response from the last request. So like req->resp->1000ms->req etc.
- I'd like to time-out each request. So for example if a request hasn't returned a response after 5 seconds, I'll cancel it and try again
I'd also be happy with any other way of accomplishing the same idea of being patient if the response takes a while, but not willing to wait forever, and not requesting too rapidly if the response comes back quickly either.
Bonus points if I can add an overall failure condition or timeout like give up if you get 3 timeouts in a row or if the whole thing takes more than 5 minutes or if I get 3 non-200 codes back in a row.