Skip to content

Commit 73e46aa

Browse files
YermanacoCodex-
andauthored
feat: New input parameter job fetch retries with a linear backoff strategy (#267)
* feat: make WORKFLOW_JOB_STEPS_RETRY_MS as an action input parameter and linear backoff strategy for retries --------- Co-authored-by: Alex Miller <codex.nz@gmail.com>
1 parent 1482f37 commit 73e46aa

File tree

12 files changed

+97
-31
lines changed

12 files changed

+97
-31
lines changed

.github/workflows/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
workflow: dispatch.yml
2727
workflow_inputs: '{"cake":"delicious"}'
2828
workflow_timeout_seconds: 30
29+
workflow_job_steps_retry_seconds: 10
2930
- name: Evaluate that the Run ID output has been set
3031
run: |
3132
if [ "${{ steps.return_dispatch.outputs.run_id }}" == "" ]; then

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ steps:
2525
workflow: automation-test.yml
2626
workflow_inputs: '{ "some_input": "value" }' # Optional
2727
workflow_timeout_seconds: 120 # Default: 300
28+
workflow_job_steps_retry_seconds:
29+
# Lineal backoff retry attempts are made where the attempt count is
30+
# the magnitude and the scaling value is `workflow_job_steps_retry_seconds`
31+
10 # Default: 5
2832
distinct_id: someDistinctId # Optional
2933

3034
- name: Use the output run ID and URL

action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ inputs:
3030
workflow_timeout_seconds:
3131
description: Time until giving up waiting for the start of the workflow run.
3232
default: 300
33+
workflow_job_steps_retry_seconds:
34+
description: |
35+
The interval (in seconds) to wait between retries. A linear backoff strategy is used, where the wait time
36+
increases by this value with each attempt (e.g., 1st retry = this value, 2nd retry = 2x this value, etc.).
37+
default: 5
3338
distinct_id:
3439
description: Specify a static string to use instead of a random distinct ID.
3540

src/__snapshots__/return-dispatch.spec.ts.snap

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,30 @@ exports[`return-dispatch > getRunIdAndUrl > should call retryOrTimeout with the
66

77
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 1`] = `"No Run IDs found for workflow, attempt 1..."`;
88

9-
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 2`] = `"No Run IDs found for workflow, attempt 2..."`;
9+
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 2`] = `"Waiting for 5000ms before the next attempt..."`;
1010

11-
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 3`] = `"Attempting to get step names for Run IDs: [0]"`;
11+
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 3`] = `"No Run IDs found for workflow, attempt 2..."`;
12+
13+
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 4`] = `"Waiting for 10000ms before the next attempt..."`;
14+
15+
exports[`return-dispatch > getRunIdAndUrl > should retry until an ID is found 5`] = `"Attempting to get step names for Run IDs: [0]"`;
1216

1317
exports[`return-dispatch > getRunIdAndUrl > should return the ID when found 1`] = `"Attempting to get step names for Run IDs: [0]"`;
1418

1519
exports[`return-dispatch > getRunIdAndUrl > should return the ID when found 2`] = `undefined`;
1620

1721
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 1`] = `"Exhausted searching IDs in known runs, attempt 1..."`;
1822

19-
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 2`] = `"Attempting to get step names for Run IDs: [0]"`;
23+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 2`] = `"Waiting for 3000ms before the next attempt..."`;
2024

21-
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 3`] = `"Exhausted searching IDs in known runs, attempt 2..."`;
25+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 3`] = `"Attempting to get step names for Run IDs: [0]"`;
2226

23-
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 4`] = `"Attempting to get step names for Run IDs: [0]"`;
27+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 4`] = `"Exhausted searching IDs in known runs, attempt 2..."`;
2428

25-
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 5`] = `"Exhausted searching IDs in known runs, attempt 3..."`;
29+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 5`] = `"Waiting for 6000ms before the next attempt..."`;
2630

2731
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 6`] = `"Attempting to get step names for Run IDs: [0]"`;
32+
33+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 7`] = `"Exhausted searching IDs in known runs, attempt 3..."`;
34+
35+
exports[`return-dispatch > getRunIdAndUrl > should timeout when unable to find over time 8`] = `"Attempting to get step names for Run IDs: [0]"`;

src/action.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe("Action", () => {
2828
workflow: "workflow_name",
2929
workflow_inputs: JSON.stringify(workflowInputs),
3030
workflow_timeout_seconds: "60",
31+
workflow_job_steps_retry_seconds: "3",
3132
distinct_id: "distinct_id",
3233
};
3334

@@ -48,6 +49,8 @@ describe("Action", () => {
4849
return mockEnvConfig.workflow_inputs;
4950
case "workflow_timeout_seconds":
5051
return mockEnvConfig.workflow_timeout_seconds;
52+
case "workflow_job_steps_retry_seconds":
53+
return mockEnvConfig.workflow_job_steps_retry_seconds;
5154
case "distinct_id":
5255
return mockEnvConfig.distinct_id;
5356
default:
@@ -72,6 +75,7 @@ describe("Action", () => {
7275
expect(config.workflow).toStrictEqual("workflow_name");
7376
expect(config.workflowInputs).toStrictEqual(workflowInputs);
7477
expect(config.workflowTimeoutSeconds).toStrictEqual(60);
78+
expect(config.workflowJobStepsRetrySeconds).toStrictEqual(3);
7579
expect(config.distinctId).toStrictEqual("distinct_id");
7680
});
7781

@@ -89,6 +93,13 @@ describe("Action", () => {
8993
expect(config.workflowTimeoutSeconds).toStrictEqual(300);
9094
});
9195

96+
it("should provide a default workflow job step retry if none is supplied", () => {
97+
mockEnvConfig.workflow_job_steps_retry_seconds = "";
98+
const config: ActionConfig = getConfig();
99+
100+
expect(config.workflowJobStepsRetrySeconds).toStrictEqual(5);
101+
});
102+
92103
it("should handle no inputs being provided", () => {
93104
mockEnvConfig.workflow_inputs = "";
94105
const config: ActionConfig = getConfig();

src/action.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { randomUUID } from "node:crypto";
33
import * as core from "@actions/core";
44

55
const WORKFLOW_TIMEOUT_SECONDS = 5 * 60;
6+
const WORKFLOW_JOB_STEPS_RETRY_SECONDS = 5;
67

78
/**
89
* action.yaml definition.
@@ -43,6 +44,11 @@ export interface ActionConfig {
4344
*/
4445
workflowTimeoutSeconds: number;
4546

47+
/**
48+
* Time in retries for identifying the Run ID.
49+
*/
50+
workflowJobStepsRetrySeconds: number;
51+
4652
/**
4753
* Specify a static ID to use instead of a distinct ID.
4854
*/
@@ -69,6 +75,9 @@ export function getConfig(): ActionConfig {
6975
workflowTimeoutSeconds:
7076
getNumberFromValue(core.getInput("workflow_timeout_seconds")) ??
7177
WORKFLOW_TIMEOUT_SECONDS,
78+
workflowJobStepsRetrySeconds:
79+
getNumberFromValue(core.getInput("workflow_job_steps_retry_seconds")) ??
80+
WORKFLOW_JOB_STEPS_RETRY_SECONDS,
7281
distinctId:
7382
getOptionalWorkflowValue(core.getInput("distinct_id")) ?? randomUUID(),
7483
};

src/api.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ describe("API", () => {
9595
return JSON.stringify({ testInput: "test" });
9696
case "workflow_timeout_seconds":
9797
return "30";
98+
case "workflow_job_steps_retry_seconds":
99+
return "5";
98100
default:
99101
return "";
100102
}
@@ -332,6 +334,7 @@ describe("API", () => {
332334
workflow: "workflow_name",
333335
workflowInputs: { testInput: "test" },
334336
workflowTimeoutSeconds: 60,
337+
workflowJobStepsRetrySeconds: 3,
335338
distinctId: "test-uuid",
336339
};
337340

src/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-inferrable-types */
22

33
export const WORKFLOW_FETCH_TIMEOUT_MS: number = 60 * 1000;
4-
export const WORKFLOW_JOB_STEPS_RETRY_MS: number = 5000;
54
export const WORKFLOW_JOB_STEPS_SERVER_ERROR_RETRY_MAX: number = 3;
65
export const WORKFLOW_JOB_STEPS_SERVER_ERROR_RETRY_MS: number = 500;

src/main.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ describe("main", () => {
3535
ref: "test-ref",
3636
workflow: "test-workflow",
3737
workflowTimeoutSeconds: 0,
38+
workflowJobStepsRetrySeconds: 0,
3839
} satisfies Partial<action.ActionConfig> as action.ActionConfig;
3940
const testBranch: utils.BranchNameResult = {
4041
branchName: "test-branch",
@@ -173,6 +174,7 @@ describe("main", () => {
173174
distinctIdRegex: distinctIdRegex,
174175
workflowId: 0,
175176
workflowTimeoutMs: testCfg.workflowTimeoutSeconds * 1000,
177+
workflowJobStepsRetryMs: testCfg.workflowJobStepsRetrySeconds * 1000,
176178
});
177179

178180
// Result

src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export async function main(): Promise<void> {
4444
distinctIdRegex,
4545
workflowId,
4646
workflowTimeoutMs: config.workflowTimeoutSeconds * 1000,
47+
workflowJobStepsRetryMs: config.workflowJobStepsRetrySeconds * 1000,
4748
});
4849
if (result.success) {
4950
handleActionSuccess(result.value.id, result.value.url);

0 commit comments

Comments
 (0)