Shutdown service after the service has done its job - java

I am creating a service which watch for a file and as soon as file is available it loads it to db. Once this job is done I want to shutdown the app gracefully.
But when I use context.close it throws exception (though the app shuts down) but I want to shut it down without causing any exception.
#profile("non-test")
class Manager implements ApplicationContextAware{
#PostConstruct
public void init()
{
//watch for file and as soon as file is available invokde trigger()
}
public void trigger()
{
//load to db
shutodown()
}
public void shutdown()
{
SpringApplication.exit(context);
}
}
when i call shutdown it throws below exception.
AnnotationConfigApplicationContext has already been closed
I want the app to shutdown gracefully without any exception.

You problem is most probably presence of Spring dependency that makes your app long lived. Such dependency is for example spring-boot-starter-web. This starter includes Servlet container as dependency ans Spring will by default be running forever.
If non of such dependencies is on classpath, your Spring Boot app would shut down automatically (without any special effort to kill it). I would suggest to take a look at some of Spring guides for batch job.

Related

How to save jpa entities on application shutdown?

I have a service which handles CRUD operations for entities using H2 database. Previously during testing phase I used to have a csv file which "acted" as a database and upon application shutdown I saved all in-memory changes to entities to this csv file. Now I want to do the same, but for some reason I am not hitting any breakpoints in my onExit() method and therefore not saving data on application shutdown. I am still working out proper logic for selecting which entities to save, but for now I just want to be able to automatically save when I press Stop 'Application' button in Intellij.
#Component
public class MangaDataProvider {
private static MangaService mangaService;
#Autowired
public MangaDataProvider(MangaService mangaService) {
MangaDataProvider.mangaService = mangaService;
}
#PreDestroy
public static void onExit() {
mangaService.saveAll();
}
}
And then I have a onExit() method in Application:
#SpringBootApplication
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {
public static void main(String[] args) {
LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
}
#PreDestroy
public void onExit() {
MangaDataProvider.onExit();
}
}
There is no guarantee that the shutdown hooks will be executed. They have a very limited time to execute. That means you code may be partially executed. You can try to add a Print statement, or a debug breakpoint. You will observe that the first statement is executed because it's super fast, but there is no time left to execute the rest of the method.
I good practice would be to call a service or an endpoint which "prepares" (in your case, it will persist your data) your application for shutdown. You call this service/endpoint then, when execution completed, you can safely terminate the application.
Many server application have a "prepare for shutdown" endpoint. Per example Jenkins ;)

Spring do on startup ingnoring failures

