From 0e34daeb46cd113235ab534735a91b278d724b99 Mon Sep 17 00:00:00 2001 From: Will O'Beirne Date: Mon, 1 Mar 2021 21:58:04 -0600 Subject: [PATCH] Add healthcheckretries option --- README.md | 32 ++++++++++++++++++++++++++++++++ action.yml | 4 ++++ index.js | 30 +++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9bdc59c..1f24060 100644 --- a/README.md +++ b/README.md @@ -439,6 +439,38 @@ By default, the application will not be rolled back if the healthcheck fails. Thanks to [FridaTveit](https://github.com/FridaTveit) for adding this feature +### Retry healthcheck + +You can set the healthcheckretries option to re-run the healthcheck some number of times before considering it a failure. Retries will be delayed by delay each time, not just initially. + +_.github/workflows/main.yml_ + +```yaml +name: Deploy + +on: + push: + branches: + - master # Changing the branch here would also work + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: akhileshns/heroku-deploy@v3.12.12 # This is the action + with: + heroku_api_key: ${{secrets.HEROKU_API_KEY}} + heroku_app_name: "YOUR APP's NAME" #Must be unique in Heroku + heroku_email: "YOUR EMAIL" + healthcheck: "https://[YOUR APP's NAME].herokuapp.com/health" + healthcheckretries: 10 # Try 5 times before failing + healthcheckdelay: 30 # 30s delay, the last try (10th) will happen 5 minutes after the first + rollbackonhealthcheckfailed: true +``` + +By default healthcheck will only try once. + ## Environment Variables Heroku offers a means of passing sensitive information to your app (such as api keys etc) via something it calls **config vars** which you can find in the settings of your heroku app. But sometimes you might want to store sensitive information (api keys etc) in GitHub Secrets instead just to ensure platform independence. If you choose to this, you can then pass those secrets to your heroku app by using the "env" object of the action:- diff --git a/action.yml b/action.yml index a7c909e..8a3cff2 100644 --- a/action.yml +++ b/action.yml @@ -47,6 +47,10 @@ inputs: description: "A URL to which a healthcheck is performed (checks for 200 request)" required: false default: "" + healthcheckretries: + description: "Number of times to try the healthcheck" + required: false + default: "1" checkstring: description: "Value to check for when conducting healthcheck request" required: false diff --git a/index.js b/index.js index 2f5bee2..6367db1 100644 --- a/index.js +++ b/index.js @@ -141,6 +141,7 @@ let heroku = { dockerBuildArgs: core.getInput("docker_build_args"), appdir: core.getInput("appdir"), healthcheck: core.getInput("healthcheck"), + healthcheckretries: parseInt(core.getInput("healthcheckretries")), checkstring: core.getInput("checkstring"), delay: parseInt(core.getInput("delay")), procfile: core.getInput("procfile"), @@ -233,23 +234,38 @@ if (heroku.dockerBuildArgs) { } if (heroku.healthcheck) { - if (typeof heroku.delay === "number" && heroku.delay !== NaN) { - await sleep(heroku.delay * 1000); - } + const maxRetries = typeof heroku.healthcheckretries === "number" && heroku.healthcheckretries !== NaN ? + heroku.healthcheckretries : 1; + let err; + for (let tries = 0; tries < maxRetries; tries++) { + if (err) { + console.log(`Health check failed, trying again (${tries} of ${maxRetries})`); + } + + if (typeof heroku.delay === "number" && heroku.delay !== NaN) { + await sleep(heroku.delay * 1000); + } - try { const res = await p(heroku.healthcheck); if (res.statusCode !== 200) { - throw new Error( + err = new Error( "Status code of network request is not 200: Status code - " + res.statusCode ); + continue; } if (heroku.checkstring && heroku.checkstring !== res.body.toString()) { - throw new Error("Failed to match the checkstring"); + err = new Error("Failed to match the checkstring"); + continue; } + + // Success + err = undefined; console.log(res.body.toString()); - } catch (err) { + break; + } + + if (err) { console.log(err.message); healthcheckFailed(heroku); }