25

I have a Spring Boot application which runs on embedded Tomcat servlet container mvn spring-boot:run . And I don’t want to deploy the project as separate war to standalone Tomcat.

Whenever I push code to BitBucket/Github, a hook runs and triggers Jenkins job (runs on Amazon EC2) to deploy the application.

The Jenkins job has a post build action: mvn spring-boot:run, the problem is that the job hangs when post build action finished.

There should be another way to do this. Any help would be appreciated.

azizunsal
  • 2,074
  • 1
  • 25
  • 33
  • If that's all that you run, then it's going to hang. It sounds like you just need to use `nohup` to run it as a background process. – Steve Feb 13 '15 at 13:05
  • Why are you running your application from source via Maven instead of `java -jar`ring the packaged artifact? – kryger Feb 13 '15 at 14:24
  • @kryger I'll change the running method asap. In this way the old process (embedded Tomcat instance) should be removed to deploy the new one. I should do it in more elegant way. – azizunsal Feb 14 '15 at 13:12
  • Hi Aziz. How did you solve your problem? The answer to your question is not clear enough for me. I have a similar situation where i use "spring-boot:run" in "my Goals and options" under build section of the configuration page. The application is build and deployed successfully, but the job does not stop. – akcasoy May 25 '15 at 15:24
  • @akcasoy the problem is explained in the accepted answer. If you want to see what the actual problem is you can look at [here](https://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build). `| at now + 1 minutes` do the trick. – azizunsal May 26 '15 at 14:41

5 Answers5

22

The problem is that Jenkins doesn't handle spawning child process from builds very well. Workaround suggested by @Steve in the comment (nohuping) didn't change the behaviour in my case, but a simple workaround was to schedule app's start by using the at unix command:

> echo "mvn spring-boot:run" | at now + 1 minutes

This way Jenkins successfully completes the job without timing out.


If you end up running your application from a .jar file via java -jar app.jar be aware that Boot breaks if the .jar file is overwritten, you'll need to make sure the application is stopped before copying the artifact. If you're using ApplicationPidListener you can verify that the application is running (and stop it if it is) by adding execution of this command:

> test -f application.pid && xargs kill < application.pid || echo 'App was not running, nothing to stop'
kryger
  • 12,906
  • 8
  • 44
  • 65
  • 2
    `echo "mvn spring-boot:run" | at now` (without the 1 minute delay) also works well in my case. – Abdull May 14 '15 at 16:22
  • @Abdull that probably depends on the version of unix; on Ubuntu `now` would schedule at 00 seconds of the current minute (i.e. potentially even in the past). I've just tried `at now + 1 minutes` on a Mac and it complains that "`pluralization is wrong`" :-| – kryger May 21 '15 at 11:16
  • You have to install at (es. sudo apt-get install at) – Flavio Troia Nov 18 '15 at 16:59
  • What if you have two environments for an application? DEV environment and PROD environment. When one runs (even if another port) the other stops. I think this is the case that Jenkins uses only one shell which gets blocked when one environment started running. How to proceed in this case? – Turbut Alin Jun 22 '16 at 11:23
5

I find very useful to first copy the artifacts to a specified area on the server to keep track of the deployed artifacts and not to start the app from the jenkins job folder. Then create a server log file there and start to listening to it on the jenkins window until the server started.

To do that I developed a small shell script that you can find here

You will also find a small article explaining how to configure the project on jenkins.

Please let me know if worked for you. Thnaks

Taylor
  • 3,942
  • 2
  • 20
  • 33
Rogerio Coli
  • 51
  • 1
  • 4
3

The nohup and the at now + 1 minutes didn't work for me. Since Jenkins was killing the process spun in the background, I ensured the process to not be killed by setting a fake BUILD_ID to that Jenkins task. This is what the Jenkins Execute shell task looks like:

BUILD_ID=do_not_kill_me
java -jar -Dserver.port=8053 /root/Deployments/my_application.war &
exit

As discussed here.

Sujay Anjankar
  • 321
  • 3
  • 13
2

I assume you have a Jenkins-user on the server and this user is the owner of the Jenkins-service:

  1. log in on the server as root.
  2. run sudo visudo
  3. add "jenkins ALL=(ALL) NOPASSWD:ALL" at the end (jenkins=your Jenkins-user)
  4. Sign In in Jenkins and choose your jobs and click to configure
  5. Choose "Execute Shell" in the "Post build step"
  6. Copy and paste this:
   service=myapp
   if ps ax | grep -v grep | grep -v $0 | grep $service > /dev/null
   then
       sudo service myapp stop
       sudo unlink /etc/init.d/myapp
       sudo chmod +x /path/to/your/myapp.jar
       sudo ln -s /path/to/your/myapp.jar /etc/init.d/myapp
       sudo service myapp start 
    else
       sudo chmod +x  /path/to/your/myapp.jar
       sudo ln -s  /path/to/your/myapp.jar /etc/init.d/myapp
       sudo service myapp start 
    fi

Save and run your job, the service should start automatically.

kryger
  • 12,906
  • 8
  • 44
  • 65
Anatole Nkwadjo
  • 111
  • 1
  • 2
  • `jenkins ALL=(ALL) NOPASSWD:ALL`??. That is potentially dangerous as you are giving full privileges for jenkins user to execute any command on the server. If the jenkins installation is compromised somehow, the hacker will get full control over the system. For a tighter access restriction, you may change it to: `jenkins ALL=(ALL) NOPASSWD:comma_seperated_commands`. Since there are several commands in here, the whole of the above code could be put in a script, say `myapp_service.sh` and then update the sudo command as `jenkins ALL=(root) NOPASSWD:/full_path_to/myapp_service.sh` – VanagaS Apr 26 '19 at 04:17
1

This worked for me on jenkins on a linux machine

kill -9 $(lsof -t -i:8080) || echo "Process was not running."
mvn clean compile
echo "mvn spring-boot:run" | at now + 1 minutes

In case no process on 8080 it will print the message and will continue.

Make sure that at is installed on your linux machine. You can use

sudo apt-get install at

to install at

muasif80
  • 5,586
  • 4
  • 32
  • 45