Skip to content

Instantly share code, notes, and snippets.

@greyblake
Last active December 2, 2018 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save greyblake/9d9d6205ad1fd7cabd9cf259bea617de to your computer and use it in GitHub Desktop.
Save greyblake/9d9d6205ad1fd7cabd9cf259bea617de to your computer and use it in GitHub Desktop.
http-poll
import { throwError, of, interval, Observable } from 'rxjs';
import { take, filter, map, concatMap, catchError } from 'rxjs/operators';
import { httpPoll, isNotReady } from './http-poll';
function buildError(code) {
return {
error: {
errors: [{ code }]
}
};
}
function buildPoll(call) {
let pollArgs = {
call,
delay: 0,
attempts: 10
};
return httpPoll(pollArgs);
}
describe('httpPoll', () => {
describe('when call function returns result', () => {
it('returns Observable that returns result', async () => {
let obs = buildPoll(() => of(5));
let result = await obs.toPromise();
expect(result).toEqual(5);
});
});
describe('when call function returns Observable that returns an error', () => {
it('propagates an error', async () => {
let obs = buildPoll(() => throwError(5));
let isRejected = false;
try {
await obs.toPromise();
} catch {
isRejected = true;
}
expect(isRejected).toEqual(true);
});
});
describe('when after sequence of NOT_READY a result is returned', () => {
it('returns a result', async () => {
let notReadyError = buildError('NOT_READY');
let count = 0;
let obs = buildPoll( () => {
if (count > 5) {
return of('RESULT');
} else {
count += 1;
return throwError(notReadyError);
}
});
let result = await obs.toPromise();
expect(result).toEqual('RESULT');
});
});
describe('when time outed', () => {
it('propagates the last error', async () => {
let notReadyError = buildError('NOT_READY');
let obs = buildPoll(() => throwError(notReadyError));
let isRejected = false;
try {
await obs.toPromise();
} catch {
isRejected = true;
}
expect(isRejected).toEqual(true);
});
});
});
describe('isNotReady', () => {
it('return true for NOT_READY error', () => {
expect(isNotReady({})).toEqual(false);
expect(isNotReady('')).toEqual(false);
expect(isNotReady('12')).toEqual(false);
expect(isNotReady({error: ''})).toEqual(false);
expect(isNotReady(buildError('NOT_FOUND'))).toEqual(false);
expect(isNotReady(buildError('NOT_READY'))).toEqual(true);
});
});
import { throwError, interval, Observable } from 'rxjs';
import { take, concatMap, catchError } from 'rxjs/operators';
interface PollArgs<T> {
call: () => Observable<T>,
delay: number,
attempts: number
}
export function httpPoll<T>({ call, delay, attempts }: PollArgs<T>): Observable<T> {
return interval(delay).pipe(
concatMap( (_) => call()),
catchError((err: any) => {
if (isNotReady(err) && attempts > 0) {
let newArgs = { call, delay, attempts: attempts - 1};
return httpPoll(newArgs);
} else {
return throwError(err);
}
}),
take(1)
);
}
export function isNotReady(err: any): boolean {
return !!(
err
&& err.error
&& err.error.errors
&& err.error.errors[0]
&& err.error.errors[0].code === 'NOT_READY'
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment