Skip to content

Commit 9c8b77c

Browse files
YermanacoCodex-
authored andcommitted
make WORKFLOW_JOB_STEPS_RETRY_MS as an action input parameter and linear backoff strategy for retries
1 parent 1482f37 commit 9c8b77c

File tree

11 files changed

+65
-21
lines changed

11 files changed

+65
-21
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ 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: 10 # Default: 5
2829
distinct_id: someDistinctId # Optional
2930

3031
- name: Use the output run ID and URL

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ 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: Duration to wait between retries while monitoring for the workflow run to start.
35+
default: 5
3336
distinct_id:
3437
description: Specify a static string to use instead of a random distinct ID.
3538

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);

src/return-dispatch.spec.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ describe("return-dispatch", () => {
480480
distinctIdRegex: distinctIdRegex,
481481
workflowId: workflowId,
482482
workflowTimeoutMs: 100,
483+
workflowJobStepsRetryMs: 5,
483484
};
484485

485486
let apiFetchWorkflowRunIdsMock: MockInstance<
@@ -662,13 +663,14 @@ describe("return-dispatch", () => {
662663
.mockResolvedValueOnce({ success: true, value: [] });
663664
apiFetchWorkflowRunJobStepsMock.mockResolvedValue([distinctId]);
664665
apiFetchWorkflowRunUrlMock.mockResolvedValue(runUrl);
665-
vi.spyOn(constants, "WORKFLOW_JOB_STEPS_RETRY_MS", "get").mockReturnValue(
666-
5000,
667-
);
668666

667+
const retryMs = 5000;
668+
const timeoutMs = 60 * 60 * 100;
669+
669670
const getRunIdAndUrlPromise = getRunIdAndUrl({
670671
...defaultOpts,
671-
workflowTimeoutMs: 60 * 60 * 1000,
672+
workflowTimeoutMs: timeoutMs,
673+
workflowJobStepsRetryMs: retryMs,
672674
});
673675

674676
// First attempt
@@ -681,10 +683,10 @@ describe("return-dispatch", () => {
681683
expect(coreInfoLogMock.mock.calls[0]?.[0]).toMatchSnapshot();
682684

683685
expect(utilSleepMock).toHaveBeenCalledOnce();
684-
expect(utilSleepMock).toHaveBeenCalledWith(5000);
686+
expect(utilSleepMock).toHaveBeenCalledWith(retryMs);
685687

686688
resetLogMocks();
687-
await vi.advanceTimersByTimeAsync(5000);
689+
await vi.advanceTimersByTimeAsync(retryMs);
688690

689691
// Second attempt
690692
expect(apiRetryOrTimeoutMock).toHaveBeenCalledTimes(2);
@@ -695,10 +697,10 @@ describe("return-dispatch", () => {
695697
expect(coreInfoLogMock.mock.calls[0]?.[0]).toMatchSnapshot();
696698

697699
expect(utilSleepMock).toHaveBeenCalledTimes(2);
698-
expect(utilSleepMock).toHaveBeenCalledWith(5000);
700+
expect(utilSleepMock).toHaveBeenCalledWith(retryMs * 2);
699701

700702
resetLogMocks();
701-
await vi.advanceTimersByTimeAsync(5000);
703+
await vi.advanceTimersByTimeAsync(retryMs * 2);
702704

703705
// Third attempt
704706
expect(apiRetryOrTimeoutMock).toHaveBeenCalledTimes(3);
@@ -771,13 +773,14 @@ describe("return-dispatch", () => {
771773
});
772774
apiFetchWorkflowRunJobStepsMock.mockResolvedValue([]);
773775
apiFetchWorkflowRunUrlMock.mockResolvedValue(runUrl);
774-
vi.spyOn(constants, "WORKFLOW_JOB_STEPS_RETRY_MS", "get").mockReturnValue(
775-
5000,
776-
);
776+
777+
const retryMs = 3000;
778+
const timeoutMs = 15 * 1000;
777779

778780
const getRunIdAndUrlPromise = getRunIdAndUrl({
779781
...defaultOpts,
780-
workflowTimeoutMs: 15 * 1000,
782+
workflowTimeoutMs: timeoutMs,
783+
workflowJobStepsRetryMs: retryMs,
781784
});
782785

783786
// First attempt
@@ -793,10 +796,10 @@ describe("return-dispatch", () => {
793796
expect(coreDebugLogMock.mock.calls[0]?.[0]).toMatchSnapshot();
794797

795798
expect(utilSleepMock).toHaveBeenCalledOnce();
796-
expect(utilSleepMock).toHaveBeenCalledWith(5000);
799+
expect(utilSleepMock).toHaveBeenCalledWith(retryMs);
797800

798801
resetLogMocks();
799-
await vi.advanceTimersByTimeAsync(5000);
802+
await vi.advanceTimersByTimeAsync(retryMs);
800803

801804
// Second attempt
802805
expect(apiRetryOrTimeoutMock).toHaveBeenCalledTimes(2);
@@ -810,10 +813,10 @@ describe("return-dispatch", () => {
810813
expect(coreDebugLogMock.mock.calls[0]?.[0]).toMatchSnapshot();
811814

812815
expect(utilSleepMock).toHaveBeenCalledTimes(2);
813-
expect(utilSleepMock).toHaveBeenCalledWith(5000);
816+
expect(utilSleepMock).toHaveBeenCalledWith(retryMs * 2);
814817

815818
resetLogMocks();
816-
await vi.advanceTimersByTimeAsync(5000);
819+
await vi.advanceTimersByTimeAsync(retryMs * 2);
817820

818821
// Timeout attempt
819822
expect(apiRetryOrTimeoutMock).toHaveBeenCalledTimes(3);
@@ -827,10 +830,10 @@ describe("return-dispatch", () => {
827830
expect(coreDebugLogMock.mock.calls[0]?.[0]).toMatchSnapshot();
828831

829832
expect(utilSleepMock).toHaveBeenCalledTimes(3);
830-
expect(utilSleepMock).toHaveBeenCalledWith(5000);
833+
expect(utilSleepMock).toHaveBeenCalledWith(retryMs * 3);
831834

832835
resetLogMocks();
833-
await vi.advanceTimersByTimeAsync(5000);
836+
await vi.advanceTimersByTimeAsync(retryMs * 3);
834837

835838
// Result
836839
const run = await getRunIdAndUrlPromise;

0 commit comments

Comments
 (0)