Code Monkey home page Code Monkey logo

wait-for-it's Introduction

wait-for-it

wait-for-it.sh is a pure bash script that will wait on the availability of a host and TCP port. It is useful for synchronizing the spin-up of interdependent services, such as linked docker containers. Since it is a pure bash script, it does not have any external dependencies.

Usage

wait-for-it.sh host:port [-s] [-t timeout] [-- command args]
-h HOST | --host=HOST       Host or IP under test
-p PORT | --port=PORT       TCP port under test
                            Alternatively, you specify the host and port as host:port
-s | --strict               Only execute subcommand if the test succeeds
-q | --quiet                Don't output any status messages
-t TIMEOUT | --timeout=TIMEOUT
                            Timeout in seconds, zero for no timeout
-- COMMAND ARGS             Execute command with args after the test finishes

Examples

For example, let's test to see if we can access port 80 on www.google.com, and if it is available, echo the message google is up.

$ ./wait-for-it.sh www.google.com:80 -- echo "google is up"
wait-for-it.sh: waiting 15 seconds for www.google.com:80
wait-for-it.sh: www.google.com:80 is available after 0 seconds
google is up

You can set your own timeout with the -t or --timeout= option. Setting the timeout value to 0 will disable the timeout:

$ ./wait-for-it.sh -t 0 www.google.com:80 -- echo "google is up"
wait-for-it.sh: waiting for www.google.com:80 without a timeout
wait-for-it.sh: www.google.com:80 is available after 0 seconds
google is up

The subcommand will be executed regardless if the service is up or not. If you wish to execute the subcommand only if the service is up, add the --strict argument. In this example, we will test port 81 on www.google.com which will fail:

$ ./wait-for-it.sh www.google.com:81 --timeout=1 --strict -- echo "google is up"
wait-for-it.sh: waiting 1 seconds for www.google.com:81
wait-for-it.sh: timeout occurred after waiting 1 seconds for www.google.com:81
wait-for-it.sh: strict mode, refusing to execute subprocess

If you don't want to execute a subcommand, leave off the -- argument. This way, you can test the exit condition of wait-for-it.sh in your own scripts, and determine how to proceed:

$ ./wait-for-it.sh www.google.com:80
wait-for-it.sh: waiting 15 seconds for www.google.com:80
wait-for-it.sh: www.google.com:80 is available after 0 seconds
$ echo $?
0
$ ./wait-for-it.sh www.google.com:81
wait-for-it.sh: waiting 15 seconds for www.google.com:81
wait-for-it.sh: timeout occurred after waiting 15 seconds for www.google.com:81
$ echo $?
124

Community

Debian: There is a Debian package.

wait-for-it's People

Contributors

aviau avatar douglas-gibbons avatar fwoelffel avatar garethrandall avatar iturgeon avatar renanbr avatar scop avatar silex avatar szczad avatar vishnubob avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wait-for-it's Issues

wait-for-it.sh file if downloaded and unzipped using winrar - creates problem

If using windows operating system this may cause a problem.
Desite supplying a command with host and port as below:

When using command in docker-compose

    command: ["/wait-for-it.sh", "myservice:4444", "npm", "test"]

error

"Error: you need to provide a host and port to test."

Solution, download file manually by clicking 'raw' on github and downloading it.

Add proper support to MAC OS systems (workarounds do not work)

Installing 'coreutils' and setting the alias to timeout for gtimeout does not work.

It is missing '--timeout' flag. So the code fails on line 56 or 58 where it specifies --timeout=$TIMEOUT.

I do not want to use PERL workaround as it won't be available on all machines. And the script needs to run on both Mac OS and linux alpine, so I can't simply change it to work with one or the other.

Overriding $PORT and $HOST variables

I was using wait-for-it.sh for starting service from docker-compose after RabbitMq is ready.
Though wait-for-it.sh was overriding my $HOST and $PORT variables that the service was dependent on.

I customized script a little bit to dump env variables and then return them back when executing commands after --

I suggest to add this to script or if needed I can open a PR for
as it was relatively hard to debug

Breaking change to busybox's timeout causes wait-for-it to fail

In busybox commit c9720a761, a breaking change was introduced that
removes the -t flag to timeout in favor of just taking the time as
the second arg, bringing it in line with coreutils' timeout. This
commit was included in tag 1.31.1, released on 25 Oct, 2019, at
which point my integration tests that spin up a server using wait-for-it
started to fail.

