Skip to content

Commit 5bceb2b

Browse files
Merge pull request #13 from github/upload_retry
Add retrying to the upload
2 parents 1cdde3e + 129ce28 commit 5bceb2b

File tree

2 files changed

+105
-39
lines changed

2 files changed

+105
-39
lines changed

lib/upload-lib.js

Lines changed: 48 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/upload-lib.ts

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,61 @@ export function combineSarifFiles(sarifFiles: string[]): string {
4747
return JSON.stringify(combinedSarif);
4848
}
4949

50+
// Upload the given payload.
51+
// If the request fails then this will retry a small number of times.
52+
async function uploadPayload(payload) {
53+
core.info('Uploading results');
54+
55+
const githubToken = core.getInput('token');
56+
const ph: auth.BearerCredentialHandler = new auth.BearerCredentialHandler(githubToken);
57+
const client = new http.HttpClient('Code Scanning : Upload SARIF', [ph]);
58+
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY'] + '/code-scanning/analysis';
59+
60+
// Make up to 4 attempts to upload, and sleep for these
61+
// number of seconds between each attempt.
62+
// We don't want to backoff too much to avoid wasting action
63+
// minutes, but just waiting a little bit could maybe help.
64+
const backoffPeriods = [1, 5, 15];
65+
66+
for (let attempt = 0; attempt <= backoffPeriods.length; attempt++) {
67+
68+
const res: http.HttpClientResponse = await client.put(url, payload);
69+
core.debug('response status: ' + res.message.statusCode);
70+
71+
const statusCode = res.message.statusCode;
72+
if (statusCode === 202) {
73+
core.info("Successfully uploaded results");
74+
return;
75+
}
76+
77+
const requestID = res.message.headers["x-github-request-id"];
78+
79+
// On any other status code that's not 5xx mark the upload as failed
80+
if (!statusCode || statusCode < 500 || statusCode >= 600) {
81+
core.setFailed('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
82+
return;
83+
}
84+
85+
// On a 5xx status code we may retry the request
86+
if (attempt < backoffPeriods.length) {
87+
// Log the failure as a warning but don't mark the action as failed yet
88+
core.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) +
89+
') failed (' + requestID + '). Retrying in ' + backoffPeriods[attempt] +
90+
' seconds: (' + statusCode + ') ' + await res.readBody());
91+
// Sleep for the backoff period
92+
await new Promise(r => setTimeout(r, backoffPeriods[attempt] * 1000));
93+
continue;
94+
95+
} else {
96+
// If the upload fails with 5xx then we assume it is a temporary problem
97+
// and not an error that the user has caused or can fix.
98+
// We avoid marking the job as failed to avoid breaking CI workflows.
99+
core.error('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
100+
return;
101+
}
102+
}
103+
}
104+
50105
// Uploads a single sarif file or a directory of sarif files
51106
// depending on what the path happens to refer to.
52107
export async function upload(input: string) {
@@ -112,25 +167,8 @@ async function uploadFiles(sarifFiles: string[]) {
112167
"tool_names": toolNames,
113168
});
114169

115-
core.info('Uploading results');
116-
const githubToken = core.getInput('token');
117-
const ph: auth.BearerCredentialHandler = new auth.BearerCredentialHandler(githubToken);
118-
const client = new http.HttpClient('Code Scanning : Upload SARIF', [ph]);
119-
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY'] + '/code-scanning/analysis';
120-
const res: http.HttpClientResponse = await client.put(url, payload);
121-
const requestID = res.message.headers["x-github-request-id"];
122-
123-
core.debug('response status: ' + res.message.statusCode);
124-
if (res.message.statusCode === 500) {
125-
// If the upload fails with 500 then we assume it is a temporary problem
126-
// with turbo-scan and not an error that the user has caused or can fix.
127-
// We avoid marking the job as failed to avoid breaking CI workflows.
128-
core.error('Upload failed (' + requestID + '): ' + await res.readBody());
129-
} else if (res.message.statusCode !== 202) {
130-
core.setFailed('Upload failed (' + requestID + '): ' + await res.readBody());
131-
} else {
132-
core.info("Successfully uploaded results");
133-
}
170+
// Make the upload
171+
await uploadPayload(payload);
134172

135173
// Mark that we have made an upload
136174
fs.writeFileSync(sentinelFile, '');

0 commit comments

Comments
 (0)