Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stop-on-signals and auto-cancellation #149

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ The only required input is `project-name`.
1. **disable-github-env-vars** (optional) :
Set to `true` if you want do disable github environment variables in codebuild.

1. **stop-on-signals** (optional) :
Copy link
Contributor

@taoyong-ty taoyong-ty Jan 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to test this PR but I couldn't cancel the workflow and the build .

my workflow: https://github.com/taoyong-ty/aws-codebuild-run-build/actions/runs/7731467637/workflow

name: Run CodeBuild Action

on: push

jobs:
  codebuild-job:
    runs-on: ubuntu-latest
    name: CodeBuild Job
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-west-2
      - name: Run CodeBuild
        id: codebuild
        if: always()
        uses: freckle/aws-codebuild-run-build@0881951f31dfd749aea98e4dcb1bcc7d8f9dbc05
        with:
          project-name: aws-codebuild-run-build
          buildspec-override:   |
            version: 0.2
            phases:
              build:
                commands:
                  - sleep 300
          hide-cloudwatch-logs: false
          artifacts-type-override: NO_ARTIFACTS

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you say a little more about "couldn't cancel the workflow and the build"? The logs seem to have expired for that example. If you do it again, I can take a look.

This has been working well for us since I opened this PR. Here is a recent example,

GitHub cancels the build (it was a fail-fast matrix Job where another Job failed):

You can see the Build did indeed go into Stopped at exactly that time:

And the end of the logs on the CodeBuild side, showing the same:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't now why you have if: always() there, can you try removing it? always() is an anti-pattern anyway because it includes the cancelled status too, which feels important here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right.

What I saw earlier was that the CodeBuild build was still running, even though the GitHub has acknowledged the cancelling request.

But I am now able to see the expected behavior after removin if: always()!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the change!

I am ready to approve and merge the change. Could you rebase your commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, done.

Comma-separated list of signals that will cause any started builds to be
stopped. The default value is `SIGINT`, which is what GitHub sends processes
when a workflow is cancelled. This means you can use concurrency settings or
other GitHub features that cause workflow cancellations without leaving
orphan builds running. Set to an empty string to disable.

### Outputs

1. **aws-build-id** : The CodeBuild build ID of the build that the action ran.
Expand Down
4 changes: 4 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ inputs:
artifacts-type-override:
description: 'The type of build output artifact'
required: false
stop-on-signals:
description: 'Comma separated list of process signals on which to stop the build. Default is SIGINT.'
required: false
default: 'SIGINT'
outputs:
aws-build-id:
description: 'The AWS CodeBuild Build ID for this build.'
Expand Down
32 changes: 31 additions & 1 deletion code-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@ function runBuild() {

const inputs = githubInputs();

const config = (({ updateInterval, updateBackOff, hideCloudWatchLogs }) => ({
const config = (({
updateInterval,
updateBackOff,
hideCloudWatchLogs,
stopOnSignals,
}) => ({
updateInterval,
updateBackOff,
hideCloudWatchLogs,
stopOnSignals,
}))(inputs);

// Get input options for startBuild
Expand All @@ -39,10 +45,27 @@ async function build(sdk, params, config) {
// Start the build
const start = await sdk.codeBuild.startBuild(params);

// Set up signal handling to stop the build on cancellation
setupSignalHandlers(sdk, start.build.id, config.stopOnSignals);

// Wait for the build to "complete"
return waitForBuildEndTime(sdk, start.build, config);
}

function setupSignalHandlers(sdk, id, signals) {
signals.forEach((s) => {
core.info(`Installing signal handler for ${s}`);
process.on(s, async () => {
try {
core.info(`Caught ${s}, attempting to stop build...`);
await sdk.codeBuild.stopBuild({ id }).promise();
} catch (ex) {
core.error(`Error stopping build: ${ex}`);
}
});
});
}

async function waitForBuildEndTime(
sdk,
{ id, logs },
Expand Down Expand Up @@ -226,6 +249,12 @@ function githubInputs() {
const artifactsTypeOverride =
core.getInput("artifacts-type-override", { required: false }) || undefined;

const stopOnSignals = core
.getInput("stop-on-signals", { required: false })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to set the default value SIGINT here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because of the default in action.yaml: https://github.com/aws-actions/aws-codebuild-run-build/pull/149/files#diff-1243c5424efaaa19bd8e813c5e6f6da46316e63761421b3e5f5c8ced9a36e6b6R46. And it must be this way (vs leaving it required: false in action.yml and doing that defaulting here).

My understanding (correct me if I'm wrong) is:

Putting the default in action.yml means the action is always technically invoked with a value, either the one given by the user or that default. From the perspective of the code here, it will always receive a value.

Confusingly, { required: false } is needed for .getInput to not blow up on signals: '', which is a valid choice the user can make to say "don't do signal handling". Since inputs are always string-typed, getInput would see '' as missing and error if we did { required: true }.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. I asked this question because of the issue I reported in the other comment.

.split(",")
.map((i) => i.trim())
.filter((i) => i !== "");

return {
projectName,
owner,
Expand All @@ -243,6 +272,7 @@ function githubInputs() {
hideCloudWatchLogs,
disableGithubEnvVars,
artifactsTypeOverride,
stopOnSignals,
};
}

Expand Down
Loading
Loading