Network Bridge never detects container is Live

Hi,

I noticed some abnormal behavior and i need some tips if you can help me, when i run my compose file and let docker manage the networks the containers start and wait for their respectively dependencies and being available in the ports i specified but when i specify for each container network: bridge and run the compose i get this weird behavior that the container starts but never runs the init script i define it to run. in the logs it nevers shows the wait-for-it script picking up the container it was waiting for it to be live,

Any help on how to fix this

Thanks

How to wait for multiple ports to be ready?

Having quickly skimmed through the script, I couldn't find a way to wait for multiple host+port combinations to be ready. Any pointers on the best way to do this?
One way I can imagine is one wait-for-it starting another wait-for-it.

This is probably not a common situation, but in my case I need to wait for two independent databases to get ready before launching my app.

To check a running service instead of only checking if host on port is available

I have a Dockerfile which basis is
FROM jboss/keycloak-mysql:3.3.0.Final
Exposing the port 8080.
The wildfly comes up pretty fast, in xx seconds, the keycloak.war takes yy minutes to deploy.
My next service is relying that the keycloak war is up and running with its realms.
Using wait-for-it.sh gives clerance after xx seconds while I would want to wait for yy minutes.

The last rows in Dockerfile relying on keycloak looks lik this ( where 'sso' is my keycloak-service)

ENTRYPOINT ["/sbin/tini", "--", "/wait-for-it.sh", "sso:8080", "-t", "300", "--"]
CMD ["java", "-jar", "accounts-api-swarm.jar", "-Sinitdata" ]

So 'sso' always starts to early, the keycloak realms have not been created.
What I would like to do is to have an enhancement that works like this

ENTRYPOINT ["/sbin/tini", "--", "/wait-for-it.sh", "sso:8080/auth/realms/master/", "-t", "300", "--"]

so "sso:8080/auth/realms/master/ gives me http_status = 200 - Then and only then would like to start the java -jar accounts-api-swarm.jar Sinitdata ....

Some thoughts are here in this small repo :
https://github.com/Inkimar/wait-for

-Ingimar

single quotes getting removed from the command args

I am trying to run nginx startup command in the command args but failing

bash-4.3# /tmp/wait-for-fpm.sh webapp:9000 -t 100 -- nginx -g 'daemon off;'
wait-for-fpm.sh: waiting 100 seconds for webapp:9000
wait-for-fpm.sh: webapp:9000 is available after 0 seconds
nginx -g daemon off;
nginx: invalid option: "off;"
bash-4.3# 

Can't find how the signgle quotes getting removed
The command should be as it is like nginx -g 'daemon off;' not nginx -g daemon off;

Not working for cassandra docker container

screen shot 2018-10-24 at 9 23 37 pm

Eventhough the docker cassandra container is running. I am manually testing the script on running container. However, its still printing db is up. For host I have also tried name of the container:port. I am getting same error results for that input as well

Thank you

Support running on OSX

OSX bash shell doesn't have a timeout command, but often (at least dev OSX machines) will have perl. Can do:

function timeout() { perl -e 'alarm shift; exec @ARGV' "$@"; }

wait-for error message for missing dependencies

wait-for should throw an error message if dependencies are missing.

For example the Centos7 image neither has netcat nor tcp installed. A friendly message that this packages are neccessary.

Alternatively a hint in the README should point the admin to the required packages.

Timeout needs -t option in BusyBox

When running this script in Alpine, this error occurs:

timeout: can't execute '15': No such file or directory
BusyBox v1.24.1 (2015-12-16 08:00:02 GMT) multi-call binary.

Usage: timeout [-t SECS] [-s SIG] PROG ARGS

Timeout is not support on Centos 7

Hi guy, when I run this script in OSX, everything will be ok. But when I deploy docker on cloud with CentOS 7, this error is shown.

timeout: can't execute '15': No such file or directory

Please help me this problem.

permission denied

ERROR: for api Cannot start service api: oci runtime error: container_linux.go:247: starting container process caused "exec: "./wait-for-postgres.sh": permission denied"
ERROR: Encountered errors while bringing up the project.

Support http endpoints (http status codes)

