Skip to content

Commit f188bf3

Browse files
authored
Merge pull request #116 from vililahtevanoja/master
feat: Add configurable update rate
2 parents a695f21 + 160321e commit f188bf3

File tree

6 files changed

+199660
-122299
lines changed

6 files changed

+199660
-122299
lines changed

README.md

+25
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ The only required input is `project-name`.
4646
the one defined here replaces the one in the CodeBuild project.
4747
For a list of CodeBuild environment variables, see
4848

49+
1. **update-interval** (optional) :
50+
Update interval as seconds for how often the API is called to check on the status.
51+
52+
A higher value mitigates the chance of hitting API rate-limiting especially when
53+
running many instances of this action in parallel, but also introduces a larger
54+
potential time overhead (ranging from 0 to update interval) for the action to
55+
fetch the build result and finish.
56+
57+
Lower value limits the potential time overhead worst case but it may hit the API
58+
rate-limit more often, depending on the use-case.
59+
60+
The default value is 30.
61+
62+
1. **update-back-off** (optional) :
63+
Base back-off time in seconds for the update interval.
64+
65+
When API rate-limiting is hit the back-off time, augmented with jitter, will be
66+
added to the next update interval.
67+
E.g. with update interval of 30 and back-off time of 15, upon hitting the rate-limit
68+
the next interval for the update call will be 30 + random_between(0, 15 _ 2 \*\* 0))
69+
seconds and if the rate-limit is hit again the next interval will be
70+
30 + random_between(0, 15 _ 2 \*\* 1) and so on.
71+
72+
The default value is 15.
73+
4974
### Outputs
5075

5176
1. **aws-build-id** : The CodeBuild build ID of the build that the action ran.

action.yml

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ inputs:
2222
env-vars-for-codebuild:
2323
description: 'Comma separated list of environment variables to send to CodeBuild'
2424
required: false
25+
update-interval:
26+
description: 'How often the action calls the API for updates'
27+
required: false
28+
update-back-off:
29+
description: 'Base back-off time for the update calls for API if rate-limiting is encountered'
30+
required: false
31+
2532
outputs:
2633
aws-build-id:
2734
description: 'The AWS CodeBuild Build ID for this build.'

code-build.js

+43-16
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,37 @@ function runBuild() {
2020
// get a codeBuild instance from the SDK
2121
const sdk = buildSdk();
2222

23+
const inputs = githubInputs();
24+
25+
const config = (({ updateInterval, updateBackOff }) => ({
26+
updateInterval,
27+
updateBackOff,
28+
}))(inputs);
29+
2330
// Get input options for startBuild
24-
const params = inputs2Parameters(githubInputs());
31+
const params = inputs2Parameters(inputs);
2532

26-
return build(sdk, params);
33+
return build(sdk, params, config);
2734
}
2835

29-
async function build(sdk, params) {
36+
async function build(sdk, params, config) {
3037
// Start the build
3138
const start = await sdk.codeBuild.startBuild(params).promise();
3239

3340
// Wait for the build to "complete"
34-
return waitForBuildEndTime(sdk, start.build);
41+
return waitForBuildEndTime(sdk, start.build, config);
3542
}
3643

3744
async function waitForBuildEndTime(
3845
sdk,
3946
{ id, logs },
47+
{ updateInterval, updateBackOff },
4048
seqEmptyLogs,
4149
totalEvents,
4250
throttleCount,
4351
nextToken
4452
) {
45-
const {
46-
codeBuild,
47-
cloudWatchLogs,
48-
wait = 1000 * 30,
49-
backOff = 1000 * 15,
50-
} = sdk;
53+
const { codeBuild, cloudWatchLogs } = sdk;
5154

5255
totalEvents = totalEvents || 0;
5356
seqEmptyLogs = seqEmptyLogs || 0;
@@ -86,17 +89,21 @@ async function waitForBuildEndTime(
8689
if (errObject) {
8790
//We caught an error in trying to make the AWS api call, and are now checking to see if it was just a rate limiting error
8891
if (errObject.message && errObject.message.search("Rate exceeded") !== -1) {
89-
//We were rate-limited, so add `backOff` seconds to the wait time
90-
let newWait = wait + backOff;
92+
// We were rate-limited, so add backoff with Full Jitter, ref: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
93+
let jitteredBackOff = Math.floor(
94+
Math.random() * (updateBackOff * 2 ** throttleCount)
95+
);
96+
let newWait = updateInterval + jitteredBackOff;
9197
throttleCount++;
9298

9399
//Sleep before trying again
94100
await new Promise((resolve) => setTimeout(resolve, newWait));
95101

96102
// Try again from the same token position
97103
return waitForBuildEndTime(
98-
{ ...sdk, wait: newWait },
104+
{ ...sdk },
99105
{ id, logs },
106+
{ updateInterval: newWait, updateBackOff },
100107
seqEmptyLogs,
101108
totalEvents,
102109
throttleCount,
@@ -136,13 +143,19 @@ async function waitForBuildEndTime(
136143
// More to do: Sleep for a few seconds to avoid rate limiting
137144
// If never throttled and build is complete, halve CWL polling delay to minimize latency
138145
await new Promise((resolve) =>
139-
setTimeout(resolve, current.endTime && throttleCount == 0 ? wait / 2 : wait)
146+
setTimeout(
147+
resolve,
148+
current.endTime && throttleCount == 0
149+
? updateInterval / 2
150+
: updateInterval
151+
)
140152
);
141153

142154
// Try again
143155
return waitForBuildEndTime(
144156
sdk,
145157
current,
158+
{ updateInterval, updateBackOff },
146159
seqEmptyLogs,
147160
totalEvents,
148161
throttleCount,
@@ -173,8 +186,9 @@ function githubInputs() {
173186
core.getInput("compute-type-override", { required: false }) || undefined;
174187

175188
const environmentTypeOverride =
176-
core.getInput("environment-type-override", { required: false }) || undefined;
177-
const imageOverride =
189+
core.getInput("environment-type-override", { required: false }) ||
190+
undefined;
191+
const imageOverride =
178192
core.getInput("image-override", { required: false }) || undefined;
179193

180194
const envPassthrough = core
@@ -183,6 +197,17 @@ function githubInputs() {
183197
.map((i) => i.trim())
184198
.filter((i) => i !== "");
185199

200+
const updateInterval =
201+
parseInt(
202+
core.getInput("update-interval", { required: false }) || "30",
203+
10
204+
) * 1000;
205+
const updateBackOff =
206+
parseInt(
207+
core.getInput("update-back-off", { required: false }) || "15",
208+
10
209+
) * 1000;
210+
186211
return {
187212
projectName,
188213
owner,
@@ -193,6 +218,8 @@ function githubInputs() {
193218
environmentTypeOverride,
194219
imageOverride,
195220
envPassthrough,
221+
updateInterval,
222+
updateBackOff,
196223
};
197224
}
198225

0 commit comments

Comments
 (0)