Global method to prevent app from crashing? - java

I am trying to add a method in my parent activity that all my activities are inheriting from. I want the method to catch any errors that have not already been handled so the app does not crash. Instead of crashing it will redirect to a failure screen activity.
Here is what I have at the moment but it does not work, the app freezes and then goes black:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
redirectToFailureScreen();
}
});

The uncaught exception handler is not meant for rescuing an application. Ending up in that handler means the thread is being terminated. The handler gets notified as a courtesy for logging purposes before the thread is killed.
Implemented by objects that want to handle cases where a thread is
being terminated by an uncaught exception. Upon such termination, the
handler is notified of the terminating thread and causal exception. If
there is no explicit handler set then the thread's group is the
default handler.

Related

Spring Boot scheduler thread stops randomly

I have an Scheduler in spring boot that fulfils a specific business task every X minutes. It works fine until it suddenly stops and does not engage anymore. There is no exception in the logs or any other logs. I need to restart the program for the scheduler to work again.
Sometimes the task of the scheduler goes wrong, and I throw an exception. To be able to handle those exceptions specifically, I wrote a custom ErrorHandler in Spring for the scheduler that resolves a seperate task for logging purposes. It is linked correctly to the scheduler and processes the task.
This issue can come up when an unhandled exception gets thrown inside of an ErrorHandler. I am not sure about the specifics, however a Runtime Exception thrown by an ErrorHandler (or a method inside of it) that gets propagated outside of it basically kills the scheduled thread for that task. Furthermore NOTHING gets written to the logs (no Exception message, nada).
The "easiest" way to resolve this is by wrapping the entirety of the method in a try/catch block catching Exception - although depending on why you have that Error Handler that might be a bad idea. This does not solve the underlying issue at hand, but it keeps the thread alive and allows you to log the issue.
Example:
public class MyErrorHandler implements ErrorHandler {
#Override
public void handleError(Throwable t) {
try {
//handle intended exception (ex. write to database or logs)
} catch (Exception e) {
//handle exception that was thrown while trying to handle the intended exception.
}
}

How to get exception thrown during state transition using spring state machine

I am trying to understand, how an exception thrown by an action during a state transition is possible. I‘ve this simple state machine configured:
transitions
.withExternal()
.source(State.A1)
.target(State.A2)
.event(Event.E1)
.action(executeAnActionThrowingAnException())
In my service class, I injected my state machine and send this event E1:
#Service
public class MyService() {
#Autowired
private StateMachine<State, Event> stateMachine;
public void executeMyLogic() {
stateMachine.start()
stateMachine.sendEvent(Event.E1);
// how to get thrown exception here
}
}
In my service I just want to know, if and why my state machine wasn‘t able to reached State.A2. Because a thrown exception is fetched by Spring state machine, I am not able to get any response after sending the event. But the state machine hasn‘t any error, which means that
stateMachine.hasStateMachineError()
will return false. So, how can I get the information in my service, that something went wrong and more importantly what?
I appriciate your help.
Best regards
For transitions exceptions, there's an overload for the actions method available in the TransitionConfigurer
action(Action<S,E> action, Action<S,E> error)
This means you can specify and additional action to be triggered, if there's an exception raised during the transition. The exception is available from the StateContext passed to the action.
When your error action is triggered, you can retrieve the exception with:
context.getException();
Inside the error action you can do a couple of things to deal with the exception:
do logging of the exception and the context
transition to some error state
clear the context and transition to the same state and try to execute some retry logic
add some additional info to the context and return the context to the caller
For example:
context.getVariables().put("hasError", true);
context.getVariables().put("error", ex);
And in your service(caller) you handle the exception as you like, for example:
public void executeMyLogic() {
stateMachine.start()
stateMachine.sendEvent(Event.E1);
if (stateMachine.getExtendedState().getVariables().containsKey("hasError") {
throw (RuntimeException)stateMachine.getExtendedState().getVariables().get("error")
}
}

How to prevent Spring app context shutdown until shutdown hook is fired

I have a spring-boot application.
I have implemented SmartLifecycle interface in my bean which starts async snmp server in it's start method and stops it in it's stop method.
All working fine, except the fact that main application context stops right after start, so my server bean also stops right after start.
All I need is to make spring context to stop only when shutdown hook is fired.
This is not a web application, so I don't need spring-boot-starter-web, which is solves this problem by starting webserver which prevents context stop until webserver stops.
I can use something like CountDownLatch and waiting for it to be zero in my main method right after context starts. Somethig like this:
public static void main(String[] args) throws InterruptedException {
ConfigurableApplicationContext ctx = SpringApplication.run(SnmpTrapRetranslatorApplication.class, args);
CountDownLatch snmpServerCloseLatch = ctx.getBean("snmpServerCloseLatch", CountDownLatch.class);
snmpServerCloseLatch.await();
}
And my server bean's start method will create this latch with count 1, while stop method will call snmpServerCloseLatch.countDown().
This technique is described here.
But what wrong with this is that my main method is responsible for waiting my custom server bean to stop. I feel this just not right.
How for example spring-boot-starter-web do this? When it starts tomcat, it keeps running until shutdown hook is received and it don't need to have any managing code in the main method. It stops only when context receiving shoutdown signal.
The same behaviour is for example when I have #Scheduled method in my bean. Spring also doesn't stops context automatically. Only on CTRL-C.
I want to achieve similar effect. My main method should have only one line: start the context. Context should start and stop my async server when it starts or stops (already achieved by SmartLifecycle) and should not stop until shutdown is requested (CTRL-C, SIGINT etc).
My investigation lead me to the core of the problem: daemon threads.
The snmp server implementation which I use (snmp4j) use daemon threads internally. So even when snmp server started, there are no more live user threads in JVM, so it exits.
TL/DR:
Just add this method to any bean (snmp server bean is good candidate for this):
#Scheduled(fixedDelay = 1000 * 60 * 60) // every hour
public void doNothing() {
// Forces Spring Scheduling managing thread to start
}
(Do not forget to add #EnableScheduling to your spring configuration).
Explanation:
To prevent stopping spring context, while SNMP server is still running, we need any non-daemon thread to be alive in JVM. Not necessarily main thread. So we can let main method to finish.
We can run new non-daemon thread from our server bean's start method. This thread will wait on some lock in while loop checking for some running variable, while our stop method will set this running variable to false and notifyAll on this lock.
This way, our non-daemon thread will be alive until shotdown hook is triggered (and prevents JVM to exit).
After shutdown hook, spring context lifecycle close method will call all SmartLifecycle bean's close methods, that will lead to SNMP server bean's stop method call, that will lead to set running to false, that will lead to our non-daemon thread to stop, that allow JVM to stop gracefully.
Or instead we can use Spring's scheduling thread in similar way. It also is non-daemon thread, so it will prevent JVM to exit. And Spring manages this thread itself, so it will automatically stop it when shutdown hook is triggered.
To make Spring's scheduling thread to start we need any #Scheduled method in any bean.
I think that first (manual) approach is still more "correct", while requires more async coding (which is error-prone as we all know). Who knows how Spring will change it's scheduling implementation in the future.
SpringApplication app = new SpringApplication(Main.class);
app.setRegisterShutdownHook(false);
ConfigurableApplicationContext applicationContext= app.run();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
#Override
public void run() {
//do your things
applicationContext.close();
}
}));