Sometimes it is needed to not just reach the endpoint, but verify that something is responding normally there. My specific use case was that I had an nginx server on which I was testing the endpoints "successfully", but they were returning 502 Bad Gateway errors because the server that it was proxying was not yet up.

Can add an option to use curl or wget to do this.

Not compatible with mac?

Trying all the examples in iTerm2 on my mac, I get the following error:

$ wait-for-it.sh www.google.com:80 -- echo "google is up"
wait-for-it.sh: line 53: timeout: command not found
wait-for-it.sh: timeout occurred after waiting 15 seconds for www.google.com:80
google is up

I've tried with variations such as using bash and sh and different working directories. Is this just not compatible with mac osx, El Captain?

The script doesn't work on bash 4.4

The version where it doesn't work: GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0). After each command it shows:

readlink: illegal option -- f

The version where it works: GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

infinite wait

It would be nice if --timeout=-1 would wait forever until the port is available.

Environment variables like PORT, HOST, and TIMEOUT clobbered

The script contaminates the environment, clobbering the PORT env-var, among others. These are not-uncommon names to use when setting up services in a container.

It might be wise for the script to namespace its env-vars, like WAITFORIT_PORT

Usage with Docker

In order to use it with Docker and docker-compose,
place it alongside Dockerfile, build it into the image with exec permissions and reference it in docker-compose.yml.

- Dockerfile
- wait-for-it.sh
#Dockerfile
...
COPY wait-for-it.sh /wait-for-it.sh
RUN chmod +x /wait-for-it.sh
...
#docker-compose.yml
...
  my-service:
    build:
      context: "."
      container_name: my_container
      command: ["/wait-for-it.sh", "mysql:3306", "--", [entrypoint function]]
...

Wait for multiple services

It would be ideal if multiple services (i.e. multiple host:port combinations) could be declared such that the command is executed only after all dependent services are available.

Prefix http:// does not work

When a preffix is used before the domain or IP, like http://localhost:8080, the script recognizes the preffix as the domain so it tries to ping without the port, like:

wait-for-it.sh: waiting 10 seconds for http://localhost
wait-for-it.sh: timeout occurred after waiting 10 seconds for http://localhost

Debian tracker and policy recommendation flag

Debian tracker reports three issues. The one with higher importance is:

The package is severely out of date with respect to the Debian Policy. The package should be updated to follow the last version of Debian Policy (Standards-Version 4.5.0 instead of 3.9.7).

Apparently #3 could be closed.

POSIX compliant shell

Is it possible to make this shell-independent?

/wait-for-it.sh: line 70: syntax error: unexpected "(" (expecting ";;")

This would be particularly useful to run it with alpine, which uses busybox.

Volunteer Needed

Hi there! I wrote wait-for-it in order to help me orchestrate containers I operate at my day job. I thought it was a neat little script, so I published it. I assumed I would be its only user, but that's not what happened! wait-for-it has received more stars then all of my other public repositories put together. I had no idea this tool would solicit such an audience, and I was equally unprepared to carve out the time required to address my user's issues and patches. I would like to solicit a volunteer from the community who would be willing to be a co-maintainer of this repository. If this is something you might be interested in, please email me at [email protected]. Thanks!

Is it possible to wait for a specific path?

I am using a reverse proxy where a lot of services are located under the same domain on different paths.

my-domain/api/bacon
my-domain/api/potato

And I would like to wait for each of these services individually.

Would it be possible to do something like:

wait-for-it my-domain:80/api/bacon

I've tryed some variations of it and all of them fail.

Line 75 syntax error

line 75: syntax error: unexpected "(" (expecting ";;")

P.S: Script running via /bin/sh

License?

Would you mind explicitly adding a license to this script? I realize this sounds like a ridiculous request, but lawyers are annoying. ;)

For UDP?

Enhancement request:

  • Is there any chance to have UDP test added for this script?

PORT env variable will be overridden

In my use case:

  web:
    build: .
    command: ./wait-for-it.sh mongo:27017 -t 0 -- nodemon server.js
    restart: always
    environment:
      - PORT=8096
    volumes:
      - .:/code
    ports:
      - "8096:8096"
    links:
      - mongo

  mongo:
    image: 'mongo:3.2.1'
    ports:
      - '27017:27017'
    volumes:
      - './data/db:/data/db'

I have environment variable named PORT which will be overridden by mongo's port when running wait-for-it bash.
My solution is to change PORT variable in bash to _PORT to make it looks more private.

Docker stack deploy seems not working

It seems strange that all services are started, but cannot connect to the expose port...
But everything is ok via docker-compose, except docker stack deploy.

Publish to package manager

It would be great if we could just install this from something like apt-get.

I would like to do the following steps:

  • sudo apt-get install wait-for-it
  • wait-for-it www.google.com:80 -- echo "google is up"

not working on alpine 3.10 with bash installed

we use wait-for-it.sh heavily in CI for docker integration testing in golang. Recently a job broke due to wait-for-it.sh error. I believe the issue may have to do with something changing in timeout from alpine3.9 (works) to alpine 3.10 (not working). In both cases we were installing bash with apk.

Repro (note in vi I am copying wait-for-it from current master)

$ docker run -it --rm golang:1.12-alpine
/go # vi wait-for-it.sh
/go # chmod +x wait-for-it.sh 
/go # apk update && apk add --no-cache bash
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.1-11-g89d0862481 [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.1-12-ga885fe876c [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10327 distinct packages available
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
(1/5) Installing ncurses-terminfo-base (6.1_p20190518-r0)
(2/5) Installing ncurses-terminfo (6.1_p20190518-r0)
(3/5) Installing ncurses-libs (6.1_p20190518-r0)
(4/5) Installing readline (8.0.0-r0)
(5/5) Installing bash (5.0.0-r0)
Executing bash-5.0.0-r0.post-install
Executing busybox-1.30.1-r2.trigger
OK: 15 MiB in 20 packages
/go # ./wait-for-it.sh docker:5432
timeout: unrecognized option: t
BusyBox v1.30.1 (2019-06-12 17:51:55 UTC) multi-call binary.

Usage: timeout [-s SIG] SECS PROG ARGS

Runs PROG. Sends SIG to it if it is not gone in SECS seconds.
Default SIG: TERM.
wait-for-it.sh: timeout occurred after waiting 15 seconds for docker:5432

Workaround: I was able to work around this issue by installing coreutils as well which updates timeout (continuing from example above)

/go # apk update && apk add --no-cache coreutils
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
v3.10.1-11-g89d0862481 [http://dl-cdn.alpinelinux.org/alpine/v3.10/main]
v3.10.1-12-ga885fe876c [http://dl-cdn.alpinelinux.org/alpine/v3.10/community]
OK: 10327 distinct packages available
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
(1/3) Installing libacl (2.2.52-r6)
(2/3) Installing libattr (2.4.48-r0)
(3/3) Installing coreutils (8.31-r0)
Executing busybox-1.30.1-r2.trigger
OK: 16 MiB in 23 packages
/go # ./wait-for-it.sh -t 15 docker:5432
wait-for-it2.sh: waiting 15 seconds for docker:5432
wait-for-it2.sh: timeout occurred after waiting 15 seconds for docker:5432

please tag and version this repository

Hello!

I am going to upload wait-for-it to Debian and It would help me keep up with development if the repository was tagged. Are you able to do that please?

Busybox's timeout requires different arguments

I was using wait-for-it on a debian docker container, and all things were great (thanks for the script!).

However, we switched to an Alpine Linux based docker image (which uses busybox) and the script stopped waiting correctly.

As it turns out timeout requires an argument flag for the time. Here's the manual from https://busybox.net/downloads/BusyBox.html

timeout
timeout [-t SECS] [-s SIG] PROG [ARGS]
Runs PROG. Sends SIG to it if it is not gone in SECS seconds. Defaults: SECS: 10, SIG: TERM.

This differs from typical linux usage:

timeout [OPTION] DURATION COMMAND [ARG]...

Changing lines 52 and 54 where timeout is used by prepending -t before the $TIMEOUT causes it to work.

Here's the working result:

wait_for_wrapper()
{
    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
    if [[ $QUIET -eq 1 ]]; then
        timeout -t $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
    else
        timeout -t $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
    fi
    PID=$!
    trap "kill -INT -$PID" INT
    wait $PID
    RESULT=$?
    if [[ $RESULT -ne 0 ]]; then
        echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
    fi
    return $RESULT
}

I did a quick search for a simple method to determine if busybox is being used, not sure what the best solution would be. Worst case - this post may help others in a similar situation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.