Создание демон-процесса на Java
Доброго всем времени суток.
Недавно, по долгу службы, появилась необходимость написать background process для IBM AIX 5.2 на Java с контролирующим shell скриптом.
Раз работа проделана, документация поднята, код написан, почему бы не поделиться с общественностью? По сему, переходим к делу.
1 Демонизация
Для того чтобы демонизировать приложение, необходимо отключить его от терминала, в котором происходит его непосредственный запуск. Для этого необходимо выполнить следующие шаги:
- Отключить stdin от терминала
- Запустить процесс в background’e путем указания амперсанда «&» в конце строки запуска
- Закрыть stdin, stdout непосредственно в приложении (в нашем случае, для Java, это будет System.in.close(); System.out.close();)
Таким образом, минимальная строка запуска должна выглядеть следующим образом:
где » /var/log/daemon_app_error.log» перенаправит вывод с stderr в файл /var/log/daemon_app_error.log.
Если читатель не в курсе, то потоки ввода-вывода в unix shell имеют следующие идентификаторы:
stdin – 0
stdout – 1
stderr – 2
2 Организация обработки сигналов прерывания
В методе doProcessing мы можем организовать бесконечный цикл с предусловием, по которому будет осуществляться окончание работы процесса. Таким условием может быть SIGTERM отправленный из операционной системы, например, посредством kill -15
Код 15 (SIGTERM) одинаков как для AIX, HP-UX так и для обычной Linux-based системы.
Список сигналов и их кодов можно получить с помощью команды kill -l.
Есть несколько способов обработки сигналов в Java:
- Использование sun.misc.Signal и sun.misc.SignalHandler с последующим созданием собственного класса-обработчика, который имплементирует sun.misc.SignalHandler. Более детальную информацию по данному методу вы можете найти тут (http://www.ibm.com/developerworks/ibm/library/i-signalhandling/)
- Использование метода Runtime.getRuntime().addShutdownHook. (сигнатура метода: public void addShutdownHook(Thread hook))
Первый метод не очень хорош из за использования классов из пакета sun.misc. Почему?
Вот, что Sun пишет (http://java.sun.com/products/jdk/faq/faq-sun-packages.html) про package sun.*:
The sun.* packages are not part of the supported, public interface.
A Java program that directly calls into sun.* packages is not guaranteed to work on all Java-compatible platforms. In fact, such a program is not guaranteed to work even in future versions on the same platform…
2-й метод предусматривает передачу в него в качестве аргумента класс наследованный от Thread. Это значит, что при получении SIGTERM будет создан новый thread, который будет совершать определенные программистом действия для завершения работы процесса в целом.
Обратимся к документации (http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#19152), какие же предусловия необходимы, для завершения работы Java программы?
The Java virtual machine terminates all its activity and exits when one of two things happens:
- All the threads that are not daemon threads (§2.19) terminate.
- Some thread invokes the exit method of class Runtime or class System, and the exit operation is permitted by the security manager.
Поэтому:
- Если у нас есть запущенные не демон-нити, необходимо обеспечить их корректное завершение и присоединить их к main, используя join. Демон-thread’ы, т.е. те, для которых было выполнено setDaemon(true), останавливать не обязательно.
- Остановить работу thread main, что подразумевает выход из main метода запускаемого класса.
Можно попросту сделать System.exit(), если Вам не нужно проводить специфические операции по завершению работы программы, закрывая используемые ресурсы и активные соединения.
Модифицированный код с использованием Runtime.getRuntime().addShutdownHook для создания обработчика сигналов прерывания приведен ниже:
Итак, мы имеем метод registerShutdownHook, который вызывается из main и регистрирует обработчик на сигнал прерывания.
При получении сигнала прерывания, вызывается статический метод setShutdownFlag, который меняет значение статического булевого свойства shutdownFlag на true, по значению которого организован цикл в методе doProcessing с предусловием.
3 Контроллирующий скрипт
Итак, процесс-демон написан. Теперь необходимо создать скрипт управляющий его запуском, остановкой и мониторингом состояния.
Описывать весь процесс создания shell control скрипта я не буду, приведу только несколько полезных процедур.
Пример проверки переменных окружения необходымых для запуска/работы процесса
Процедура без аргументов. Перебираем необходимые переменные окружения циклом for. Если переменной нет, выводим предупреждение. Если хотя бы одна переменная не установлена, прекращаем выполнение с кодом ошибки 1.
Проверка элементов classpath
Аргументом этой процедуры является строка с classpath, в котором элементы отделены двоеточием.
Заменяем двоеточие пробельным символом — в результате получаем возможность проверить каждый элемент.
Пример процедуры запуска процесса
Данная процедура предусматривает наличие установленных переменных — PID_DIR, PROCESS_NAME, CPATH
PID_DIR – директория для хранения pid файлов
PROCESS_NAME — имя процесса
CPATH — строка с classpath
Идентификатор процесса запущенного в background’е, можно определить с помощью shell-переменной «$!», который впоследствии записывается в pid файл.
После чего происходит проверка на протяжении 5 секунд, или процесс «не упал» в процессе запуска. Каждую секунду происходит проверка с помощью ps -p статус процесса.
Пример процедуры остановки процесса
Приведенная реализация принимает 2 аргумента на вход:
- id процесса
- абсолютный путь к pid файлу
Процедура посылает процессу SIGTERM и после 5 секунд ожидания, если процесс не остановлен, посылает ему SIGKILL, после чего удаляет pid файл.
Пример процедуры проверки статуса процесса
Принимает 1 аргумент — абсолютный путь к pid файлу
Возвращает значение отличное от 0, если процесс запущен и работает, 0 — если процесс неактивен.
Вот в принципе и все, что хотел рассказать.
Интересно услышать, кто что думает на эту тему.
Источник
The Answer
First, I implemented a Java shutdown hook so when the process receives an interrupt, the service will exit cleanly. This feature is built into the JVM. The shutdown hook can be tested by running the application and then pressing Control-C in the console.
Second, I added a plugin to my pom.xml to use Appassembler to produce a shell script that will run my Java program. The plugin configuration looked something like this:
The Appassembler plugin is nice because it automatically handles:
- copying all dependent libraries
- creating a shell script with the appropriate classpath
- passing system properties for the application’s home directory
Now I had a simple shell script to run which starts the web application.
Third, I wrote an Upstart configuration file. My service was called web , so the file is called web.conf:
The file above does the following:
- Restarts the server if it dies, but if it restarts more than 10 times in 5 seconds, the system will not try to restart it again.
- The owner and group of the process are both set to web . This avoids running the process as root.
- The process umask is 027, which means any log files created will be writable by user web, readable by group web, and have no access by anybody else.
- The process runs out of the directory /opt/web
- All console output is redirected to /dev/null
- The environment has the variable JAVA_OPTS added to it, which the generated shell script uses for additional JVM arguments.
Also, notice that the service itself is launched using authbind. This allows the service to run as user web , but have permission to bind to ports 80 and 443 .
All I did was copy the web.conf file to /etc/init and then run
Conclusion
I found this method very straightforward. If I find later that I’m missing something and JSW, YAJSW, or jsvc add something I was missing, I’ll update this post.
© 2021 Mark Lovett Wells. All Rights Reserved.
Источник
How to Daemonize a Java Program?
I have a Java program that I’d like to daemonize on a linux system. In other words, I want to start running it in a shell and have it continue running after I’ve logged out. I also want to be able to stop the program cleanly.
I found this article which uses a combination of shell scripting and Java code to do the trick. It looks good, but I’d like something simpler, if possible.
What’s your preferred method to daemonize a Java program on a Linux system?
11 Answers 11
Apache Commons Daemon will run your Java program as Linux daemon or WinNT Service.
If you can’t rely on Java Service Wrapper cited elsewhere (for instance, if you are running on Ubuntu, which has no packaged version of SW) you probably want to do it the old fashioned way: have your program write its PID in /var/run/$progname.pid, and write a standard SysV init script (use for instance the one for ntpd as an example, it’s simple) around it. Preferably, make it LSB-compliant, too.
Essentially, the start function tests if the program is already running (by testing if /var/run/$progname.pid exists, and the contents of that file is the PID of a running process), and if not run
The stop function checks on /var/run/$progname.pid, tests if that file is the PID of a running process, verifies that it is a Java VM (so as not to kill a process that simply reused the PID from a dead instance of my Java daemon) and then kills that process.
When called, my main() method will start by writing its PID in the file defined in System.getProperty(«pidfile»).
One major hurdle, though: in Java, there is no simple and standard way to get the PID of the process the JVM runs in.
Источник
How to write a Java daemon
This will be a network application that will always (or near as always as I can manage) be listening on a given port.
I’m fairly new to Java, and very new to non-web server side programming, so I’d like to get feedback from the community on my assumptions and preliminary plans.
I’ve read about jsvc ( http://commons.apache.org/daemon/jsvc.html ) and am currently operating on the assumption that this is the «best» way to write a daemon in java for a linux box (likely running centOS).
Can nagios be configured to monitor whether or not my daemon is running, and to alert me or the sys admin when it isn’t? (I assume yes, but I’m not a very talented sys admin type)
This will be an SMPP client app (or ESME app I guess) which is why I’ve chosen Java as it seems to be a very mature platform for SMPP. However, I know that it’s more «traditional» to write a daemon in C/C++. With modern Java, performing fairly uncomplicated tasks, am I likely to run into any major disadvantages?
What’s the best way to manage deployment of new builds? Just stop the daemon and replace the binary as quickly as possible and restart?
Any other input would be greatly appreciated.
2 Answers 2
How to write a Java daemon that has 24/7 uptime.
We run a number of 24/365 applications on our Linux servers that just call the Java like the following — no need for any C wrappers:
That will put the jar running in the background ( nohup . & ) with no input ( ) and the output (stdout and stderr) redirected to a logfile ( > output.log 2>&1 ). We have distributed logging infrastructure but some console output (such as thread dumps) is still expected. These applications can run for months until we upgrade them.
Can nagios be configured to monitor whether or not my daemon is running, and to alert me or the sys admin when it isn’t?
In terms of monitoring, there is much you can do. Nagios looks to have a JMX plugin for testing the information that jconsole displays. There are also a lot of native JMX logging and monitoring utilities out there. We have internal green/yellow/red indicators that can be pulled up using JMX and easily checked. I also have exported a simple JMX/HTTP service from each application to provide status information making it easy for 3rd party monitoring tools to detect failures.
This will be an SMPP client app (or ESME app I guess) which is why I’ve chosen Java as it seems to be a very mature platform for SMPP.
I assume you mean SMPP? If so then I see no reason why Java couldn’t do a good job. Our applications do a wide variety of HTTP, UDP, SMTP, JDBC, LDAP, and other protocols in real time. We use Jgroups at lot which accomplishes a complete authenticated, encrypted, network stack in Java.
What’s the best way to manage deployment of new builds? Just stop the daemon and replace the binary as quickly as possible and restart?
In terms of replacing a running binary on the fly, that it more complicated. We have VIPs up front and replace the binaries at our leisure. Our internal protocols are designed to failover. If you do not have a VIP then one thing to consider would be an orderly handoff. You boot the new jar and it talks to the application running the old jar when it is ready to bind to the new port. Then the old application unbinds and the new one binds immediately afterwards. Something like that.
Источник
Tool for creating a Java daemon service on Linux [closed]
Want to improve this question? Update the question so it’s on-topic for Stack Overflow.
Closed 7 years ago .
What is the best way to create a java application that can be run using ‘service’ on Linux? I was going to use the JSW available here, but cannot use the licence on that (licence is either GPL or it costs money as far as I can tell). I’d need an apache style licence.
I’m using maven to build, so it would be great if it was possible to create the service using a maven plugin, but any other suggestions would be great.
I’ve seen Apache Commons Daemon, is there a maven plugin for this? Documentation seems sparse, so a working example of this would be good.
3 Answers 3
Services on Linux are just shell scripts which start background processes. Have a look in /etc/init.d — you can open the files in a text editor. All you need is a bash script which responds to the parameters start and stop in an appropriate way (eg. start will start your service and record the process ID in a known location, stop will kill the process with the PID from the file you created), and then place it in /etc/init.d .
As far as I know there isn’t a Maven plugin for either Apache Daemon or Akuma. Though you could attempt to invoke them from within a Maven build by using the maven-exec-plugin.
As far as your companies reservations about using GPL-licensed products, it’s worth reading up on the implications of use. It is not as virulent as corporations fear. Here’s an interpretation of the GPL. It of course doesn’t carry any weight in law (and may not be correct or supported by precedent, I am not a lawyer), but might be sufficient to allow you to start a conversation with your legal people.
From the referenced page:
Simply combining a copyrighted work with another work does not create a derivative work. The original copyrighted work must be modified in some way. The resulting derivative work must itself «represent an original work of authorship.» So if the licensee does not modify the original GPL-licensed program, but merely runs it, he is not creating a derivative work.
There is the Appassembler Maven plugin that I think does what you need (though it does create JSW wrappers). It creates a shell script (and a bat file), and collects all the application jars into a directory. It can optionally be configured to create JSW-based Daemon configurations.
Here is an example configuration that will generate the standalone application in the target/appassembler folder, and generate the JSW wrapper files in the target/appassembler/jsw/myApp directory. Note the assemble goal is bound to the integration-test phase to ensure the project’s jar is created. To generate the output run mvn verify or to just generate the service wrappers run mvn package:
For reference the generated files are as follows:
Источник