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.
Related
I am getting below error in my PROD environment. Some DB call is working fine but some call is throwing exception due to package is discarded/state is invalidate and many reason. But I don't have control to re-compile package. i.e i have only read-only access. I am using Java8, JDBI and Oracle database with connection pooling.
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "USER.PKG_MY_PACKAGE" has been invalidated
ORA-04065: not executed, altered or dropped package body "USER.PKG_MY_PACKAGE"
ORA-06508: PL/SQL: could not find program being called: "USER.PKG_MY_PACKAGE"
ORA-06512: at line 34
I would like do to re-try options(2 times) by handle this exception in catch block and re-try from catch block. I referred many forums, connection has old compiled stored procedure or state of object as dirty. So, If I re-try with fresh connection for 3 times i may not get this error. Please suggest me fresh connection will work or fresh session will work. I am going to try this below
public void callDB(int userName, int retryCount) throws Exception {
try(Handle handle = dbInstance.open()) {
OutputParameters parameters = handle.createCall(MY_STORED_PROC).bind(0,userName).bind(1,Oracle.CURSOR);
Employee employee=parameters.getObject(2);
} catch(Exception e) {
logger.error(e);
if(retryCount!=2 && e.getMessage().contains("ORA-04068")) {
retryCount=retryCount+1;
callDB(userName, retryCount);
} else {
throw e;
}
}
}
I am getting from connection pooling via JDBI API. Please let me know this above code will work or not. Or Shall I need to re-try different way.
Also, suggest me when i re-try do i need create a new session or connection from connection pool is enough.
Hi i´m development and app with Netbeans Platform and i can´t catch this exception:
org.hibernate.exception.ConstraintViolationException
I use the follow line:
try {
il.delete(lote);
}
catch (HibernateException he) {
NotifyDescriptor error = new NotifyDescriptor.Message(ERROR+he.getMessage(), NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(error);
}
My interface may throw this exception, and the exception can be captured in the TopComponent. The problem is that I get twice, one is my notification and another from the platform.
How I can fix this?
In case of above code there is no possibility that you will receive exception twice. Because there is only one method call which returns exception.
What might possibility is you might be requesting it two times so that you are receiving exception multiple times.
What you can do is add a log check if method is being called multiple times on single click and fix that issue.
When I use 4 threads for my program there is usually no problems, but today I increased it to 8 and I noticed 1-3 threads stop working without throwing any exceptions. Is there anyway to find out why they are stopping? is there anyway to make the thread restart?
This is how the structure of my thread is
public void run()
{
Main.logger.info(threadName + ": New Thread started (inside run)");
while (true)
{
try
{
//all my code
//all my code
//all my code
}
catch(Exception e)
{
Main.logger.error("Exception: " + e);
try
{
Thread.sleep(10000);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
}
finally
{
try
{
webClient.closeAllWindows();
Thread.sleep(3000);
Main.logger.info(threadName + ": Closed browser!");
}
catch (Exception e)
{
Main.logger.error("Exception: " + e);
}
}
}// end while
}
Regards!
Note that an Error is not an Exception; it's a Throwable.
So, if you catch Exception, Errors will still get through:
private void m() {
try {
m(); // recursively calling m() will throw a StackOverflowError
} catch (Exception e) {
// this block won't get executed,
// because StackOverflowError is not an Exception!
}
}
to catch "everything", change your code to this:
try {
...
} catch (Throwable e) {
// this block will execute when anything "bad" happens
}
Note that there might be little you can do if an Error occurs. Excerpt from javadoc for Error:
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.
Is there anyway to find out why they are stopping?
That's a bit tricky.
A Java thread can terminate for two reasons:
it can return from its run() method,
it can terminate due to an exception being thrown and not caught on the thread's stack.
You can detect the latter case by using an "UncaughtExceptionHandler" for the thread, but the former case can't be positively detected unless you modify your thread's run() method to log the event ... or something like that.
I guess, the other way to figure out what is going on would be to attach a debugger to the JVM and get it to report the uncaught exception to you.
(I suspect that the reason you are not seeing any exceptions is that your threads' run methods are not catching / logging all exceptions, AND they don't have an uncaught exception handler.)
is there anyway to make the thread restart?
No. There is no way to restart a Thread that has terminated.
If you are running from the command line, you can have dump states of all threads to the console. On windows you do this by hitting Ctrl+Break, under linux, by sending the QUIT signal to the process with 'kill'.
Please refer to An Introduction to Java Stack Traces
Sending a signal to the Java Virtual Machine On UNIX platforms you can
send a signal to a program by using the kill command. This is the quit
signal, which is handled by the JVM. For example, on Solaris you can
use the command kill -QUIT process_id, where process_id is the process
number of your Java program.
Alternatively you can enter the key sequence \ in the window
where the Java program was started. Sending this signal instructs a
signal handler in the JVM, to recursively print out all the
information on the threads and monitors inside the JVM.
To generate a stack trace on Windows 95, or Windows NT platforms,
enter the key sequence in the window where the Java
program is running, or click the Close button on the window.
Thread priority on one of them could be too high, try setting them the same level through?
Deadlocking is possible if there is any control on each and other between them.
Historical Context: This problem ended up being not at all what I thought it was. The cause and solution are below, but the original posting is left for reference.
I'm developing a simple framework for periodically polling a directory for .properties files, then performing SQL queries and sending e-mails based on their configurations. Because each .properties file has the same spectrum of operations, they are all interpreted by the same Task class. But since they each represent different logical operations, they each get separate log files.
This is accomplished by sharing one instance of a log4j RollingFileAppender, and dynamically changing its output file based on a value in the .properties file. Since this is a single-threaded application, this works fine.
However, I've noticed that in certain situations, this RollingFileAppender will become closed, and the application will continue on obliviously except that now no logging takes place. I've only managed to catch this in action once, thanks to the console output, since usually this service is running as a background process on a Linux server. Here's what happened:
1) StartScheduler, the main class, creates a new instance of TaskPoller every minute.
2) TaskPoller scans the directory, loads a little information from each .properties file, and determines if it should be run. It also has its own separate RollingFileAppender, which it retrieves via Logger.getLogger(TaskPoller.class). If a Task should be run, then it instantiates a Task object, passing in the specific .properties file to be run.
3) Task gets its RollingFileAppender, then calls fileAppender.setFile("newtaskname.log") and fileAppender.activateOptions() to change the output file location. Then, during its execution, something like this happens:
[TaskPoller]
...
task = new Task(fileName); //Points RollingFileAppender to the right place
if (!task.Execute())
logger.warn(fileName + " returned with an error code."); //Succeeds
[Task.Execute]
...
try {
dbDAO.Connect();
} catch (Exception e) {
logger.fatal{"Database connection error.", e}; //Different RFA; Fails
return false;
}
[DBDAO.Connect throws SQLException, ClassNotFoundException]
...
try {
Class.forName(dbDriver); //Dynamically loaded jdbc driver class name
connection = DriverManager.getConnection(urlString, userName, password);
} catch (SQLException e) {
if (connection != null)
try { connection.close(); } catch (Exception e2) { ; }
throw e;
}
What's happening is that during DBDAO.Connect(), sometimes I'll get a com.mysql.jdbc.exceptions.jdbc4.CommunicationsException (or some other unexpected exception from whichever jdbc class is loaded). This will not be caught by Connect(), but it will be caught by Execute().
Somehow, this process causes Task's RollingFileAppender to become closed. The only thing I can think of that's special to this situation, as opposed to its consistent and stable normal operation, is that the exception being thrown isn't declared as thrown by Connect(). But I don't think that should cause a log4j Appender to close.
So my question is, what could be causing this appender to unexpectedly close in methods that have nothing to do with its configuration?
--Edit--
It looks like I've been misdirected entirely; the problem is somewhere in the interactions between Quartz, which I was using to have TaskPoller fire every minute, and log4j. I don't entirely understand its cause yet, but [this solution][1] seems to solve this problem. It just didn't manifest itself as an observed problem until now, so I thought it had something to do with what was happening recently.
The real cause of this problem is an interaction between the Quartz scheduler and the way I was using log4j. It turns out, if you modify log4j's properties (which I was doing by calling fileAppender.setFile(fileName) and fileAppender.activateOptions()) on a Quartz worker thread (even if Quartz is configured to only have a single thread running at a time), things break down. This is fixed by reloading the log4j properties on each new instance of the worker thread before using it, which I accomplished like so:
[Task() Constructor]
Properties props = new Properties();
URL url = ClassLoader.getSystemResource("log4j.properties");
try {
props.load(url.openStream());
PropertyConfigurator.configure(props);
} catch (Exception e) {
//The logger that never got renamed never stopped working.
Logger.getLogger(TaskPoller.class).error("Diagnostics!");
}
logger = Logger.getLogger(Task.class);
Jetty can be used as a library to embed a servlet-server into your application. To do that, you create an instance of the class Server and call start at some point. This method throws Exception. Catching or throwing a pure Exception (not a specialized subclass) is bad style. Does anyone know, how I can avoid this and get a Jetty-server in my application running without handling this general Exception?
Catching Exception is bad practice unless only Exception is thrown. There is no workaround for it. Catching distinct subclasses of Exception has the disadvantage of possibly missing out on some of them.
What is the meaning of Jetty failing to start in your application? You can have multiple approaches:
Decide at the component level that you should proceeed
try {
server.start();
reportingAvailable = true;
} catch ( Exception e ) {
log("Jetty failed to start. Reporting will we unavailable", e);
}
Treat it as a fatal exception
try {
server.start();
} catch ( Exception e ) {
throw new RuntimeException("Jetty failed to start", e);
}
Treat it as a recoverable exception
try {
server.start();
} catch ( Exception e ) {
throw new JettyFailedToStartException(e); // JettyFailedToStartException !instanceof RuntimeException
}
I would strongly advise you to handle it somehow.
If Jetty can't start (e.g. bind to its nominated port) then you're going to want to manage that somehow. At the very least log this so you know you don't have a web server running. Perhaps retry after a while ?
The point is that Jetty is unable to start and you should care about that.