heroku/heroku-pg

View on GitHub
commands/wait.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict'

const cli = require('heroku-cli-util')
const co = require('co')
const path = require('path')
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))

async function run (context, heroku) {
  const debug = require('debug')('heroku-pg')
  const fetcher = require('../lib/fetcher')(heroku)
  const host = require('../lib/host')
  const app = context.app
  const db = context.args.database
  const notify = require('../lib/notify')(context)

  let waitFor = async function waitFor (db) {
    let interval = parseInt(context.flags['wait-interval'])
    if (!interval || interval < 0) interval = 5

    let status
    let waiting = false
    let name = 'db'
    let retries = 20

    while (true) {
      try {
        status = await heroku.request({
          host: host(db),
          path: `/client/v11/databases/${db.id}/wait_status`
        })
      } catch (err) {
        debug(err)
        if (!retries || err.statusCode !== 404) throw err
        retries--
        status = {'waiting?': true}
      }

      if (status['error?']) {
        notify({
          sound: true,
          subtitle: 'error',
          message: `${name} ${status['message']}`,
          contentImage: path.join(__dirname, '../assets/error.png')
        })
        cli.error(status['message'])
        cli.exit(1)
      }

      if (!status['waiting?']) {
        if (waiting) {
          notify({
            sound: true,
            message: `${name} is ${status['message']}`,
            contentImage: path.join(__dirname, '../assets/success.png')
          })
          cli.action.done(status.message)
        }
        return
      }

      if (!waiting) {
        waiting = true
        name = db.name
        cli.action.start(`Waiting for database ${cli.color.addon(db.name)}`)
      }

      cli.action.status(status.message)

      await wait(interval * 1000)
    }
  }

  let dbs = []
  if (db) {
    dbs = [ await fetcher.addon(app, db) ]
  } else {
    dbs = await fetcher.all(app)
  }

  for (let db of dbs) await waitFor(db)
}

module.exports = {
  topic: 'pg',
  command: 'wait',
  description: 'blocks until database is available',
  needsApp: true,
  needsAuth: true,
  args: [{name: 'database', optional: true}],
  flags: [
    {name: 'wait-interval', description: 'how frequently to poll in seconds (to avoid rate limiting)', hasValue: true},
    {name: 'no-notify', description: 'do not show OS notification'}
  ],
  run: cli.command({preauth: true}, co.wrap(run))
}