1 | 'use strict'
|
2 |
|
3 | const cli = require('heroku-cli-util')
|
4 | const path = require('path')
|
5 | const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
|
6 |
|
7 | async function run (context, heroku) {
|
8 | const debug = require('debug')('heroku-pg')
|
9 | const fetcher = require('../lib/fetcher')(heroku)
|
10 | const host = require('../lib/host')
|
11 | const app = context.app
|
12 | const db = context.args.database
|
13 | const notify = require('../lib/notify')(context)
|
14 |
|
15 | let waitFor = async function waitFor (db) {
|
16 | let interval = parseInt(context.flags['wait-interval'])
|
17 | if (!interval || interval < 0) interval = 5
|
18 |
|
19 | let status
|
20 | let waiting = false
|
21 | let name = 'db'
|
22 | let retries = 20
|
23 |
|
24 | while (true) {
|
25 | try {
|
26 | status = await heroku.request({
|
27 | host: host(db),
|
28 | path: `/client/v11/databases/${db.id}/wait_status`
|
29 | })
|
30 | } catch (err) {
|
31 | debug(err)
|
32 | if (!retries || err.statusCode !== 404) throw err
|
33 | retries--
|
34 | status = { 'waiting?': true }
|
35 | }
|
36 |
|
37 | if (status['error?']) {
|
38 | notify({
|
39 | sound: true,
|
40 | subtitle: 'error',
|
41 | message: `${name} ${status['message']}`,
|
42 | contentImage: path.join(__dirname, '../assets/error.png')
|
43 | })
|
44 | cli.error(status['message'])
|
45 | cli.exit(1)
|
46 | }
|
47 |
|
48 | if (!status['waiting?']) {
|
49 | if (waiting) {
|
50 | notify({
|
51 | sound: true,
|
52 | message: `${name} is ${status['message']}`,
|
53 | contentImage: path.join(__dirname, '../assets/success.png')
|
54 | })
|
55 | cli.action.done(status.message)
|
56 | }
|
57 | return
|
58 | }
|
59 |
|
60 | if (!waiting) {
|
61 | waiting = true
|
62 | name = db.name
|
63 | cli.action.start(`Waiting for database ${cli.color.addon(db.name)}`)
|
64 | }
|
65 |
|
66 | cli.action.status(status.message)
|
67 |
|
68 | await wait(interval * 1000)
|
69 | }
|
70 | }
|
71 |
|
72 | let dbs = []
|
73 | if (db) {
|
74 | dbs = [ await fetcher.addon(app, db) ]
|
75 | } else {
|
76 | dbs = await fetcher.all(app)
|
77 | }
|
78 |
|
79 | for (let db of dbs) await waitFor(db)
|
80 | }
|
81 |
|
82 | module.exports = {
|
83 | topic: 'pg',
|
84 | command: 'wait',
|
85 | description: 'blocks until database is available',
|
86 | needsApp: true,
|
87 | needsAuth: true,
|
88 | args: [{ name: 'database', optional: true }],
|
89 | flags: [
|
90 | { name: 'wait-interval', description: 'how frequently to poll in seconds (to avoid rate limiting)', hasValue: true },
|
91 | { name: 'no-notify', description: 'do not show OS notification' }
|
92 | ],
|
93 | run: cli.command({ preauth: true }, run)
|
94 | }
|