Execute request to AWS service * @param {Object|string} [service] - Description of the service to call * @prop [service.name] - Name of the service to call, support subclasses * @prop [service.params] - Parameters to apply when creating the service and doing the request * @prop [service.params.c
(service, method, ...args)
| 127 | * @param {Array} args - Argument for the method call |
| 128 | */ |
| 129 | async function awsRequest(service, method, ...args) { |
| 130 | // Checks regarding expectations on service object |
| 131 | if (isObject(service)) { |
| 132 | ensureString(service.name, { name: 'service.name' }) |
| 133 | } else { |
| 134 | ensureString(service, { name: 'service' }) |
| 135 | service = { name: service } |
| 136 | } |
| 137 | const BASE_BACKOFF = 5000 |
| 138 | const persistentRequest = async (f, numTry = 0) => { |
| 139 | try { |
| 140 | return await f() |
| 141 | } catch (e) { |
| 142 | const { providerError } = e |
| 143 | if ( |
| 144 | numTry < MAX_RETRIES && |
| 145 | providerError && |
| 146 | ((providerError.retryable && |
| 147 | providerError.statusCode !== 403 && |
| 148 | providerError.code !== 'CredentialsError' && |
| 149 | providerError.code !== 'ExpiredTokenException') || |
| 150 | providerError.statusCode === 429) |
| 151 | ) { |
| 152 | const nextTryNum = numTry + 1 |
| 153 | const jitter = Math.random() * 3000 - 1000 |
| 154 | // backoff is between 4 and 7 seconds |
| 155 | const backOff = BASE_BACKOFF + jitter |
| 156 | log.info( |
| 157 | [ |
| 158 | `Recoverable error occurred (${ |
| 159 | e.message |
| 160 | }), sleeping for ~${Math.round(backOff / 1000)} seconds.`, |
| 161 | `Try ${nextTryNum} of ${MAX_RETRIES}`, |
| 162 | ].join(' '), |
| 163 | ) |
| 164 | await wait(backOff) |
| 165 | return persistentRequest(f, nextTryNum) |
| 166 | } |
| 167 | throw e |
| 168 | } |
| 169 | } |
| 170 | const request = await requestQueue.add(() => |
| 171 | persistentRequest(async () => { |
| 172 | const requestId = ++requestCounter |
| 173 | const awsService = getServiceInstance(service, method) |
| 174 | awsLog.debug(`request: #${requestId} ${service.name}.${method}`, args) |
| 175 | const req = awsService[method](...args) |
| 176 | try { |
| 177 | const result = await req.promise() |
| 178 | awsLog.debug( |
| 179 | `request result: #${requestId} ${service.name}.${method}`, |
| 180 | result, |
| 181 | ) |
| 182 | return result |
| 183 | } catch (err) { |
| 184 | awsLog.debug( |
| 185 | `request error: #${requestId} - ${service.name}.${method}`, |
| 186 | err, |
nothing calls this directly
no test coverage detected