{"id":29143865,"url":"https://github.com/nickjj/wait-until","last_synced_at":"2025-06-30T20:39:38.169Z","repository":{"id":56528281,"uuid":"266351384","full_name":"nickjj/wait-until","owner":"nickjj","description":"A zero dependency Bash script that waits until a command of your choosing has run successfully.","archived":false,"fork":false,"pushed_at":"2024-12-07T18:38:40.000Z","size":34,"stargazers_count":64,"open_issues_count":0,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-22T01:47:53.103Z","etag":null,"topics":["bash","docker","docker-compose","wait"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nickjj.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-23T14:19:18.000Z","updated_at":"2025-06-07T22:21:59.000Z","dependencies_parsed_at":"2022-08-15T20:20:52.794Z","dependency_job_id":null,"html_url":"https://github.com/nickjj/wait-until","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/nickjj/wait-until","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickjj%2Fwait-until","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickjj%2Fwait-until/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickjj%2Fwait-until/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickjj%2Fwait-until/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickjj","download_url":"https://codeload.github.com/nickjj/wait-until/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickjj%2Fwait-until/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262847700,"owners_count":23374055,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","docker","docker-compose","wait"],"created_at":"2025-06-30T20:39:34.030Z","updated_at":"2025-06-30T20:39:38.161Z","avatar_url":"https://github.com/nickjj.png","language":"Shell","readme":"# wait-until ![CI](https://github.com/nickjj/wait-until/workflows/CI/badge.svg?branch=master)\n\nA zero dependency Bash script that waits until a command of your choosing has\nrun successfully.\n\n- [Demo Video](#demo-video)\n- [Use Cases](#use-cases)\n- [Installation](#installation)\n- [Usage Examples](#usage-examples)\n- [Configuration Options](#configuration-options)\n- [About the Author](#about-the-author)\n\n## Demo Video\n\nThis video covers why you might want to use this script and how to use it. It's\nbasically the documention in video form.\n\n[![Demo\nvideo](https://nickjanetakis.com/assets/blog/cards/wait-until-your-dockerized-database-is-ready-before-continuing-6181d654c8c7a45dfffe0384afacb58e71db84fe75bac9eceb53a90faa122159.jpg)](https://www.youtube.com/watch?v=jqqIQoSpxxA)\n\n## Use Cases\n\nI mainly use this in my CI pipelines to wait until a Dockerized database is\nready to accept connections to a specific database as a specific user.\n\nFor example, you might have something like this in your CI set up:\n\n```sh\ndocker-compose up -d\n\nmake db-reset\nmake lint\nmake test\n```\n\nThe make commands don't really matter, but the idea is you can't really reset\nyour database or run your tests that depend on your database being set up\nbefore your database is available.\n\nWhen you first start the official PostgreSQL or MySQL Docker containers, it\nwill take about 5 to 10 seconds for your initial database user / database to\nbe created based on environment variables you pass into the container.\n\nThis isn't a problem in development because you'd probably run everything in\nthe foreground and manually wait until your DB is ready before interacting\nwith your project. But in a CI environment, it's a problem because it will\nblow up without waiting.\n\nTechnically you can use this script to wait for any command to run successfully.\nThere is nothing about it that's limited to databases or CI environments. There\nare [usage examples](#usage-examples) included in the README.\n\n### Why not sleep X seconds?\n\nYou could, but that's kind of brittle because depending on where you run the\ncommand, it might take a different amount of time to be ready since the spin up\ntime of a command is based on the hardware specs of the machine.\n\nIf you put a long sleep like 30 seconds to be safe then you're waiting\npotentially tens of extra seconds on every CI run.\n\n### Can't you do `docker-compose up -d \u0026\u0026 make db-reset`?\n\nTechnically yes, but you're going to be at the mercy of race conditions. That\nisn't going to ensure that your database is \"really\" ready before control is\npassed over to the 2nd command in the chain.\n\nI ran that 10 times manually and it failed 9 out of 10 times. That's not really\nsuitable to have running in CI.\n\n### What about the `wait-for-it` script?\n\nThe [wait-for-it](https://github.com/vishnubob/wait-for-it) script is popular,\nbut in my opinion it's not suitable for the CI use case and it solves a\ndifferent use case.\n\nFor starters, it waits for a TCP port to be available. Technically that port\ncan be available shortly after your database service is up, but your DB is not\nreally ready for connections because the DB user and database itself hasn't\nbeen created yet.\n\nThat could potentially cause your CI run to fail.\n\nAnother issue with that script is that it expects you to access a TCP port,\nwhich means you'll need to run it inside of your app's container or publish\nyour database's port back to your Docker host if you wanted to use it for CI.\n\nIf you're using that script to make `depends_on` more robust, then yes you'll\nhave that in your app's Docker image but personally I don't do that. IMO that\nproblem should be solved at the web framework level. Once the DB itself is\ncreated with the proper user credentials your app's code should be robust\nenough to retry your database connection until it works or gives up.\n\nAs for publishing the port back to the host so you can run the script from\nwithin your CI server, that comes with 2 problems:\n\n1. Now you're responsible for having to install the `psql` or `mysql` CLI directly within your CI environment.\n2. You'll need to publish your database's port in your `docker-compose.yml` file to access your DB's TCP port.\n\nPersonally I don't like either of those things. The second one means allowing\nthe public internet to attempt to login to your database so having that in my\nreal compose file by default isn't happening and I didn't want to have to rig\nup some `sed` in-line replacement script to do the port publish specifically\nfor CI (basically editing the file only for CI).\n\nAnd that's why I decided to make this script.\n\n## Installation\n\nTypically you would install this script into a base Docker image that you use\nas your CI environment, but we'll cover a few installation methods here.\n\nThe snippets below are set to use the latest release. If you're living on the\nedge you can always replace the tag name with `master`, but I don't recommend\nthat since it's not guaranteed to be stable and may change in the future.\n\n### Installing it directly on your system\n\nThis allows you to run `wait-until` from any directory. If this is on your\npersonal dev box or something like that, feel free to adjust this to put it\ninto a local `bin/` directory that's on your path for your user.\n\n```sh\nsudo curl \\\n  -L https://raw.githubusercontent.com/nickjj/wait-until/v0.3.0/wait-until \\\n  -o /usr/local/bin/wait-until \u0026\u0026 sudo chmod +x /usr/local/bin/wait-until\n```\n\n### Installing it remotely within a Docker image (useful for CI images)\n\nYou would add these instructions somewhere near the bottom of your `Dockefile`.\n\n```Dockerfile\nADD https://raw.githubusercontent.com/nickjj/wait-until/v0.3.0/wait-until /usr/local/bin\nRUN chmod +x /usr/local/bin/wait-until\n```\n\nThis is one of those times where [using `ADD` instead of\n`COPY`](https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile)\ncomes in handy.\n\n### Installing it locally within a Docker image (useful for CI images)\n\nIf you're going for a super optimized base CI image and you already have your\nown scripts being copied to `/usr/local/bin` and you want to piggy back off\nyour `COPY usr/local/bin /usr/local/bin` instruction you may want to just copy\n/ paste this script directly into your image.\n\nThis 1 liner will download the latest release into the current directory of\nyour system. Then you can put it anywhere you want.\n\n```sh\ncurl \\\n  -L https://raw.githubusercontent.com/nickjj/wait-until/v0.3.0/wait-until \\\n  -o wait-until \u0026\u0026 chmod +x wait-until\n```\n\n## Usage Examples\n\nYou can use this for any command but here's a couple of database related examples.\n\n### A quick note about .env files and database passwords\n\nIn all examples, we're sourcing an `.env` file because typically that's where\nyou would define your database environment variables that the official Docker\nimages expect to be set.\n\nYour `.env` file is usually ignored from version control which is a good idea.\nWhat I do is commit a safe `.env.example` file to version control and then `mv\n.env.example .env` as part of my CI pipeline. This file would have development\ncredentials that work and are safe to commit as defaults.\n\nBut if you're connecting to a remote database with sensitive credentials, then\nyou may want to skip that source step and read those environment variables\ndirectly in from your CI provider's secure environment variable settings.\n\n### Waiting for PostgreSQL\n\nThis expects that you've named your Docker Compose PostgreSQL service\n`postgres` if you plan to copy / paste what's below.\n\n```sh\ndocker-compose up -d\n\nsource .env\nwait-until \"docker-compose exec -T -e PGPASSWORD=${POSTGRES_PASSWORD} postgres psql -U ${POSTGRES_USER} ${POSTGRES_USER} -c 'select 1'\"\n\n# TODO: Run your DB reset commands, test suite, etc.\n```\n\n### Waiting for MySQL\n\nThis expects that you've named your Docker Compose MySQL service `mysql` if you\nplan to copy / paste what's below.\n\n```sh\ndocker-compose up -d\n\nsource .env\nwait-until \"docker-compose exec -T -e MYSQL_PWD=${MYSQL_ROOT_PASSWORD} mysql mysql -D ${MYSQL_DATABASE} -e 'select 1'\"\n\n# TODO: Run your DB reset commands, test suite, etc.\n```\n\n#### What's with the `-T` flag?\n\nBy default `docker-compose exec` configures a TTY which is fine and dandy in\ndevelopment since you're running a terminal emulator. This has nice advantages\nlike being able to have an interactive prompt and see colors.\n\nWithin most (maybe all?) CI environments you'll get a `the input device is not\na TTY` error without having `-T` set when using this script. That flag disables\npseudo-tty allocation.\n\n#### The failed connection output is noisy, make it stop!\n\nYou can always adjust your command to redirect everything to `/dev/null`. For\nexample, at the end of your command (outside of the quotes) you can add `\u003e\n/dev/null 2\u003e\u00261` to eliminate all output (both STDOUT and STDERR).\n\nPersonally I like seeing all of the output in CI. It's especially handy for\nbeing able to debug the command you're waiting on. For example I initially\nredirected everything to `/dev/null` by default but it made debugging that `-T`\nissue a pain in the butt.\n\n## Configuration Options\n\nYou can add an optional second argument to customize the timeout in seconds. By\ndefault it's set to 60 seconds.\n\nFor example you can run `wait-until \"grep\" 3` to try it out. The `grep` command\nwill fail to run since it requires at least 1 argument. As configured\n`wait-until` will try for 3 seconds until it gives up.\n\n## About the Author\n\nI'm a self taught developer and have been freelancing for the last ~20 years.\nYou can read about everything I've learned along the way on my site at\n[https://nickjanetakis.com](https://nickjanetakis.com/). There's hundreds of\n[blog posts](https://nickjanetakis.com/blog/) and a couple of [video\ncourses](https://nickjanetakis.com/courses/) on web development and deployment\ntopics. I also have a [podcast](https://runninginproduction.com) where I talk\nto folks about running web apps in production.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickjj%2Fwait-until","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickjj%2Fwait-until","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickjj%2Fwait-until/lists"}