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 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
    • Security Level: Public (Everyone can see)
    • 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.

      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: