Skip to content

Commit beeee48

Browse files
committed
remove unused functions and introduce new helpers
1 parent 45ef2f0 commit beeee48

File tree

2 files changed

+107
-83
lines changed

2 files changed

+107
-83
lines changed

tests/functional/raw-node/utils/gcpUtils.js

Lines changed: 107 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,112 @@
11
const async = require('async');
2-
const assert = require('assert');
2+
const { callbackify } = require('util');
33
const { v4: uuidv4 } = require('uuid');
4-
5-
const { makeGcpRequest } = require('./makeRequest');
4+
const { HeadBucketCommand } = require('@aws-sdk/client-s3');
65

76
const genUniqID = () => uuidv4().replace(/-/g, '');
87

9-
function gcpRequestRetry(params, retry, callback) {
10-
const maxRetries = 4;
11-
const timeout = Math.pow(2, retry) * 1000;
12-
return setTimeout(makeGcpRequest, timeout, params, (err, res) => {
13-
if (err) {
14-
if (retry <= maxRetries && err.statusCode === 429) {
15-
return gcpRequestRetry(params, retry + 1, callback);
8+
const defaultShouldRetry = err =>
9+
err && (err.name === 'SlowDown' || err.$metadata?.httpStatusCode === 429);
10+
11+
async function gcpRetryCall(callFn, retryOptions) {
12+
const {
13+
maxAttempts = 3,
14+
shouldRetry = defaultShouldRetry,
15+
getDelayMs = attempt => Math.pow(2, attempt) * 1000,
16+
} = retryOptions || {};
17+
18+
let lastError;
19+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
20+
try {
21+
22+
return await callFn();
23+
} catch (err) {
24+
lastError = err;
25+
if (!shouldRetry(err, attempt) || attempt === maxAttempts - 1) {
26+
throw err;
1627
}
17-
return callback(err);
28+
const delay = getDelayMs(attempt);
29+
process.stdout.write(
30+
'Retryable error from GCP, retrying in ' +
31+
`${delay}ms (attempt ${attempt + 1}): ${err}\n`);
32+
33+
await new Promise(resolve => setTimeout(resolve, delay));
1834
}
19-
return callback(null, res);
20-
});
35+
}
36+
37+
throw lastError;
2138
}
2239

23-
function gcpClientRetry(fn, params, callback, retry = 0) {
24-
const maxRetries = 4;
25-
const timeout = Math.pow(2, retry) * 1000;
26-
return setTimeout(fn, timeout, params, (err, res) => {
27-
if (err) {
28-
if (retry <= maxRetries && err.statusCode === 429) {
29-
return gcpClientRetry(fn, params, callback, retry + 1);
40+
async function gcpRetry(gcpClient, command, retryOptions, cb) {
41+
if (cb) {
42+
return callbackify(() => gcpRetry(gcpClient, command,
43+
retryOptions))(cb);
44+
}
45+
46+
return gcpRetryCall(() => gcpClient.send(command), retryOptions);
47+
}
48+
49+
const defaultShouldRetryUpload = err => err && (
50+
err.name === 'NoSuchBucket'
51+
|| err.name === 'NotFound'
52+
|| err.$metadata?.httpStatusCode === 404
53+
|| err.name === 'SlowDown'
54+
|| err.$metadata?.httpStatusCode === 429
55+
|| (typeof err.message === 'string'
56+
&& (err.message.includes('NoSuchBucket')
57+
|| err.message.includes('unable to complete upload')))
58+
);
59+
60+
const defaultShouldRetryMpuCreate = err => err && (
61+
err.name === 'NoSuchBucket'
62+
|| err.name === 'NotFound'
63+
|| err.$metadata?.httpStatusCode === 404
64+
|| err.name === 'SlowDown'
65+
|| err.$metadata?.httpStatusCode === 429
66+
);
67+
68+
async function gcpUploadWithRetry(gcpClient, params, retryOptions) {
69+
const callFn = () => new Promise((resolve, reject) => {
70+
gcpClient.upload(params, (err, data) => {
71+
if (err) {
72+
return reject(err);
3073
}
31-
return callback(err);
32-
}
33-
return callback(null, res);
74+
return resolve(data);
75+
});
76+
});
77+
78+
return gcpRetryCall(callFn, {
79+
maxAttempts: 6,
80+
shouldRetry: defaultShouldRetryUpload,
81+
getDelayMs: attempt => (attempt + 1) * 1000,
82+
...retryOptions,
83+
});
84+
}
85+
86+
async function gcpCreateMultipartUploadWithRetry(gcpClient, params, retryOptions) {
87+
const callFn = () => new Promise((resolve, reject) => {
88+
gcpClient.createMultipartUpload(params,
89+
(err, res) => (err ? reject(err) : resolve(res)));
90+
});
91+
return gcpRetryCall(callFn, {
92+
maxAttempts: 6,
93+
shouldRetry: defaultShouldRetryMpuCreate,
94+
getDelayMs: attempt => (attempt + 1) * 1000,
95+
...retryOptions,
3496
});
3597
}
3698

3799
// mpu test helpers
38100
function gcpMpuSetup(params, callback) {
39101
const { gcpClient, bucketNames, key, partCount, partSize } = params;
102+
40103
return async.waterfall([
41-
next => gcpClient.createMultipartUpload({
42-
Bucket: bucketNames.mpu.Name,
43-
Key: key,
44-
}, (err, res) => {
45-
assert.equal(err, null,
46-
`Expected success, but got error ${err}`);
47-
return next(null, res.UploadId);
48-
}),
104+
next => gcpCreateMultipartUploadWithRetry(gcpClient, {
105+
Bucket: bucketNames.mpu.Name,
106+
Key: key,
107+
})
108+
.then(res => next(null, res.UploadId))
109+
.catch(err => next(err)),
49110
(uploadId, next) => {
50111
if (partCount <= 0) {
51112
return next('SkipPutPart', { uploadId });
@@ -141,13 +202,26 @@ function setBucketClass(storageClass) {
141202
'</CreateBucketConfiguration>';
142203
}
143204

205+
async function waitForBucketReady(gcpClient, bucketName, retryOptions) {
206+
const cmd = new HeadBucketCommand({ Bucket: bucketName });
207+
return await gcpRetry(gcpClient, cmd, {
208+
maxAttempts: 6,
209+
shouldRetry: defaultShouldRetryMpuCreate,
210+
getDelayMs: attempt => (attempt + 1) * 1000,
211+
...retryOptions,
212+
});
213+
}
214+
144215
module.exports = {
145-
gcpRequestRetry,
146-
gcpClientRetry,
147216
setBucketClass,
148217
gcpMpuSetup,
149218
genPutTagObj,
150219
genGetTagObj,
151220
genDelTagObj,
152221
genUniqID,
222+
gcpRetryCall,
223+
gcpRetry,
224+
gcpCreateMultipartUploadWithRetry,
225+
gcpUploadWithRetry,
226+
waitForBucketReady,
153227
};

tests/functional/raw-node/utils/makeRequest.js

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -185,55 +185,6 @@ function makeS3Request(params, callback) {
185185
makeRequest(options, callback);
186186
}
187187

188-
/** makeGcpRequest - utility function to generate a request against GCP
189-
* @param {object} params - params for making request
190-
* @param {string} params.method - request method
191-
* @param {object} [params.queryObj] - query fields and their string values
192-
* @param {object} [params.headers] - headers and their string values
193-
* @param {string} [params.bucket] - bucket name
194-
* @param {string} [params.objectKey] - object key name
195-
* @param {object} [params.authCredentials] - authentication credentials
196-
* @param {object} params.authCredentials.accessKey - access key
197-
* @param {object} params.authCredentials.secretKey - secret key
198-
* @param {string} [params.region] - request body contents
199-
* @param {function} callback - with error and response parameters
200-
* @return {undefined} - and call callback
201-
*/
202-
async function makeGcpRequest(params, callback) {
203-
const { method, queryObj, headers, bucket, objectKey, authCredentials,
204-
requestBody, region } = params;
205-
206-
let resolvedCredentials = authCredentials;
207-
if (authCredentials && typeof authCredentials === 'function') {
208-
try {
209-
resolvedCredentials = await authCredentials();
210-
resolvedCredentials = {
211-
accessKey: resolvedCredentials.accessKeyId,
212-
secretKey: resolvedCredentials.secretAccessKey,
213-
};
214-
} catch (err) {
215-
return callback(err);
216-
}
217-
}
218-
219-
const options = {
220-
authCredentials: resolvedCredentials,
221-
requestBody,
222-
hostname: 'storage.googleapis.com',
223-
port: 80,
224-
method,
225-
queryObj,
226-
headers: headers || {},
227-
path: bucket ? `/${bucket}/` : '/',
228-
GCP: true,
229-
region,
230-
};
231-
if (objectKey) {
232-
options.path = `${options.path}${objectKey}`;
233-
}
234-
return makeRequest(options, callback);
235-
}
236-
237188
/** makeBackbeatRequest - utility function to generate a request going
238189
* through backbeat route
239190
* @param {object} params - params for making request
@@ -270,6 +221,5 @@ function makeBackbeatRequest(params, callback) {
270221
module.exports = {
271222
makeRequest,
272223
makeS3Request,
273-
makeGcpRequest,
274224
makeBackbeatRequest,
275225
};

0 commit comments

Comments
 (0)