Skip to content

Instantly share code, notes, and snippets.

@rendfall
Last active August 9, 2019 17:42
Show Gist options
  • Save rendfall/6900ef102575d4c0df5bbc11c42565e6 to your computer and use it in GitHub Desktop.
Save rendfall/6900ef102575d4c0df5bbc11c42565e6 to your computer and use it in GitHub Desktop.
[RxJS] Retry HTTP request as long as response status is PENDING (1)
import { makeRequestWhile } from './make-request-while'
const MOCKED_API = {
PENDING: 'https://www.mocky.io/v2/5d4db060330000254b33796a',
SUCCESS: 'https://www.mocky.io/v2/5d4db057330000d43f337969',
ERROR: 'https://www.mocky.io/v2/5d4db0463300004b44337968',
}
const STATUSES = {
PENDING: 1,
SUCCESS: 0,
ERROR: -1,
}
makeRequestWhile(MOCKED_API.PENDING, (response) => {
return response.status === STATUSES.PENDING;
})
.then((response) => { console.log(response); })
.catch((error) => { console.log(error); });
import { retryGenerator } from './retry-generator';
import { makeRequest$ } from './make-request.ts';
import { delay as rxDelay, expand as rxExpand, takeWhile as rxTakeWhile } from 'rxjs/operators';
export interface MakeRequestWhileOptionsInterface {
retryGenerator?: any;
tryLimit?: number;
}
export function makeRequestWhile<T>(url: string, takeWhileFn: Function, options: MakeRequestWhileOptionsInterface = {}): Promise<T> {
const retryGen = options.retryGenerator || retryGenerator(1000, 1000, 2);
const tryCountLimit = options.tryLimit || 6;
return new Promise((resolve, reject) => {
let tryCount = 0;
makeRequest$(url)
.pipe(
rxExpand(() => {
tryCount++;
const delayTime = retryGen.next().value;
return makeRequest$(url)
.pipe(
rxTakeWhile((response: T) => {
if (!takeWhileFn(response)) {
resolve(response);
return false;
}
if (tryCount >= tryCountLimit) {
reject(response);
return false;
}
return true;
}),
rxDelay(delayTime)
);
})
)
.subscribe(
// Nothing to do here - rxEpand do the magic
() => {},
(err) => reject(err)
);
})
}
import { Observable } from 'rxjs';
export function makeRequest$(url: string, options?: any): Observable<any> {
return Observable.create((observer) => {
fetch(url, options)
.then((response) => response.json())
.then((response) => {
observer.next(response);
observer.complete();
})
.catch((error) => {
observer.error(error);
});
});
}
/**
* Generator formula:
* (Math.round(delay * incrementRatio)) + baseIncrement
*
* @param baseValue first returned value
* @param baseIncrement constant inremental value
* @param incrementRatio multiplier value
*
* @example
*
* retryGenerator(1000, 1000, 2) returns:
* 1. 1000
* 2. (1000*2 + 1000) = 3000
* 3. (3000*2 + 1000) = 7000
* 4. (7000*2 + 1000) = 15000
*
* retryGenerator(15000, 0, 1) returns:
* 1. 15000
* 2. (15000*1 + 0) = 15000
* 3. (15000*1 + 0) = 15000
* 4. (15000*1 + 0) = 15000
*/
export function *retryGenerator(baseValue = 1000, baseIncrement = 0, incrementRatio = 1): Generator {
let delay = baseValue;
while (true) {
yield delay;
delay = (Math.round(delay * incrementRatio)) + baseIncrement;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment