diff --git a/lib/routes/routeBackbeat.js b/lib/routes/routeBackbeat.js index 34a75cb5ff..15e53b10c9 100644 --- a/lib/routes/routeBackbeat.js +++ b/lib/routes/routeBackbeat.js @@ -1372,6 +1372,10 @@ function routeBackbeat(clientIP, request, response, log) { _normalizeBackbeatRequest(request); const requestContexts = prepareRequestContexts('objectReplicate', request); + // Ensure backbeat operations like expiration can properly use quotas + // eslint-disable-next-line no-param-reassign + request.finalizerHooks = []; + // proxy api requests to Backbeat API server if (request.resourceType === 'api') { if (!config.backbeat) { @@ -1518,16 +1522,24 @@ function routeBackbeat(clientIP, request, response, log) { return backbeatRoutes[request.method][request.resourceType] [request.query.operation](request, response, log, next); }], - err => { - if (err) { - return responseJSONBody(err, null, response, log); - } - log.debug('backbeat route response sent successfully', - { method: request.method, - bucketName: request.bucketName, - objectKey: request.objectKey }); - return undefined; - }); + err => async.forEachLimit( + // Finalizer hooks are used in a quota context and ensure consistent + // metrics in case of API errors. No operation required if the API + // completed successfully. + request.finalizerHooks, + 5, + (hook, done) => hook(err, done), + () => { + if (err) { + return responseJSONBody(err, null, response, log); + } + log.debug('backbeat route response sent successfully', + { method: request.method, + bucketName: request.bucketName, + objectKey: request.objectKey }); + return undefined; + }, + )); }