Cancelling a build through the API from inside the build itself

Hello,

I currently have a GitHub bot (Renovate) configured on my repos to automatically update my dependencies to the latest released version. For each update, it creates a new commit on master, which in turn triggers a deploy. This consumes a lot of build minutes for changes that are irrelevant.

In an attempt to consume less minutes, I added some logic to my build script. It now checks if any relevant files/folder were changed since the last deploy and a few other checks. If no relevant changes were made, it cancels the build.

I couldn’t find a way to cleanly cancel the build through exit code. Returning 0 would mark the build as a success and deploy it, and returning 1 would mark it as failing; hiding real failures in the UI. I ended up using the cancelSiteDeploy method from the Netlify API client.

It works, and correctly marks the build as cancelled in the UI, but it also generates a warning inside the build itself:

2:35:54 PM: ** WARNING **
2:35:54 PM: There are some lingering processes even after the build process finished:
2:35:54 PM: USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2:35:54 PM: root        1632  0.0  0.0   4508   744 ?        Ss   12:35   0:00 /bin/sh -c rm -rf /opt/build
2:35:54 PM: root        1637 96.0  0.0  32180  2688 ?        R    12:35   0:00 rm -rf /opt/build
2:35:54 PM: Our builds do not kill your processes automatically, so please make sure
2:35:54 PM: that nothing is running after your build finishes, or it will be marked as
2:35:54 PM: failed since something is still running.
2:35:54 PM: 

Should I be worried about the message or can I ignore it? Is there a specific error code I could return to mark the build as cancelled instead of requesting the API?

You can see an example of such a build with the gamemaster-loot site name and deploy id 5efdd3f37cbeb700081da423

