Why do sleep & wait in bash?

后端 未结 2 1770
终归单人心
终归单人心 2021-02-01 06:57

I\'m having trouble understanding the startup commands for the services in this docker-compose.yml. The two relevant lines from the .yml are:

command: \"/bin/sh          


        
相关标签:
2条回答
  • 2021-02-01 07:18

    The only reason I see:

    If you killall -INT sleep, this won't affect main script.

    Try this:

    while true ;do sleep 12; echo yes;done
    

    Then send a Interrupt signal:

    killall -INT sleep
    

    This will break the job!

    Try now

    while true ;do sleep 12 & wait $! ; echo yes;done
    

    Then again:

    killall -INT sleep
    

    Job won't break!

    Sample output, hitting killall -INT sleep from another window:

    user@myhost:~$ while true ;do sleep 12; echo yes;done
    break
    
    user@myhost:~$ while true ;do sleep 12 & wait $! ; echo yes;done
    [1] 30632
    [1]+  Interrupt               sleep 12
    yes
    [1] 30636
    [1]+  Interrupt               sleep 12
    yes
    [1] 30638
    [1]+  Interrupt               sleep 12
    yes
    [1] 30640
    
    0 讨论(0)
  • 2021-02-01 07:28

    It makes sense to sleep in background and then wait, when one wants to handle signals in a timely manner.

    When bash is executing an external command in the foreground, it does not handle any signals received until the foreground process terminates

    (detailed explanation here).

    While the second example implements a signal handler, for the first one it makes no difference whether the sleep is executed in foreground or not. There is no trap and the signal is not propagated to the nginx process. To make it respond to the SIGTERM signal, the entrypoint should be something this:

    /bin/sh -c 'nginx -g \"daemon off;\" & trap exit TERM; while :; do sleep 6h  & wait $${!}; nginx -s reload; done'
    

    To test it:

    docker run --name test --rm --entrypoint="/bin/sh" nginx  -c 'nginx -g "daemon off;" & trap exit TERM; while :; do sleep 20 & wait ${!}; echo running; done'
    

    Stop the container

    docker stop test
    

    or send the TERM signal (docker stop sends a TERM followed by KILL if the main process does not exit)

    docker kill --signal=SIGTERM test
    

    By doing this, the scripts exits immediately. Now if we remove the wait ${!} the trap is executed when sleep ends. All that works well for the second example too.

    Note: in both cases the intention is to check certificate renewal every 12h and reload the configuration every 6h as mentioned in the guide The two commands do that just fine. IMHO the additional wait in the first example is just an oversight of the developers.

    EDITED:

    It seems the rationalization above, which was meant to give possible reasons behind the background sleep, might create some confusion. (There is a related post Why use nginx with “daemon off” in background with docker?).

    While the command suggested in the answer above is an improvement over the one in the question it is still flawed because, as mentioned in the linked post, the nginx server should be the main process and not a child. That can be easily achieved using the exec system call. The script becomes:

    'while :; do sleep 6h; nginx -s reload; done & exec nginx -g "daemon off;"'
    

    (More info in section Configure app as PID 1 in Docker best practices)

    This, IMHO, is far better because not only is nginx monitored but it also handle signals. A configuration reload (nginx -s reload), for example, can also be done manually by simply sending the HUP signal to the docker container (See Controlling nginx).

    0 讨论(0)
提交回复
热议问题