Skip to content

Instantly share code, notes, and snippets.

@bajtos
Last active August 8, 2020 20:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bajtos/2379d7c6df31e477aaa3a3f6ea87886c to your computer and use it in GitHub Desktop.
Save bajtos/2379d7c6df31e477aaa3a3f6ea87886c to your computer and use it in GitHub Desktop.
How to intercept LoopBack connector's execute method to implement retry mechanism
@lifeCycleObserver('datasource')
export class DbDataSource extends juggler.DataSource
implements LifeCycleObserver {
static dataSourceName = 'db';
static readonly defaultConfig = config;
constructor(
@inject('datasources.config.db', {optional: true})
dsConfig: object = config,
) {
super(dsConfig);
const connector = this.connector!;
// Save the original `execute` implementation
connector._originalExecute = connector.execute;
// Inject our custom version
connector.execute = function (...params: unknown[]) {
// IMPORTANT: connectors are still callback-based
// Unfortunately, LB4 type definitions are incorrect here.
const callback = params.pop() as Function;
console.log('executing', ...params);
connector._originalExecute(
// forward the arguments provided by the caller
...params,
// but use our own callback to intercept the outcome
(err: unknown, ...results: unknown[]) => {
console.log('result', err, ...results);
if (!err) {
// all is good, operation was a success
callback(err, ...results);
return;
}
// modify the condition to match your retry criteria
const shouldRetry = (err as any).statusCode === 429;
if (!shouldRetry) {
// unknown error, report it back to the caller
callback(err, ...results);
return;
}
// retry the request after 50ms
setTimeout(
() => void connector.execute!(...params, callback),
50,
);
},
);
} as any;
// ^^^ the cast is a hack to work around incorrect typings in LB4
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment