I have a main java program which should launch other java programs in an own process using Runtime.exec(), e.g.
Runtime.exec("java -jar myapp.jar");
Is there a possibility to communicate with this new process, e.g. sending request, chaing fields...?
How can I shutdown this new created process? I think I get an handler back and thus can kill the process. But is there a nicer way?
If I kill the process, will the shutdownhook still be executed before the process is killed?
Runtime.getRuntime().addShutdownHook
Is there a possibility to communicate with this new process, e.g. sending request, chaing fields...?
You can communicate with the process through the Process object returned by Runtime.exec. Just use Process.getInputStream/.getOutputStream.
If you want to invoke methods on the other Java process you could look into RMI ("Remote method invocation"). Another option is of course sockets. See this related answer.
There's no straight forward platform independent way of changing fields of the other Java process.
If I kill the process, will the shutdownhook still be executed before the process is killed?
Depends on how you kill it, but typically, yes, the shutdown hooks will be executed.
Related
I'm interested in different approaches to gracefully shutting down a Java command line program. Sending a kill signal is not an option.
I can think of a few different approaches.
Open a port and wait for a connection. When one is made, gracefully shutdown.
Watch for a file to be created, then shutdown.
Read some input from the terminal, such as "execute shutdown".
The third one is not ideal, since there is often program output pumped to the screen. The first one takes too much effort (I'm lazy). Do most programmers use the second option? If not, what else is possible/elegant/simple?
you can try something like this:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { /*
my shutdown code here
*/ }
});
edit:
the shutdown hook will not perform the shutting down of the app. instead, it gives the developer a way to perform any clean-up that he/she wishes at shutdown.
from the JavaDoc for Runtime (a good read if you are planning to use this method):
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently. When all the hooks have finished it will then run all uninvoked finalizers if finalization-on-exit has been enabled. Finally, the virtual machine will halt. ...
you could try to use Runtime.getRuntime().addShutdownHook() that should satisfy your requisite. In this way you can register an hook to do cleanups, in order to perfom a gracefull shutdown.
EDIT
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread)
public void addShutdownHook(Thread hook)
Registers a new virtual-machine shutdown hook.
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
The benefit of the second option - checking for a file - over the first - listening on a port - is that you have some possibility of security.
You can set the permissions on the directory where the file is created so that only appropriate users can close the program. If you listen on a port any user can connect to it.
If you wanted to go with the socket version, it is very simple to implement. Here's the code:
ServerSocket server = new ServerSocket(8080);
System.out.println("Socket listening!");
server.accept();
System.out.println("Connection received!");
You could easily embed this code in a separate thread that you start with your program, and then have it modify global state to initiate shutdown.
The first two option is simple to implement. You could also use some JMX stuff (I don't know much about that). Tomcat uses the first approach and I applied 1 and 2 in two of my projects.
Consider having a JMX component. Then you can attach with JConsole either locally or over the network, and communicate with your component. Then the component can shut down the program properly.
With Java 6 u 10 or later, you can do the same with JVisualVM.
I would suggest to use the shutdown hook. It will allow your program do be controlled using standard OS tools. It also does not need any additional access to external resources (disk, ports, whatever).
From my java web application I am creating process object and after passing commands I am starting the process.
Along with the process start I am maintaining another thread which is keeping a look at the exit value of the current process.
Does this process.exitValue() causes the current thread to wait?
Updated Question:
Please can you give some information about why process.destroy() is able to kill gcc(for c and c++) , java processes, but while coming to c# programs running in mono these processes cannot be destroyed, why?
And can I get pid value from the Process object while running it in ubuntu server to kill the process by pid ?
To wait end of created process you can use Process.waitFor()
exitValue doesn't wait process termination. Moreover it will throw exception in case if process still in progress.
Currently I have slow starting java service in systemd which takes about 60 seconds until it opens its HTTP port and serves other clients.
Another client service expects this service to be available (is a client of the this service), otherwise it dies after a certain retry. It also started with systemd. This is to be clear also a service. But uses the former like database.
Can I configure systemd to wait until the first service has made his socket available? (something like if the socket is actually listens , then the second client service should start).
Initialization Process Requires Forking
systemd waits for a daemon to initialize itself if the daemon forks. In your situation, that's pretty much the only way you have to do this.
The daemon offering the HTTP service must do all of its initialization in the main thread, once that initialization is done and the socket is listening for connections, it will fork(). The main process then exits. At that point systemd knows that your process was successfully initialized (exit 0) or not (exit 1).
Such a service receives the Type=... value of forking as follow:
[Service]
Type=forking
...
Note: If you are writing new code, consider not using fork. systemd already creates a new process for you so you do not have to fork. That was an old System V boot requirement for services.
"Requires" will make sure the process waits
The other services have to wait so they have to require the first to be started. Say your first service is called A, you would have a Requires like this:
[Unit]
...
Requires=A
...
Program with Patience in Mind
Of course, there is always another way which is for the other services to know to be patient. That means try to connect to the HTTP port, if it fails, sleep for a bit (in your case, 1 or 2 seconds would be just fine) then try again, until it works.
I have developed both methods and they both work very well.
Note: A powerful aspect to this method, if service A gets restarted, you'd get a new socket. This server can then auto-reconnect to the new socket when it detects that the old one goes down. This means you don't have to restart the other services when restarting service A. I like this method, but it's a bit more work to make sure it's all properly implemented.
Use the systemd Auto-Restart Feature?
Another way, maybe, would be to use the restart on failure. So if the child attempts to connect to that HTTP service and fails, it should fail, right? systemd can automatically restart your process over and over again until it succeeds. It's sucky, but if you have no control over the code of those daemons, it's probably the easiest way.
[Service]
...
Restart=on-failure
RestartSec=10
#SuccessExitStatus=3 7 # if success is not always just 0
...
This example waits 10 seconds after a failure before attempting to restart.
Hack (last resort, not recommended)
You could attempt a hack, although I do not ever recommend such things because something could happen that breaks such... in the services, change the files so that they have a sleep 60 then start the main process. For that, just write a script like so:
#!/bin/sh
sleep 60
"$#"
Then in the .service files, call that script as in:
ExecStart=/path/to/script /path/to/service args to service
This will run the script instead of directly your code. The script will first sleep for 60 seconds and then try to run your service. So if for some reason this time the HTTP service takes 90 seconds... it will still fail.
Still, this can be useful to know since that script could do all sorts of things, such as use the nc tool to probe the port before actually starting the service process. You could even write your own probing tool.
#!/bin/sh
while true
do
sleep 1
if probe
then
break
fi
done
"$#"
However, notice that such a loop is blocking until probe returns with exit code 0.
You have several options here.
Use a socket unit
The most elegant solution is to let systemd manage the socket for you. If you control the source code of the Java service, change it to use System.inheritedChannel() instead of allocating its own socket, and then use systemd units like this:
# example.socket
[Socket]
ListenStream=%t/example
[Install]
WantedBy=sockets.target
# example.service
[Service]
ExecStart=/usr/bin/java ...
StandardInput=socket
StandardOutput=socket
StandardError=journal
systemd will create the socket immediately (%t is the runtime directory, so in a system unit, the socket will be /run/example), and start the service as soon as the first connection attempt is made. (If you want the service to be started unconditionally, add an Install section to it as well, with WantedBy=multi-user.target.) When your client program connects to the socket, it will be queued by the kernel and block until the server is ready to accept connections on the socket. One additional benefit from this is that you can restart the service without any downtime on the socket – connection attempts will be queued until the restarted service is ready to accept connections again.
Make the service signal readiness to systemd
Alternatively, you can set up the service so that it signals to systemd when it is ready, and order the client after it. (Note that this requires After=example.service, not just Requires=example.service! Dependencies and ordering are orthogonal – without After=, both will be started in parallel.) There are two main service types that might make this possible:
Type=forking: systemd will consider the service to be ready as soon as the main program exits. Since you can’t fork in Java, I think you would have to write a small shell script which starts the server in the background and then waits until the socket is available (while ! test -S /run/example; do sleep 1s; done). Once the script exits, the service is considered ready.
Type=notify: systemd will wait for a message from the service before it is considered ready. Ideally, the message should be sent from the service PID itself: check if you can call the sd_notify function from libsystemd via JNI/JNA/whatever (specifically, sd_notify(0, "READY=1")). If that’s not possible, you can use the systemd-notify command-line tool (--ready option), but then you need to set NotifyAccess=all in the service unit (by default, only the main process may send notifications), and even then it likely will not work (systemd needs to process the message before systemd-notify exits, otherwise it will not be able to verify which cgroup the message came from).
I use Amazon EC2 instances to perform some complex computation by using the AWS Java SDK, these computations might take so long sometimes. Hence, I need to kill the process running on the EC2 instance remotely from my Java code so that I can reuse the same instance for another task without needing to stop and start the instance.
The problem with stop and start, is that Amazon treat partial hours as complete hours, so my aim is to make my code more cost effective.
I use SSH to connect with my EC2 instances and that is how I pass commands to be executed there. I doubt that if I disconnect the SSH connection and connect to it again, it would kill whatever process was running there.
In short, what I need is away of doing Ctrl+C but from within my Java code (without user intervention). Is that possible?
EDIT:
To clarify, the computation is executed by a separate tool installed on the Linux EC2 instance. So I just pass the command to start this tool, then the command line waits until its finished and shows the results. On manual usage scenario, I can click Ctrl+C on linux command line and will get control of the command line back. But in my case, I want to do similar thing from java code if possible.
Use the SIGAR library to scan the process list on a machine and kill your process.
Use getProcList() to get all process IDs, getProcArgs() to get the full command line of each process, and kill() to kill the relevant process or processes.
So if a task is running and you want to kill it, SSH again into the machine and run your SIGAR based process killer.
One dirty/functional way would be to kill your process via SSH using the java Runtime to execute it.
Something like
Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec("ssh user#host command");
So in your case, if you know the program's PID (1234 for example):
Process p = runtime.exec("ssh user#host kill 1234");
Or if you know the program's name:
Process p = runtime.exec("ssh user#host pkill my_program_name_x64");
Note that you usually have to give absolute paths to the executables invoked via runtime.
So you'll have to replace ssh by something like /bin/ssh or /usr/bin/ssh as well as for kill and pkill or killall.
I have written a service for JIRA(a web application runs in tomcat) which runs periodically(say 1 hour). Basically, the service executes a system command thru runtime.exec(command) and parses the output generated by the command then updates a Lucene index with it, output will be huge.
The problems are:
1) If I shutdown tomcat with shutdown.sh while the above service is executing, the java(or the catalina) process is not getting killed. Both the java & child process are living for a while i.e., until the system command completes & service processes the output. But then the service fails to update the index leaving the index in an inconsistent state.
If I shutdown tomcat when the above service is not running, everything is good. I think, this is explained here. I am still not clear why JVM won't shutdown as the above service is running within tomcat?
Note that this is the only java app running on that machine.
2) Then, if I kill java using kill <pid>, both the java & child process are getting killed contradicting to this post.
Is this because the child process is sending output to parent(java) and once parent is killed, the child has no idea where to send the output and thus got killed ?
3) I tried to use shutdownhook as explained in this post, but that's not working for me. The code inside the shutdownhook is getting executed only after the java & child processes are done with their work. So, calling process.destroy() inside shutdownhook is not useful here.
This seems obvious, as the JVM is still running in my case, it won't call shutdownhooks until it starts it's shutdown sequence. Don't know how this worked for the other guy, I mean, how come the child process spawned by java is still running when JVM is down.
4) If I restart tomcat, new java process with different pid is generated.
Is it possible to stop the child process programmatically when tomcat is shutdown ?
Let me know if I am not clear with my explanation...
Here is the code that executes system command:
String command = getCommand();
File view = new File(viewPath);
Runtime runtime = Runtime.getRuntime();
try
{
final Process process = runtime.exec(command, null, view);
StreamReader errorStreamReader = new StreamReader(process
.getErrorStream());
Thread errorStreamThread = new Thread(errorStreamReader);
errorStreamThread.start();
revisions = parseRevisionLogs(process.getInputStream());
process.waitFor();
process.getInputStream().close();
process.getErrorStream().close();
process.getOutputStream().close();
}
The JVM will not shutdown unless the threads that are left are marked as "daemon". Any non-daemon user threads must finish before the JVM will exit. See this question. If your periodic tasks are not set with setDaemon(true) then they will have to finish before the JVM will exit. You have to call setDaemon before the process starts.
You should be able to make your periodic tasks to be daemon however you do have a race condition with JVM shutdown. You might consider having one daemon task doing the reading from the process but having a non-daemon task do the updating of the index which probably should not get killed while it is working.
Your non-daemon thread could then be sleeping, waiting for the load to finish, and testing to see if it should terminate with a volatile boolean field or other signal.
I'd suggest you to do the following.
Do not read the process' output directly from java. Instead redirect the output to file and read it from there when process is terminated. Wrap your command using batch file or shell script that stores the PID of separate process, so that you will be able to kill this process separately. Now add shutdown hook to tomcat that will run kill PID where PID is the process ID of separate process.
I believe this will work because now your tomcat and separate process are totally decoupled, so nothing bothers tomcat to shutdown. The same is about the process.
Good luck.
Are you doing a waitFor() on the process?
If so you could catch InterruptedException and to a p.destroy()