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 ;)
Related
I have to improve the atomicity of a process in a Spring Boot web application. The idea is the following:
class X {
#transactional
method a() {
b("STARTING") //Transactional method
try {
c() //transactional method
} except {
b("FAILED") //transactional method
}
}
}
#transactional
class Z {
b(status) {
//change status
}
c() {
//do stuff
}
// ... More transactional methods
}
I am working on class X, the problem is that when I call a() from another class to execute the whole transactional process, it only perform the changes from line 4, b("STARTING") and it completely ignores the rest. I am using Hibernate, so I cannot use NESTED propagation, I have tried some other things but I am not even sure why this happens, as I understand, default REQUIRED propagation setting should merge everything in a single transaction.
When I start the application in DEBUG mode, I can see how the code flows as it is expected, but at the end, when executing COMMIT, the transaction is incomplete. Any ideas?
I have some startup operations to be executed one after another. Both of these runners performs some heavy database operations.
#Slf4j
#Data
#Component
#Order(1)
public class MyFailureHandlerA implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
some_io_calls_a();
}
}
#Slf4j
#Data
#Component
#Order(2)
public class MyFailureHandlerB implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
some_io_calls_b();
}
}
I need to make sure that #Order(2) runner starts only after #Order(1) has finished it's processing.
Is there any way to achieve this, like registering the runners onto some strategies so that they can be monitored for their completion.
I found a way, like, I can go for waiting till the value of a singleton scoped bean variable turns true, which is set only when first runner finishes it's task. But I'm afraid if this is recommended or not.
Or, can I rely on #DependsOn for the task completion? Is is guaranteed that, by using #DependsOn("MyFailureHandlerA") over MyFailureHandlerB will guaranteee that 1st runner has completed it's entire operations?
Another way I was trying is, invoking the services call one after another from one single runner, like this:
#Slf4j
#Data
#Component
public class MyFailureHandler implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
some_io_calls_q();
some_io_calls_b();
}
}
Would this makes some sense and will ensure that ops are executed in order one after another?
spring-boot-2.3.2
some_io_calls_q();
some_io_calls_b();
If both your methods do synchronized tasks, then using order is enough.
Your command will be executed following the order annotation.
You can print few logs to check about it.
Otherwise, it's not enough with async task. You have to control when/how the task is completed...
The most simple solutions as you describe is calling both method in one commandlinerunner in case you are not sure the internal process of spring.
#DependsOn: only working with process creating bean. It's not relative the execution of commands.
I'm writing a #Repository/#Service integration test that leverages an embedded database. In my test class, I would like to preload my database with some data.
I'm currently using #BeforeEach to load in my sample data, however, this code is run upon each test in my class.
Is there any way that I can load in my test data after Spring application context has loaded, but before any test has been run?
My current approach:
#BeforeEach
public void before() {
repository.save(...); // -> prepopulates repository with sample data
}
#Test
public void testService() {
service.get(...); // -> gathers existing record
}
#Test
public void deleteById() {
service.delete(...); // -> deletes existing record
}
However... with this, I am required to flush out the records after every test. Otherwise any unique constraints can easily be violated.
Rather than using #BeforeEach which is required to run before every test... is it possible to load this in in a #BeforeAll kind of fashion that happens after the spring application context has been loaded?
Is there any way that I can load in my test data after Spring application context has loaded
Basically yes, I think you can do that:
The idea is to load the SQL data when the application context is started or in the process of being started.
For example, spring boot integration with Flyway works this way (the bean of Flyway is created and loaded). So, in theory, you could merely use Flyway with test migrations that will contain all the relevant SQL scripts of test data generation.
How can you do this technically?
Here is one way:
Create a special bean (just like the way it works with Flyway) that would depend on your repository and in post construct save the data:
#Component
public class SqlGenerationBean {
#Autowired
private MyRepository repo;
#PostConstruct
public void init() {
repo.save();
}
}
Another way of doing is to create a listener that will be called upon the application context started and again will call the same repo.save().
In both cases the bean/listener code should not be accessible from production (it's only for tests): so put it somewhere under src/test/java for example
Now once the application context is started you can use a neat trick:
Mark your tests with #Transactional annotation. Spring will wrap the code in an artificial transaction that will be rolled back automatically (even if the test succeeds) so that all the data that you'll modify during the test will be rolled back and basically before each test, you'll have the same state (that is identical to the state of the database when/after the application context starts). Of course, if you use DDL in the test, some databases can't make it a part of transaction but it depends on the database really.
Another interesting point here is that the application context can be cached even between the test cases (created only once), so keep this in mind.
In this case I would just create a constructor for the test class. It will be triggered before everything.
#BeforeEach runs before each tests but after all initialisations .
you can also just use Mockito and mock the result without need to clean and overcomplicate
Just add following snippet to your code. This is just like you can do to detect that Spring application is really started.
#Configuration
public class AppConfig implements ApplicationListener<ApplicationReadyEvent> {
/**
* This is to indicate in the logs when the application has actually started and everything is loaded.
*/
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
ApplicationContext context = event.getApplicationContext();
Environment env = context.getEnvironment();
// do what you want on application start
}
}
P.S. For database manipulation in test #Sql is the best candidate as was mentioned in comment.
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.
In my web application I have to insert some seed data if not exists in DB when application got deployed. So, I have triggered inserting data api as follows
#Component
public class ApplicationContextLoadListener implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private PersistenceFacilitator persistenceFacilitator;
#Autowired
private SeedDataService seedDataService;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// generate metadata for entities and schema
persistenceFacilitator.facilitate();
//insert seed data
seedDataService.insertSeedData();
}
}
It's working fine. But the problem comes when I execute test cases with #RunWith(SpringJUnit4ClassRunner.class), that event got triggered and try to insert seed data though DB is not ready. So, all my test cases getting failed.
Is there a way to address this issue with spring or any good application start-up event to handle seed data?
[updated]
As per app engine specification to test inserting data into DB, I have to call
#Before
public void setup(){
LocalServiceTestHelper helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
helper.setUp();
}
Which is not ready by the time application context loads. Anyway I don't want to insert seed data in DB while running testcases