I need to perform some work when the spring application is ready, something similar to #Scheduled but I want it to perform only once.
I found some ways to do it, such as using #PostConstruct on a bean, using #EventListener or InitializingBean, however, all of these ways does not match my need. If during the execution of this logic something goes wrong, I want to ignore it so the application starts anyway. But using these methods the application crashes.
Of course, I can surround the logic with try-catch and it will work. But, is there any more elegant way?
We faced a similar issue with our microservices , in order to run code just after startup we added a Component.
ApplicationStartup implements ApplicationListener<ApplicationReadyEvent>
Within the application to make a call to the services just after application startup, this worked for us.
#Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
#Autowired
YourService yourService;
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent: application is up");
try {
// some code to call yourservice with property driven or constant inputs
} catch (Exception e) {
e.printStackTrace();
}
}
}
When you use #PostConstruct for implementing a logic, the application is not ready yet, so it kind of contradicts your requirement. spring initializes the beans one by one (with respect to the dependencies between them.
After all it builds up the application context.
When the application context is fully initialized, spring indeed allows listeners to be run. So The listeners is a way to go - when the listener is invoked the application is ready.
In both cases (PostConstruct, EventListener) as long as you're not using try/catch block the application context will fail, because it waits till all the listeners will be done.
You can use #Async if you don't want the application context to wait for listeners execution. In this case the exception handling will be done by the task executor. See here
Personally I don't see any issue with try/catch approach
You can use #PostConstruct (as you said) but you must wrap your business in try catch and ignore it when it throws an exception.
Sample Code
#PostConstruct
void init() {
try {
//Your business
}
catch (Exception e) {
//Do nothing Or you can just log
}

Spring Boot: How do I know if an Application was interrupted in #PreDestroy Method

I there any way to find out if the #PreDestroy Method in a Spring Boot Application was called because CTRL-C was pressed or kill <PID> was called?
I want to differ from the case that the Application regularly stops. (No Daemon, No Web Server)
Background:
I'm using Spring Boot as an Runner that is started in a Docker Container by a schedule. The App does it work and closes itself. The kill <PID> occurs when docker stop <containerid> is called.
You can write your own aspect to log any #PreDestroy execution
#Aspect
#Component
public class CustomAspect {
#Around("#annotation(javax.annotation.PreDestroy)")
public Object logPreDestroyExecution(ProceedingJoinPoint joinPoint) throws Throwable {
// ...
// get info from joinPoint and log
// ...
return joinPoint.proceed();
}
}
More detailed example: Spring AOP + AspectJ

Stop ConcurrentTaskScheduler when spring context closed

I am writing a simple spring application with AnnotationConfigApplicationContext. I have a ConcurrentTaskScheduler in my application. What is the best practice for stopping the ConcurrentTaskScheduler when the spring context closed?
Update: The main problem is when Junit close the context in #After annotation all threads will be terminated but when i manually close the context at the end of application, Some threads running by ConcurrentTaskScheduler will continue running.
Let Spring handle the shutdown itself.
Pass a ScheduledExecutorService to your ConcurrentTaskScheduler.
Than add a method with anotation #PreDestroy in which shutdown the ScheduledExecutorService.
#PreDestroy
public void cleanUp() throws InterruptedException {
scheduleExecutorService.shutdown();
try {
scheduleExecutorService.awaitTermination(10000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
scheduleExecutorService.shutdownNow();
throw e;
}
}
What I do in my project is, I save the jobs in the database so I can have a control over it, so in the future I can just grab the information from it and stop.
How to manage/stop spring 4 ConcurrentTaskScheduler

Simple Arquillian test to start and stop deployed app

I'm trying to wrap my head around Arquillian and perhaps even start using it in my project. I have a simple Java web app that deploys as a WAR to Tomcat.
In my project, I define a ServletContextListener impl so that I can execute code when Tomcat starts and stops the application.
I'm trying to write a super-simple Arquillian test class that uses ShrinkWrap and:
Confirms that my bundled WAR can be deployed to Tomcat and started without throwing exceptions; and
Can access a simple system property once the app is running (that the ServletContextListener checks for); and
Confirms that when Tomcat shuts down, no exceptions are thrown (clean shutdown)
Also, my class that implements ServletContextListener is called AppLifecycleManager:
public class AppLifeCycleManager implements ServletContextListener {
private String logLevel;
// Injected by Guice, but that's not really relevant for this question.
#Inject
private Logger logger;
// Getter and setter for logLevel and logger
#Override
public void contextInitialized(ServletContextEvent event) {
logLevel = System.getProperty("log.level");
}
#Override
public void contextDestroyed(ServletContextEvent event) {
logger.info("Peacefully shutting down the application.");
}
}
So far, here's my best attempt:
#RunWith(Arquillian.class)
public class MyFirstRealIntegrationTest {
#Deployment
public static Archive<?> createDeployment() {
// Haven't figured this part out yet, but for the sake of
// this question lets pretend this returns a properly-packaged
// WAR of my web app, the same that my Ant build currently produces.
}
#Test
public void shouldBeAbleToStartTomcatWithoutExceptions() {
// Given
Archive war = createDeployment();
// When - deploy war to Tomcat container
try {
// ??? how to access/init a Tomcat container?
TomcatContainer tomcat = new TomcatContainer(); // this is wrong
tomcat.start();
} catch(Throwable throwable) {
// Starting the container should not throw exceptions
Assert.fail();
}
}
#Test
public void shouldBeAbleToStopTomcatWithoutExceptions {
// Same setup as above test but stops tomcat and checks for
// thrown exceptions. Omitted for brevity.
}
#Test
public void shouldHaveAccessToSysPropsOnceRunning() {
// Here, deploy to the container and start it.
// Then, confirm that AppLifecycleManager correctly read
// the log.level system property.
// Given
Archive war = createDeployment();
TomcatContainer tomcat = new TomcatContainer();
// When - AppLifeycleManager should now read the system property
tomcat.start();
// Then - make sure log.level was set to "DEBUG" and that it was
// correctly read by AppLifeCycleManager.
Assert.assertTrue(war.getClass(AppLifeCycleManager.class)
.getLogLevel().equals("DEBUG"));
}
}
So, given my approach here, I immediately have several problems:
I'm not sure how to access/instantiate my Tomcat container so that it can even be started/stopped
I'm not sure how to actually execute tests from inside my running/deployed web app. In the 3rd test above I used war.getClass(AppLifeCycleManager.class).getLogLevel() to try and get access to a "live" class instance and check its logLevel property's runtime value, but I know this is wrong.
So I ask: how would a battle-worn Arquillian veteran write these 3 simple tests, and how do I actually go about performing tests on my "running" web app from inside the JUnit test? Thanks in advance.
I dont't think you should handle the startup/shutdown of tomcat in your test. I would by much easier if you used the embedded tomcat container: https://docs.jboss.org/author/display/ARQ/Tomcat+7.0+-+Embedded. In this case, arquillian will handle the startup and shutdown of tomcat.
You should create the deployment in the method annotated with #Deployment. Just read the following guide: http://arquillian.org/guides/getting_started/
You're almost there. createDeployment manages the lifecycle of your embedded container for you (starts and stops the virtual container automatically). That way, you're just focussing on the tests themselves. To write your integration tests, there's no "framework" or "Arquillian API" to code against. You just call classes and methods the way your main code does.
The key thing here is: your tests are actually running inside the container. If an exception occurs, or if your assert fails, the Arquillian runner throws an exception and stops the container. For your code example, where you're testing to see if you can read a system property:
#RunsWith(Arquillian.class)
public class MyArquillianTest {
#Deployment
public Archive<?> createDeployment() { ... }
#Test
public void shouldBeAbleToReadSysPropAtStartup() {
Assert.assertTrue(System.getProperty("log.level") != null);
}
}
Remember, Assert.assertTrue(System.getProperty("log.level") != null) Arquillian is "transporting" your code inside the container you configure it for. So that assert is actually running inside your deployed container.

Categories

Resources