Full build log (click to expand)
2:32:51 PM: Waiting for other deploys from your team to complete
2:34:48 PM: Build ready to start
2:34:50 PM: build-image version: 9d79ad851d6eff3969322d6e5b1df3d597650c41
2:34:50 PM: build-image tag: v3.3.19
2:34:50 PM: buildbot version: 2cc7ea668a3e8f63326d15aab17e62cd1997fa2e
2:34:50 PM: Fetching cached dependencies
2:34:50 PM: Failed to fetch cache, continuing with build
2:34:50 PM: Starting to prepare the repo for build
2:34:51 PM: No cached dependencies found. Cloning fresh repo
2:34:51 PM: git clone https://github.com/pixelastic/loot
2:34:52 PM: Preparing Git Reference refs/heads/master
2:34:54 PM: Different publish path detected, going to use the one specified in the Netlify configuration file: 'dist' versus './dist/' in the Netlify UI
2:34:54 PM: Starting build script
2:34:54 PM: Installing dependencies
2:34:54 PM: Python version set to 2.7
2:34:54 PM: Attempting node version '12.12.0' from .nvmrc
2:34:55 PM: Downloading and installing node v12.12.0...
2:34:55 PM: Downloading https://nodejs.org/dist/v12.12.0/node-v12.12.0-linux-x64.tar.xz...
2:34:55 PM: Computing checksum with sha256sum
2:34:55 PM: Checksums matched!
2:34:58 PM: Now using node v12.12.0 (npm v6.11.3)
2:34:58 PM: Started restoring cached build plugins
2:34:58 PM: Finished restoring cached build plugins
2:34:58 PM: Attempting ruby version 2.6.2, read from environment
2:34:59 PM: Using ruby version 2.6.2
2:35:00 PM: Using PHP version 5.6
2:35:00 PM: 5.2 is already installed.
2:35:00 PM: Using Swift version 5.2
2:35:00 PM: Started restoring cached node modules
2:35:00 PM: Finished restoring cached node modules
2:35:00 PM: Started restoring cached yarn cache
2:35:00 PM: Finished restoring cached yarn cache
2:35:00 PM: Installing yarn at version 1.17.0
2:35:00 PM: Installing Yarn!
2:35:00 PM: > Downloading tarball...
2:35:00 PM: [1/2]: https://yarnpkg.com/downloads/1.17.0/yarn-v1.17.0.tar.gz --> /tmp/yarn.tar.gz.A9VTjUO8XF
2:35:00 PM:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
2:35:00 PM:                                  Dload  Upload   Total   Spent    Left  Speed
2:35:00 PM:   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
2:35:00 PM: 100    80  100    80    0     0    259      0 --:--:-- --:--:-- --:--:--   260
2:35:00 PM:   0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
2:35:00 PM: 100    93  100    93    0     0    158      0 --:--:-- --:--:-- --:--:--   688
2:35:01 PM: 100   630  100   630    0     0    734      0 --:--:-- --:--:-- --:--:--   734
2:35:01 PM: 100 1213k  100 1213k    0     0   917k      0  0:00:01  0:00:01 --:--:--  917k
2:35:01 PM: [2/2]: https://yarnpkg.com/downloads/1.17.0/yarn-v1.17.0.tar.gz.asc --> /tmp/yarn.tar.gz.A9VTjUO8XF.asc
2:35:01 PM: 100    84  100    84    0     0   2680      0 --:--:-- --:--:-- --:--:--  2680
2:35:01 PM: 100    97  100    97    0     0   1521      0 --:--:-- --:--:-- --:--:--  1521
2:35:01 PM: 100   634  100   634    0     0   6695      0 --:--:-- --:--:-- --:--:--  6695
2:35:01 PM:   0   832    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
2:35:01 PM: 100   832  100   832    0     0   2813      0 --:--:-- --:--:-- --:--:--  812k
2:35:01 PM: > Verifying integrity...
2:35:01 PM: gpg: Signature made Fri 14 Jun 2019 06:55:58 PM UTC using RSA key ID 69475BAA
2:35:01 PM: gpg: Good signature from "Yarn Packaging <yarn@dan.cx>"
2:35:01 PM: gpg: WARNING: This key is not certified with a trusted signature!
2:35:01 PM: gpg:          There is no indication that the signature belongs to the owner.
2:35:01 PM: Primary key fingerprint: 72EC F46A 56B4 AD39 C907  BBB7 1646 B01B 86E5 0310
2:35:01 PM:      Subkey fingerprint: 6D98 490C 6F1A CDDD 448E  4595 4F77 6793 6947 5BAA
2:35:01 PM: > GPG signature looks good
2:35:01 PM: > Extracting to ~/.yarn...
2:35:01 PM: > Adding to $PATH...
2:35:02 PM: > Successfully installed Yarn 1.17.0! Please open another terminal where the `yarn` command will now be available.
2:35:03 PM: Installing NPM modules using Yarn version 1.19.1
2:35:03 PM: yarn install v1.19.1
2:35:03 PM: [1/4] Resolving packages...
2:35:04 PM: [2/4] Fetching packages...
2:35:04 PM: warning Pattern ["colors@latest"] is trying to unpack in the same destination "/opt/build/.yarn_cache/v6/npm-colors-1.4.0-c50491479d4c1bdaed2c9ced32cf7c7dc2360f78-integrity/node_modules/colors" as pattern ["colors@^1.1.2","colors@^1.1.2","colors@^1.2.1"]. This could result in non-deterministic behavior, skipping.
2:35:04 PM: warning Pattern ["object-assign@latest"] is trying to unpack in the same destination "/opt/build/.yarn_cache/v6/npm-object-assign-4.1.1-2109adc7965887cfc05cbbd442cac8bfbb360863-integrity/node_modules/object-assign" as pattern ["object-assign@^4.1.1","object-assign@^4.1.1","object-assign@^4.1.1","object-assign@^4.1.1","object-assign@^4.1.1","object-assign@^4.1.1","object-assign@^4.0.1","object-assign@^4.1.0","object-assign@^4","object-assign@^4.0.1","object-assign@^4.1.0"]. This could result in non-deterministic behavior, skipping.
2:35:04 PM: warning Pattern ["send@latest"] is trying to unpack in the same destination "/opt/build/.yarn_cache/v6/npm-send-0.17.1-c1d8b059f7900f7466dd4938bdc44e11ddb376c8-integrity/node_modules/send" as pattern ["send@0.17.1","send@0.17.1"]. This could result in non-deterministic behavior, skipping.
2:35:29 PM: info fsevents@2.1.2: The platform "linux" is incompatible with this module.
2:35:29 PM: info "fsevents@2.1.2" is an optional dependency and failed compatibility check. Excluding it from installation.
2:35:29 PM: info fsevents@1.2.11: The platform "linux" is incompatible with this module.
2:35:29 PM: info "fsevents@1.2.11" is an optional dependency and failed compatibility check. Excluding it from installation.
2:35:29 PM: warning np@6.2.0: The engine "git" appears to be invalid.
2:35:29 PM: [3/4] Linking dependencies...
2:35:29 PM: warning "norska > norska-js > pug-loader@2.4.0" has unmet peer dependency "pug@^2.0.0".
2:35:29 PM: warning "aberlaas > eslint-plugin-jest > @typescript-eslint/experimental-utils > @typescript-eslint/typescript-estree > tsutils@3.17.1" has unmet peer dependency "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta".
2:35:40 PM: [4/4] Building fresh packages...
2:35:41 PM: Done in 37.70s.
2:35:41 PM: NPM modules installed using Yarn
2:35:41 PM: Started restoring cached go cache
2:35:41 PM: Finished restoring cached go cache
2:35:41 PM: Installing Go version 1.12
2:35:50 PM: unset GOOS;
2:35:50 PM: unset GOARCH;
2:35:50 PM: export GOROOT='/opt/buildhome/.gimme_cache/versions/go1.12.linux.amd64';
2:35:50 PM: export PATH="/opt/buildhome/.gimme_cache/versions/go1.12.linux.amd64/bin:${PATH}";
2:35:50 PM: go version >&2;
2:35:50 PM: export GIMME_ENV="/opt/buildhome/.gimme_cache/env/go1.12.linux.amd64.env"
2:35:50 PM: go version go1.12 linux/amd64
2:35:50 PM: Installing missing commands
2:35:50 PM: Verify run directory
2:35:51 PM: ​
2:35:51 PM: ┌─────────────────────────────┐
2:35:51 PM: │        Netlify Build        │
2:35:51 PM: └─────────────────────────────┘
2:35:51 PM: ​
2:35:51 PM: ❯ Version
2:35:51 PM:   @netlify/build 2.0.25
2:35:51 PM: ​
2:35:51 PM: ❯ Flags
2:35:51 PM:   deployId: 5efdd3f37cbeb700081da423
2:35:51 PM:   mode: buildbot
2:35:51 PM: ​
2:35:51 PM: ❯ Current directory
2:35:51 PM:   /opt/build/repo
2:35:51 PM: ​
2:35:51 PM: ❯ Config file
2:35:51 PM:   /opt/build/repo/netlify.toml
2:35:51 PM: ​
2:35:51 PM: ❯ Context
2:35:51 PM:   production
2:35:51 PM: ​
2:35:51 PM: ┌────────────────────────────────────┐
2:35:51 PM: │ 1. build.command from netlify.toml │
2:35:51 PM: └────────────────────────────────────┘
2:35:51 PM: ​
2:35:51 PM: $ yarn run build:prod
2:35:52 PM: yarn run v1.19.1
2:35:52 PM: $ ./scripts/build-prod
2:35:53 PM: • Starting building for production on Netlify. Should it continue?
2:35:53 PM: ✘ No important changes since 7febfafe8f114b60095f0039eecf1cde5afb6b26, stopping the build
2:35:53 PM: ✘ Cancelling deploy 5efdd3f37cbeb700081da423
2:35:53 PM: Canceling deploy
2:35:54 PM: Done in 2.02s.
2:35:54 PM: ​
2:35:54 PM: (build.command completed in 2.7s)
2:35:54 PM: ​
2:35:54 PM: ┌─────────────────────────────┐
2:35:54 PM: │   Netlify Build Complete    │
2:35:54 PM: └─────────────────────────────┘
2:35:54 PM: ​
2:35:54 PM: (Netlify Build completed in 2.7s)
2:35:54 PM: Caching artifacts
2:35:54 PM: Started saving node modules
2:35:54 PM: mv: cannot move '/opt/build/repo/node_modules' to '/opt/build/cache/node_modules': No such file or directory
2:35:54 PM: Finished saving node modules
2:35:54 PM: Started saving build plugins
2:35:54 PM: mv: cannot move '/opt/build/repo/.netlify/plugins' to '/opt/build/cache/.netlify/plugins': No such file or directory
2:35:54 PM: Finished saving build plugins
2:35:54 PM: Started saving yarn cache
2:35:54 PM: mv: cannot move '/opt/buildhome/.yarn_cache' to '/opt/build/cache/.yarn_cache': No such file or directory
2:35:54 PM: Finished saving yarn cache
2:35:54 PM: Started saving pip cache
2:35:54 PM: mv: cannot move '/opt/buildhome/.cache' to '/opt/build/cache/.cache': No such file or directory
2:35:54 PM: Finished saving pip cache
2:35:54 PM: Started saving emacs cask dependencies
2:35:54 PM: mv: cannot move '/opt/buildhome/.cask' to '/opt/build/cache/.cask': No such file or directory
2:35:54 PM: Finished saving emacs cask dependencies
2:35:54 PM: Started saving maven dependencies
2:35:54 PM: mv: cannot move '/opt/buildhome/.m2' to '/opt/build/cache/.m2': No such file or directory
2:35:54 PM: Finished saving maven dependencies
2:35:54 PM: Started saving boot dependencies
2:35:54 PM: mv: cannot move '/opt/buildhome/.boot' to '/opt/build/cache/.boot': No such file or directory
2:35:54 PM: Finished saving boot dependencies
2:35:54 PM: Started saving go dependencies
2:35:54 PM: mv: cannot move '/opt/buildhome/.gimme_cache' to '/opt/build/cache/.gimme_cache': No such file or directory
2:35:54 PM: Finished saving go dependencies
2:35:54 PM: mkdir: cannot create directory ‘/opt/build/cache/node_version’: No such file or directory
2:35:54 PM: mv: target '/opt/build/cache/node_version/' is not a directory
2:35:54 PM: 
2:35:54 PM: ** WARNING **
2:35:54 PM: There are some lingering processes even after the build process finished:
2:35:54 PM: USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2:35:54 PM: root        1632  0.0  0.0   4508   744 ?        Ss   12:35   0:00 /bin/sh -c rm -rf /opt/build
2:35:54 PM: root        1637 96.0  0.0  32180  2688 ?        R    12:35   0:00 rm -rf /opt/build
2:35:54 PM: Our builds do not kill your processes automatically, so please make sure
2:35:54 PM: that nothing is running after your build finishes, or it will be marked as
2:35:54 PM: failed since something is still running.
2:35:54 PM: 
2:35:54 PM: Build script success
2:35:54 PM: Failing build: Failed to build site
2:36:24 PM: Failed to inform the API about a failed build, please retry the build or contact support
2:36:24 PM: Finished processing build request in 1m34.433245248s