OSGi background thread failure

What should be done when a BundleActivator runs a background thread, and that background thread has an unrecoverable error?
public class Activator implements BundleActivator
{
private Thread t;
#Override
public void start(BundleContext context) throws Exception
{
t = new Thread(new Runnable(){
#Override
public void run(){
while (!Thread.interrupted()){
// do something which may throw a runtime exception
}
}
});
t.start();
}
#Override void stop(BundleContext context) throws Exception
{
t.interrupt();
t.join();
}
}
With this example, how can I notify the OSGi framework that the thread is dead and the bundle is effectively stopped and not running?
Look at how Peter Kriens performs similar actions in this article. All you would need to do with his example is invoke the stop on the activator in his catch block, instead of doing the printStackTrace.
Probably the best thing to do is just log the error, preferably to the OSGi Log Service. Then an administrator can detect the problem with the bundle and decide what to do. You should implement this as a Declarative Services component rather than as a BundleActivator, because that will give you much easier access to the Log Service, and you will also be able to have more than one of these things in your bundle.
I don't think that the bundle should attempt to stop itself. This puts the bundle in a weird state.... it's stopped but still has code running... i.e. the code that called stop(). This may be only for a brief period but it feels wrong.
A bundle that's in the ACTIVE state doesn't necessarily have to be "doing something" all the time, it just has the potential to "do something". The fact that something failed shouldn't really affect the external state of the bundle.
As far as I know, OSGi cannot directly help you in this particular situation. I usually rely on uncaught exception handlers to get notified of thread crashes or I implement some form of SW watchdog.
The point is that a bundle that spawns multiple threads and sucessfully completes its start method remains ACTIVE even if one of these threads crashes after some time.
Neil is (as usual) very right. A bundle should never stop itself since that interferes with the management agent. The start/stop is the message from this management agent to a bundle to say that it should be active. If the bundle cannot perform its responsibility you should log the message, wait a bit (increasingly longer) and retry.
The log is the place to notify, stopping a bundle is mixing levels badly.

Defining one global UncaughtExceptionHandler for all threads of my application

I want to define one application level UncaughtExceptionHandler in my Java application that is called if an uncaught exception is thrown in one thread of my application.
I know that is possible define an uncaught exception for a group of thread (ThreadGroup) and i'm actually using it, but i want to define a global uncaught exception for threads that don't have defined their own uncaught exception handler or that are not associated to a group of threads that have a default exception handler defined.
So for example i wanna reach something like this :
1° LEVEL ---> Call thread own UncaughtExceptionHandler ---> 2° LEVEL Call Thread Group UncaughtExceptionHandler ---> 3° LEVEL Call application(default) UncaughtExceptionHandler
In simple terms i want to override the default UncaughtExceptionHandler and define my own handler instead of print the stack trace on the System.err (that is the default behaviour).
For example in C# .NET i do something similar handling the unhandled and thread exception event handler in the Main() method of the application :
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Can be done even in Java ?
How can i override the default UncaughtExceptionHandler in Java ?
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler ex)
This should achieve what you are looking for.
As the doc says
Set the default handler invoked when a thread abruptly terminates due to an uncaught exception, and no other handler has been defined for that thread.
And an interesting note (also in the docs) regarding you using the handler in the ThreadGroup
Note that the default uncaught exception handler should not usually
defer to the thread's ThreadGroup object, as that could cause infinite
recursion.
You need to set the default uncaught exception handler. This is a static method on the Thread class called setDefaultUncaughtExceptionHandler. Doing this will do set the exception handler for the application running. It will be the default for any new threads unless otherwise specified.

Categories

Resources