I have checked some of the Java RMI examples. But none of them demonstrate how to recover from a potential server failure, or a RemoteException, which might be thrown from the remote interface we define. And I couldn't find any relevant information either.
For instance,
public static void main(String[] args)
{
try
{
Server server = new Server();
Hello stub = (Hello) UnicastRemoteObject.exportObject(server, 0);
Naming.rebind("rmi://localhost/Hello", stub);
System.out.println("Server is up.");
}
catch (RemoteException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (MalformedURLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
After the exception is caught, the server just exits. Is here the intent for the server to die when such exceptions are thrown? Can we recover from such failures, like restarting the server? But how?
Thank you,
-----------Updates----------
To clarify, initially, I thought the RemoteException specified in the remote interface might be caught here. But after some experiments, I find they will actually show up on the client side and should be handled by the client.
Your RMI server only throws that exception at initialisation / start-up in UnicastRemoteObject.exportObject or Naming.rebind. The chances are that any error here isn't recoverable simply by running a loop to perform the same action again. There is some other problem to investigate.
If you server gets past the exportObject/rebind you see the "Server is up" message, the execution passes through the catch block and main(String[] args) ends normally. Even the thread handling [main] probably ends here.
But, the JVM process does not exit as there are non-daemon threads running. Any exceptions in the server are not passed back to the catch(RemoteException e) block shown in your main because main() has ended already.
In live systems I've observed several measures used by developers to counter issues found with RMI servers:
server startup scripts use limited loop to retry startup if it dies (this is more effective if it dies after long period not if fails instantly)
periodic round trip rmi client to server calls with trivial operation to prove RMI server health
run multiple instances of rmi servers with deliberate shutdown restart cycles at different time to ensure 100% operation
process monitors on rmi servers => trigger alerts for manual intervention
Most importantly you need effective logging so you can diagnose why it died afterwards.
Related
I'm writing a program that enables UDP communication between a KUKA robot (programmed in java) and a python server running on a PC. The program on the robot needs to run multiple methods concurrently because it needs to listen/receive messages on 3 sockets simultaneously (they all need to be listening for messages at all times).
I first tried this using multi-threading. My main class is DP_UDP_COMM which start running when the robot is started. When starting some initialization between the robot and python server is done to set up the socket connection, after that the communication processes need to be started. An example of 1 of these 'communication' threads is shown below as Thread UDP_COMM:
//DP_UDP_COMM class is the main class that gets started when the robot starts
public class DP_UDP_COMM extends RoboticsAPITask {
//Some code here
//One of the communication processes that needs to run while the DP_UDP_COMM instance is active
public Thread UDP_COMM = new Thread(new Runnable(){
public void run(){
while(running){
_log.info("Thread Started, Waiting for Action");
try {
ReceiveUDP();
_log.info("Buffer received is: "+String.valueOf(receive));
_log.info("Type received is: "+String.valueOf(ByteProcess.getType(receive)));
if(status==0)
processPacket(receive);
} catch (Exception e) {
// TODO Auto-generated catch block
send = createPacketResponse("ERROR: "+e.getMessage());
try {
SendUDP(send);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace(); }
e.printStackTrace();
}
}
}
});
UDP_COMM.start();
//Some code and other methods here
}
This thread tries to receive a UDP message from a socket using ReceiveUDP(). This is a blocking method so it keeps waiting here untill it receives a message. This message is then processed using processPacket(), which is a method that sends a command to the robot determined by the message that was received. After sending the command it starts listening again for new messages. This loops indefinitely when the robot is active.
The other threads are very similar but use slightly different methods which are bound to different sockets.(For example ReceiveUDPEmergency() which is the same as ReceiveUDP() but with a different socket)
This is working well with one thread, but when running 3 threads concurrently it doesn't work anymore because the threads will wait for each other to complete before looping because ReceiveUDP() is a blocking method.
The solution for this (I think) is to use multi-processing instead of multi-threading because this truly runs them in parallel instead of sequentially.
However when looking at the java.lang.Process documentation I really don't get how creating a process works. In every example they create/start a process from an external .exe file or something like that.
Is it possible to create multiple processes that run multiple methods in parallel within my DP_UDP_COMM instance? How would I do this?
//What have I tried:
As explained above I tried multi-threading at first. But this isn't good enough.
With multi-processing it is not clear how to start a process which just runs a method in parallel to the main instance.
I have a Docker container with a Java application that uses a DB to persist some data. My application has a class that extends another one that is not code of mine (specifically SinkTask, a class from Kafka that is used to transfer data from Kafka to another system). When the application starts it opens a connection to the database. Sometimes, the database closes the connection and tasks start to fail. The exceptions thrown by these failures are catched in one part of my code and I can think of different ways to handle them:
1. Simply executing the code from within the application that stops and starts the connection again
2. Restarting the Docker container, creating a new connection in the process
I think the best solution is number 1. However, I wanted to know how could I trigger the second situation. My guess is that I should throw a new Exception in the catch block capable of terminating the application (remember that the SinkTask part of the code is out of my control). Would this be a good solution? Which kind of Exception should I throw in this case?
This is the part of the code where I catch the exception
private void commitCollections() {
for (SinkCollection sc : collections.values()) {
try {
commitCollection(sc);
} catch (Exception e) {
LOG.error("Error flushing collection " + sc.getTableName(), e);
}
}
transactionRecordCount = 0;
try {
connection.commit();
} catch (SQLException e) {
LOG.error("Commit error", e);
}
}
Throwing an Exception and letting it propagate in order to terminate the application is a perfectly nice solution. IMO, using System.exit(exit_code) would be better because it clearly describes what that code is doing.
In addition, docker will display the exit_code in the status of the container (docker ps -a), thus helping differentiate between different error conditions. When an uncaught exception is thrown the exit code is always 1.
Hope that helps.
I am using javax.jms.Connection to send and receive JMS messages to/from JBoss501. I am also using the Connection.setExceptionListener(). I would like to know if the exception listener needs to be set before the connection is started by Connection.start()? Any ideas to reproduce the JBoss connection exception at will to confirm if the exception listener is invoked.
From the spec:
If a JMS provider detects a serious problem with a Connection object, it informs the Connection object's ExceptionListener, if one has been registered. It does this by calling the listener's onException method, passing it a JMSException argument describing the problem.
An exception listener allows a client to be notified of a problem asynchronously. Some connections only consume messages, so they would have no other way to learn that their connection has failed.
Remember that there is place for vendor specific implementation here, about how exceptions are handled. Some vendors try to "fix" the situation if possible.
Now about start the connection before or after setting the exception listeneer...
Always set the exception listener BEFORE starting the connection.
And About reproducing I think you could
Start a consumer, connection.start should be run. And waiting for a message.
Shutdown jboss immediately.
Restart jboss.
Also I know that using Eclipse or other dev tools will help you start in debug mode, and you can at any specific time as the debugger shows you the status just abort the jboss server and restart it again.
With Jboss 5.0.1, setting the exception listener worked even after starting the connection. As mentioned by "MrSimpleMind" exception listener serves better before starting the connection - in fact - best as soon as the connection is created from ConnectionFactory.
The exception listener is effective even if the connection is not started - in case of Jboss 501.
//Main
try {
connection = getConnection();
connection.setExceptionListener(new MyExceptionListener());
//Exception listener is effective even before connection is started.
//connection.start();
while(true){
try {
Thread.sleep(1000 * 5);
Log.l("Kill the JMS provider any time now. !! Observe if the JMS listener works.");
} catch (InterruptedException e) {
//do nothing.
}
}
} catch (NamingException e) {
e.printStackTrace();
} catch (JMSException e) {
e.printStackTrace();
}
//Exception Listener
public class MyExceptionListener implements ExceptionListener {
#Override
public void onException(JMSException e) {
Log.l("Exception listener invoked");
}
}
To reproduce the scenario where the ExceptionListener gets triggered/invoked, I used the JBoss Management console and stopped the ConnectionFactory using the mx bean exposed by Jboss mgmt console.
I'm writing a Java client-server application that uses RMI for communication. My problem is that for some reason, the RMI server just shuts down with no exception or error, on its own. I'm using Netbeans and I ran a profile to look at the threads.
You can see in the attached image the point in time where the application supposedly finished executing as the end of the GC Daemon and the RMI Reaper threads. However, even after the application ended, the RMI TCP Accept-1099 thread is still running. The part that confuses me even more is that after the Information message popped up (you can see it in the screenshot) telling me that the server has stopped, the threads continue to be updated in the diagram so I tried to connect with the client again. Although it failed, I can see a new RMI thread being created (connection 18).
I have no idea how to debug this issue, and I can't figure out how it is possible for the application to exit when the RMI accept thread is still running.
Update: Here is the server's main method:
/**
* Main entry point.
*
* #param args the application arguments - unused.
*/
public static void main(String[] args) {
try {
System.setProperty("java.rmi.dgc.leaseValue", "30000");
sServerProperties = new ServerProperties();
System.setProperty("java.rmi.server.hostname", sServerProperties.
getRmiServer());
createRmiRegistry();
ConfigCore configCore = new ConfigCore();
ServerCore server = new ServerCore(configCore);
LoginHandler loginHandler = new LoginHandler(server);
sRegistry.
bind(Login.class.getSimpleName(), loginHandler.getRemote());
Logger.log(Level.INFO, "Server ready!");
} catch (RemoteException ex) {
Logger.log(Level.SEVERE, "Unable to start RMI registry", ex);
} catch (SQLException ex) {
Logger.log(Level.SEVERE, "Unable to connect to the MySQL server",
ex);
System.err.println(ex.getMessage());
} catch (IOException ex) {
Logger.log(Level.SEVERE, "Unable to load or write properties file",
ex);
System.err.println(ex.getMessage());
} catch (AlreadyBoundException ex) {
Logger.log(Level.SEVERE, "RMI port already bounded", ex);
} catch (NoSuchAlgorithmException ex) {
Logger.log(Level.SEVERE, "Unable to digest password", ex);
}
}
/**
* Creates the RMI registry.
*
* #throws RemoteException if the RMI registry could not be created.
*/
private static void createRmiRegistry() throws RemoteException {
if (sRegistry == null) {
Logger.log(Level.INFO, "Creating RMI Registry...");
sRegistry = LocateRegistry.createRegistry(sServerProperties.
getRmiPort());
}
}
You're seeing an interaction of the VM exiting when its last non-daemon thread exits, combined with HotSpot garbage collection behavior, RMI's exporting behavior, and running the JVM under the NetBeans profiler.
The main thread exits after the main() method returns. However, you've exported an RMI server object, so RMI keeps the JVM alive by running the "RMI Reaper" thread (non-daemon) as long as there are live, exported objects. RMI determines whether an exported object is "alive" by keeping only a weak reference to it in it object table.
Unfortunately, from looking at the main() method, it appears that your RMI server object is only referenced via local variables. Thus, it will get garbage collected sooner or later, but for the weak reference to it in RMI's object table. When the object becomes weakly reachable, the RMI Reaper unexports it and exits. Since the RMI Reaper is the last non-daemon thread, the JVM exits.
Note that the RMI registry is treated specially. Exporting a registry will not keep a JVM alive.
Note also that putting an infinite loop at the end of the main() method will not necessarily prevent the RMI server object from being unexported and GC'd. The reason is that objects are subject to GC when they become unreachable, and a reference being present in a local variable of an active method is not sufficient to make it reachable. See my answer to another question on that topic. Of course, putting an infinite loop into main() will prevent the JVM from exiting, since it keeps the main thread alive, and the main thread is not a daemon thread.
To prevent your RMI server from being unexported, it's usually sufficient to store a reference to it in a static field.
Now, why does the JVM stick around when run under the profiler? That's just an artifact of the way the profiler works. The profiler detects that the last non-daemon thread has exited (other than additional threads running in the JVM on behalf of the profiler), so that's when it pops up the dialog that says "The profiled application has finished execution." It keeps the JVM alive, though, so you can continue to get data from it; this has the side effect keeping all the daemon threads alive. You've exported a registry, so that keeps listening on port 1099. When the JVM is in this state you might still be able to register RMI objects if you tried. Your RMI server object has long since been unexported and GC'd, so requests to it won't work. But that's why the RMI connection was still accepted when the JVM was in this state.
Bottom line is, make sure your RMI server objects don't get GC'd. A good way to do this is to make sure they're reachable from a static field.
This is a common problem with RMI. You need to save the reference to your implementation as a class field so it doesn't get GC. And you need to keep that class (with the main()) alive as well.
I use this as a never-ending keep alive:
for(;;) LockSupport.park();
You can do anything you like so the implementation remains alive and the class with the main() stays alive.
I have a small Java program that reads list of IPs from text file and inside a loop it create ssl session with the ip. The session might succeed or fail depend whether the port 443 is enabled in the other side or not.
My problem:
1. If port 443 is not enabled in the other side, the session will fail. The problem is that my program stops here and go to exception handling and print me the error and ends. I want the program to continue creating the next session with the next IP and so on. How can I make it continue and print out a message saying that the session failed for that IP?
Another issue: How can I get the enabled cipher suite? I tried to print socket.getEnabledCipherSuites(); but printed strange text not a type of cipher suite at all.
EDIT:
public static void main(String[] argv) {
try{
while ((there are IPs)
{
try{
//call for Connect function which has try/catch on it the same way
}catch (Exception e){
System.err.println("Error: " + e.getMessage());
}//catch
}//end while loop
catch (Exception e){
System.err.println("Error: " + e.getMessage());
}//catch
}//end void main </i>
your point #1 seems to be something exception handling should take care of: enclose each iteration on all_ips within its own try/catch block.
You could greatly benefit from some multithreading and time-out here, as some firewall will just drop your SYN packet silently and let your scanner tool wait indefinitely.
BUT before you do that, take care: you're going to look very much like a malicious tool scanning a network for some vulnerabilities. You may get into administrative trouble if you're too aggressive or target someone you don't know. A pool of thread or some similar technique to ensure you're not exceeding fair amount of connection establishment/second is a bare minimum.