I know I could have used the ignore option of netlify.toml or a custom build plugin to cancel the build, but in my case it made more sense to run the test from inside the build command itself (because I had full access to the whole set of options passed to the build method).

Lots of different ways to tackle this! There’s no issue with what you’ve opted for; I’d be ignoring it.

However, I’d personally be looking for ways to stop the build from triggering altogether. Despite the fact that this build was cancelled via graceful failure, it still ran so it’ll still nibble at minutes!

Could you pass the [skip ci] or [skip netlify] commit message through Renovate, in order to not trigger the build at all?

Thanks for the reply.

I could pass [skip ci] to renovate messages, but this was just an example. In my real-life scenario some renovate updates should trigger a deploy, other shouldn’t (updates to devDependencies for example shouldn’t, but updates to dependencies should).

I also want to check my own commits, not only Renovate’s, to see if a deploy should trigger. For example, if I change source files it should build and deploy, but if I only update tests or a README file, it shouldn’t.

The point is that I wanted to have a custom shouldBuild() method with specific tests that make sense for my use case, and based on the return value cancel the build.

Thanks for pointing out that it would still eat minutes, though. I was under the assumption that most of the time spent on a build was either pre-build (downloading dependencies) or post-build (deploying assets). My actual site build time is rarely above 15s, but my overall deploy time is usually between 1 and 2 minutes. I was hoping to cut on the post-build time by cancelling them early.

If I were to use ignore or a build plugin to cancel the build, would it consume 0 minutes?

Thanks for the answers

Hey @pixelastic,

I understand. Asking around, we’re pretty confident that the quickest means to cancel a build (and incur the smallest amount of minutes) would be using the ignore flag within your netlify.toml. There’s a blog post to accompany it too.

I’ll leave you a link to the pricing FAQ which does a good job as serving as reference to what a build minute actually constitutes. It’s nice to have the clarification! :slight_smile: