Application Server 3  4  5 and 6
  1. Application Server 3 4 5 and 6
  2. JBAS-3748

Allow bin/run.sh to run in the background and stop jboss, when stopped.

    Details

    • Type: Feature Request Feature Request
    • Status: Closed (View Workflow)
    • Priority: Major Major
    • Resolution: Done
    • Affects Version/s: JBossAS-4.0.5.CR1
    • Fix Version/s: JBossAS-4.0.5.GA
    • Component/s: None
    • Labels:
      None
    • Similar Issues:
      Show 10 results 

      Description

      I want to write an init.d script with the typical start - stop options to start JBossAS. I want to use the method of writing a pid file when started and killing the pid found in the file when stopping.

      I do not want to use the "normal" shutdown mechanism to stop it because that assumes the JBoss instance has exposed its remote MBean interface (and I do not want to assume that). Plus, I want to ensure it is killed, and using the "kill" command is as fool-proof as I need it to be.

      I also want to be able to use run.sh to start the instance (I do not want to have to do all the work run.sh does - setting up the JVM, passing in arguments, worrying about all the cygwin - darwin things, etc. etc.).

      But, if my init.d script starts run.sh, I cannot use $! in my init.d script as the pid file contents because $! is the pid of run.sh script process. It is NOT the pid of the JBoss JVM instance itself. If I then go to kill the run.sh process, it dies, but the JVM process does not. Therefore, the init.d stop option does not work - it cannot stop the JBoss VM.

      I would like to propose to make the following change to run.sh that would facilitate this. This change is backwards compatible. What this change does is - if I set the environment variable "LAUNCH_JBOSS_IN_BACKGROUND" and source run.sh, run.sh will export JBOSS_PID as the pid value of the JVM process. My init.d script (the thing that sources run.sh) will be able to write JBOSS_PID anywhere I want and thus later be able to use it to kill the JBoss VM.

      See attached patch for the change.

        Gliffy Diagrams

        1. patch.txt
          1 kB
          John Mazzitelli
        2. patch-pidfile.txt
          1 kB
          John Mazzitelli
        3. run.sh.patch
          2 kB
          Ian Springer

          Issue Links

            Activity

            Hide
            John Mazzitelli added a comment -

            One other idea that would work (and would allow us to execute run.sh normally rather than just source it) is to not pass JBOSS_PID variable, but instead have the value of LAUNCH_JBOSS_IN_BACKGROUND be set to a file path by whoever is executing run.sh.

            If LAUNCH_JBOSS_IN_BACKGROUND is set, assume its a full filepath and use it as the filename to store the pid. run.sh can be executed normally and will write the pid thus allowing init.d to pick it up.

            Dimitris also had an idea to avoid setting variables at all and just have a signal trap in the run.sh set up so that when run.sh process is killed, it forwards that signal to the VM process - effectively killing the JBossAS process too. This would involve more testing since I've seen strange signal trap behavior on some platforms. We need to test this signal trap stuff on all flavors of UNIX as well as Darwin and Cygwin.

            Show
            John Mazzitelli added a comment - One other idea that would work (and would allow us to execute run.sh normally rather than just source it) is to not pass JBOSS_PID variable, but instead have the value of LAUNCH_JBOSS_IN_BACKGROUND be set to a file path by whoever is executing run.sh. If LAUNCH_JBOSS_IN_BACKGROUND is set, assume its a full filepath and use it as the filename to store the pid. run.sh can be executed normally and will write the pid thus allowing init.d to pick it up. Dimitris also had an idea to avoid setting variables at all and just have a signal trap in the run.sh set up so that when run.sh process is killed, it forwards that signal to the VM process - effectively killing the JBossAS process too. This would involve more testing since I've seen strange signal trap behavior on some platforms. We need to test this signal trap stuff on all flavors of UNIX as well as Darwin and Cygwin.
            Hide
            John Mazzitelli added a comment -

            I've attached a newer patch that can be used instead. I checks the value of that LAUNCH_JBOSS_IN_BACKGROUND variable and if its value is not "nofile", the it will be assumed to be full file path to the pid file that run.sh should created. That file will contain the pid of the JBoss VM process. This way, a user can either source run.sh OR directly execute run.sh (so long as the caller provides a file that the pid can be stored in).

            Show
            John Mazzitelli added a comment - I've attached a newer patch that can be used instead. I checks the value of that LAUNCH_JBOSS_IN_BACKGROUND variable and if its value is not "nofile", the it will be assumed to be full file path to the pid file that run.sh should created. That file will contain the pid of the JBoss VM process. This way, a user can either source run.sh OR directly execute run.sh (so long as the caller provides a file that the pid can be stored in).
            Hide
            Ian Springer added a comment -

            Here is a patch to https://svn.jboss.org/repos/jbossas/branches/Branch_4_0/system/src/bin/run.sh that enables run.sh to intercept signals and pass them on to the JBoss java process. I've tested it on RHEL and Cygwin, and it works correctly. It will still need to be tested on Solaris, HP-UX, AIX, etc..

            A few notes on the implementation:

            Note, java is execed in the bg - this is necessary in order to get its pid and set traps which can send signals to the java process.

            The while WAIT_STATUS loop was the tricky part - it took me a while to get this right. I found that the traps get triggered as soon as the java proc receives a signal, even if the process hasn't actually terminated yet.

            It's necessary to call wait once to catch the signal and again to wait for the proc to actually terminate. Once the proc has terminated, the very next time you call wait, it'll return 127, indicating the proc no longer exists.

            The other thing that hung me up for a bit is that JBoss appears to ignore SIGINT (2), so i had to have the trap for that signal send a SIGTERM instead so that Ctrl-C'ing run.sh will stop the server.

            The script supports relaying of the following signals:
            1) SIGHUP
            2) SIGINT (i.e. Ctrl-C)
            3) SIGQUIT (i.e. Ctrl-\ on UNIX or Ctrl-Break on Windows, which triggers JVM thread dump)
            13) SIGPIPE
            15) SIGTERM (i.e. defaut signal for kill command)

            Finally, I also modded to have run.sh exit with the same status the JBoss java proc exited w/, so run.sh's exit code will actually be useful.

            Show
            Ian Springer added a comment - Here is a patch to https://svn.jboss.org/repos/jbossas/branches/Branch_4_0/system/src/bin/run.sh that enables run.sh to intercept signals and pass them on to the JBoss java process. I've tested it on RHEL and Cygwin, and it works correctly. It will still need to be tested on Solaris, HP-UX, AIX, etc.. A few notes on the implementation: Note, java is execed in the bg - this is necessary in order to get its pid and set traps which can send signals to the java process. The while WAIT_STATUS loop was the tricky part - it took me a while to get this right. I found that the traps get triggered as soon as the java proc receives a signal, even if the process hasn't actually terminated yet. It's necessary to call wait once to catch the signal and again to wait for the proc to actually terminate. Once the proc has terminated, the very next time you call wait, it'll return 127, indicating the proc no longer exists. The other thing that hung me up for a bit is that JBoss appears to ignore SIGINT (2), so i had to have the trap for that signal send a SIGTERM instead so that Ctrl-C'ing run.sh will stop the server. The script supports relaying of the following signals: 1) SIGHUP 2) SIGINT (i.e. Ctrl-C) 3) SIGQUIT (i.e. Ctrl-\ on UNIX or Ctrl-Break on Windows, which triggers JVM thread dump) 13) SIGPIPE 15) SIGTERM (i.e. defaut signal for kill command) Finally, I also modded to have run.sh exit with the same status the JBoss java proc exited w/, so run.sh's exit code will actually be useful.
            Hide
            Dimitris Andreadis added a comment -

            Let's do some more testing, but I think it's ok.

            Show
            Dimitris Andreadis added a comment - Let's do some more testing, but I think it's ok.
            Hide
            Dimitris Andreadis added a comment -

            Thanks a bunch Ian. The final modifications to the script are shown below:

            Basically it assumes the default behaviour, unless LAUNCH_JBOSS_IN_BACKGROUND is set. In that case, it'll start and wait for jboss in the background, relaying most signals.

            The net result is if the parent process (run.sh) is stopped, jboss will be stopped too. So whoever starts run.sh (init script or whatever) needs only to deal with the run.sh PID, not the jboss one.

            while true; do
            if [ "x$LAUNCH_JBOSS_IN_BACKGROUND" = "x" ]; then

            1. Execute the JVM in the foreground
              "$JAVA" $JAVA_OPTS \
              -Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \
              -classpath "$JBOSS_CLASSPATH" \
              org.jboss.Main "$@"
              JBOSS_STATUS=$?
              else
            2. Execute the JVM in the background
              "$JAVA" $JAVA_OPTS \
              -Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \
              -classpath "$JBOSS_CLASSPATH" \
              org.jboss.Main "$@" &
              JBOSS_PID=$!
            3. Trap common signals and relay them to the jboss process
              trap "kill -HUP $JBOSS_PID" HUP
              trap "kill -TERM $JBOSS_PID" INT
              trap "kill -QUIT $JBOSS_PID" QUIT
              trap "kill -PIPE $JBOSS_PID" PIPE
              trap "kill -TERM $JBOSS_PID" TERM
            4. Wait until the background process exits
              WAIT_STATUS=0
              while [ "$WAIT_STATUS" -ne 127 ]; do
              JBOSS_STATUS=$WAIT_STATUS
              wait $JBOSS_PID 2>/dev/null
              WAIT_STATUS=$?
              done
              fi
            5. If restart doesn't work, check you are running JBossAS 4.0.4+
            6. http://jira.jboss.com/jira/browse/JBAS-2483
            7. or the following if you're running Red Hat 7.0
            8. http://developer.java.sun.com/developer/bugParade/bugs/4465334.html
              if [ $JBOSS_STATUS -eq 10 ]; then
              echo "Restarting JBoss..."
              else
              exit $JBOSS_STATUS
              fi
              done
            Show
            Dimitris Andreadis added a comment - Thanks a bunch Ian. The final modifications to the script are shown below: Basically it assumes the default behaviour, unless LAUNCH_JBOSS_IN_BACKGROUND is set. In that case, it'll start and wait for jboss in the background, relaying most signals. The net result is if the parent process (run.sh) is stopped, jboss will be stopped too. So whoever starts run.sh (init script or whatever) needs only to deal with the run.sh PID, not the jboss one. while true; do if [ "x$LAUNCH_JBOSS_IN_BACKGROUND" = "x" ]; then Execute the JVM in the foreground "$JAVA" $JAVA_OPTS \ -Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \ -classpath "$JBOSS_CLASSPATH" \ org.jboss.Main "$@" JBOSS_STATUS=$? else Execute the JVM in the background "$JAVA" $JAVA_OPTS \ -Djava.endorsed.dirs="$JBOSS_ENDORSED_DIRS" \ -classpath "$JBOSS_CLASSPATH" \ org.jboss.Main "$@" & JBOSS_PID=$! Trap common signals and relay them to the jboss process trap "kill -HUP $JBOSS_PID" HUP trap "kill -TERM $JBOSS_PID" INT trap "kill -QUIT $JBOSS_PID" QUIT trap "kill -PIPE $JBOSS_PID" PIPE trap "kill -TERM $JBOSS_PID" TERM Wait until the background process exits WAIT_STATUS=0 while [ "$WAIT_STATUS" -ne 127 ]; do JBOSS_STATUS=$WAIT_STATUS wait $JBOSS_PID 2>/dev/null WAIT_STATUS=$? done fi If restart doesn't work, check you are running JBossAS 4.0.4+ http://jira.jboss.com/jira/browse/JBAS-2483 or the following if you're running Red Hat 7.0 http://developer.java.sun.com/developer/bugParade/bugs/4465334.html if [ $JBOSS_STATUS -eq 10 ]; then echo "Restarting JBoss..." else exit $JBOSS_STATUS fi done
            Hide
            Ian Springer added a comment -

            I tested the version Dmitris checked in on RHEL4. Once I've set the LAUNCH_JBOSS_IN_BACKGROUND flag, i.e.:

            export LAUNCH_JBOSS_IN_BACKGROUND=1

            everything works as designed.

            Note, I noticed during my testing that JBoss ignores SIGPIPE. So running "kill -PIPE" on the run.sh process, is a no-op. However, if a "real" SIGPIPE occurs, JBoss becomes disconnected from its output and so run.sh appears to be hung. To reproduce this, run:

            export LAUNCH_JBOSS_IN_BACKGROUND=1
            ./run.sh | more

            Then, from another terminal, kill the 'more' process. You should see the run.sh window appear to hang, though JBoss will still be running, with its output going to /dev/null. Not sure if/how we want to handle this situation; one possiblity would be to stop the JBoss process if a SIGPIPE occurs, i.e.:

            trap "kill -TERM $JBOSS_PID" PIPE

            Another possiblity would be to print a warning, i.e.:

            trap "WARNING: run.sh has received a SIGPIPE; JBoss output may no longer be associated with a terminal." PIPE

            Show
            Ian Springer added a comment - I tested the version Dmitris checked in on RHEL4. Once I've set the LAUNCH_JBOSS_IN_BACKGROUND flag, i.e.: export LAUNCH_JBOSS_IN_BACKGROUND=1 everything works as designed. — Note, I noticed during my testing that JBoss ignores SIGPIPE. So running "kill -PIPE" on the run.sh process, is a no-op. However, if a "real" SIGPIPE occurs, JBoss becomes disconnected from its output and so run.sh appears to be hung. To reproduce this, run: export LAUNCH_JBOSS_IN_BACKGROUND=1 ./run.sh | more Then, from another terminal, kill the 'more' process. You should see the run.sh window appear to hang, though JBoss will still be running, with its output going to /dev/null. Not sure if/how we want to handle this situation; one possiblity would be to stop the JBoss process if a SIGPIPE occurs, i.e.: trap "kill -TERM $JBOSS_PID" PIPE Another possiblity would be to print a warning, i.e.: trap "WARNING: run.sh has received a SIGPIPE; JBoss output may no longer be associated with a terminal." PIPE
            Hide
            Ian Springer added a comment -

            Small correction - the last line of my previous post should have been:

            trap "echo WARNING: run.sh has received a SIGPIPE - JBoss output may no longer be associated with a terminal." PIPE

            Show
            Ian Springer added a comment - Small correction - the last line of my previous post should have been: trap "echo WARNING: run.sh has received a SIGPIPE - JBoss output may no longer be associated with a terminal." PIPE
            Hide
            Dimitris Andreadis added a comment -

            That's doesn't seem like a very common use case (I mean the pipe signal), so lets gather whatever input we have for the run.sh script changes to apply them at a later time. Thanks again.

            Show
            Dimitris Andreadis added a comment - That's doesn't seem like a very common use case (I mean the pipe signal), so lets gather whatever input we have for the run.sh script changes to apply them at a later time. Thanks again.

              People

              • Assignee:
                Dimitris Andreadis
                Reporter:
                John Mazzitelli
              • Votes:
                1 Vote for this issue
                Watchers:
                1 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Development