I have a method that is going to call a stored function. I want it to async'ly do its work. This is what I have, but it seems like the .doWork() is never started because when I call getDao.deleteAll(), the stored function does not run.
#Transactional
public void delete()
{
final Session session = (Session) entityManager.getDelegate();
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable()
{
#Override
public void run()
{
LOGGER.warn("starting");
session.doWork(new Work()
{
#Override
public void execute(Connection connection) throws SQLException
{
try
{
CallableStatement purgeArchived = connection.prepareCall("{call deleteAll()}");
purgeArchived.execute();
}
catch (SQLException exception)
{
LOGGER.warn("Failed to purge archive points. Reason: " + exception);
}
}
});
LOGGER.warn("stopping");
}
});
executorService.shutdown();
}
I see the logger has logged "starting", but it never got to "stopping" why is this happening?
Be aware that #Transaction is moot when you have a separate thread as Transactions are typically thread bound.
You will need to get a new entityManager from the factory inside the run().
Also go for #Async which is much cleaner.
Again be aware of transactionality with #Async
#Async and #Transactional: not working
As a general rule of thumb if you want to make some work async - treat that as a single unit of work and a separate transaction.
Related
I have problem with receiving new messages from my JS client after I use the first received message in new thread and cancel the thread. I use spring boot for the back end. The interesting thing is that the session is not closed but I just cannot receive any more messages after the first one when I interrupt my thread.
Here is my websocket config:
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), "/socket1").setAllowedOrigins("*");
}
}
Here is my handler with the executor service:
public class WebSocketHandler extends AbstractWebSocketHandler {
Logger logger = LoggerFactory.getLogger(WebSocketHandler.class);
Test test = new Test();
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
logger.info("START");
List<UrlWithPageNumber> listings = new ArrayList<>();
listings.add(new UrlWithPageNumber( "www.somesite.com", 1));
listings.add(new UrlWithPageNumber( "www.anothersite.com", 1));
listings.add(new UrlWithPageNumber( "www.thirdsite.com", 1));
checkItemsAsync(listings, session);
logger.info("DONE");
session.sendMessage(new TextMessage("DONE"));
}
public void checkItemsAsync(List<UrlWithPageNumber> listings, WebSocketSession session) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
final CountDownLatch latch = new CountDownLatch(listings.size());
for (UrlWithPageNumber listing : listings) {
executorService.submit(() -> {
if(Test.stop) {
return;
}
ListingInfo listingInfo = test.itemPage(listing.getLink(), 1, 1);
logger.info(listingInfo.toString());
synchronized(session) {
try {
session.sendMessage(new TextMessage(listingInfo.toString()));
} catch (IOException e) {
e.printStackTrace();
}
}
latch.countDown();
});
}
try {
latch.await();
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}
}
Now the problem is the following: I call my handleTextMessage method from JS client and the execution is starting then I press another button in my page and it is changing Test.stop boolean flag to true and in that way i stop the remaining threads to be executed. After that if I call handleTextMessage from the js like the first time it is not called. I checked if I close the WebSocketSession and then try to call the backend and the result is similar but in my case the session is not closed for sure ! The question is how to use the WebSocketSession many times and why the session is become broken when I use it in my executor service and stop the thread? Should I do something with the session if I shutdown threads or this is just some spring boot bug ?
The problem is in the latch it wait more than expected because I skip some threads..
I'm working on an app that retrieves from and enters information to a database, using Spring JDBC template. On the service tier, I would like to set up some logic to catch an exception if the database goes down. However, I have no idea how to do this. I'm able to set up the methods to catch if they fail, but I'd like set up specific logic for the server going down.
As an option - you can create a sceduler which will check database connectivity.
Database connectivity could be checked executing a simple query or via Connection interface:
boolean isValid(int timeout) throws SQLException
Returns true if the connection has not been closed and is still valid.
The driver shall submit a query on the connection or use some other
mechanism that positively verifies the connection is still valid when
this method is called. The query submitted by the driver to validate
the connection shall be executed in the context of the current
transaction.
An example of checking database connectivity via Spring scheduler:
#Service
public class ConnectionListener {
private Connection connection;
#Autowired
private JdbcTemplate jdbcTemplate;
#PostConstruct
public void init() {
connection = jdbcTemplate.getDatasource().getConnection();
}
#Scheduled(fixedRate = 60000) // check every 60 sec
public void checkConnection() {
try {
connection.isValid(10);
} catch (SQLException e) { // Or just handle it here
throw new ConnectionTimeoutException(e);
}
}
}
You need some additional cnfiguration to handle exceptions thrown from Spring Scheduler:
#EnableScheduling
#Configuration
class SchedulingConfiguration implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(...);
}
}
Sceduler also could be implemented with ExecutorService.
#Service
class ConnectionLisener {
private ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
private Connection connection;
#PostConstruct
public void init() {
connection = jdbcTemplate.getDatasource().getConnection();
checkConnection();
}
#PreDestroy
public void destroy() {
service.shutdown();
}
public void checkConnection() {
service.scheduleAtFixedRate(() -> {
try {
connection.isValid(10);
} catch (Exception e) {
// handle your exception
}
}, 60, 60, TimeUnit.SECONDS);
}
}
That's a general overview and just a couple of hints for doing further research.
Just one note that if a server is going down you need a disaster recovery, catching an exception will not help. That's a big infrastructure and architectural task, not the responsibility of single application.
The issue is that I have a method starting a new thread for a time-consuming work. I want to test the callback result, but the child thread may still running, so as a result, what I get is not the right stub.
I think the code may explain itself:
public class JustAClass {
//it is a callback for async
public interface JustACallBack {
void callFunc(JustAResult result);
}
//this is the result interface
public interface JustAResult {
}
//this is a real class for the interface
public class JustAResultReal implements JustAResult{
public JustAResultReal(String content) {this.content = content;}
public String content;
}
//here is the key function
public void threadFunc(final JustACallBack callBack) {
BCCache.executorService.execute(new Runnable() {
#Override
public void run() {
//just to simulate a time-consuming task
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//now we callback
callBack.callFunc(new JustAResultReal("can you reach me"));
}
});
}
}
and the test function could be(I am using mockito):
#Test
public void testThreadFunc() throws Exception {
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = Mockito.mock(JustAClass.JustACallBack.class);
justAClass.threadFunc(callBack);
//add this line, we can get the expected result
Thread.sleep(1200);
Mockito.verify(callBack).callFunc(captor.capture());
System.out.println(((JustAClass.JustAResultReal)captor.getValue()).content);
}
I know we can add a sleep to wait and expect that the child thread would exit within the period, but could there be a better way? Actually how could I know how long the child thread would take? Setting a very long time can be an approach but just seems not very nice.
The general approach in #stalet's answer is close, but doesn't quite work since any assertion failures from a separate thread are not noticed by the main thread. Therefore your test will always pass, even when it shouldn't. Instead, try using ConcurrentUnit (which I authored):
#Test
public void testInvoke() throws Throwable {
Waiter waiter = new Waiter();
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
waiter.assertNotNull(result);
waiter.assertTrue(result instanceof JustAClass.JustAResultReal);
waiter.resume();
}
};
justAClass.threadFunc(callBack);
waiter.await(1200, TimeUnit.SECONDS);
}
The key here is ConcurrentUnit's Waiter will properly report any assertions failures to the main test thread and the test will pass or fail as it should.
I aggree with #Gimbys comment about this is no longer a unit-test when you start testing the the threading aspect.
Nevertheless it is interesting as a way to integration-test a asynchronous invokation.
To avvoid sleep i tend to use the class CountDownLatch to wait for invokations.
In order to count down you need an actuall implementation of the callback interface - so in my example I have made a mock implementation of this.
Since there is no actual methods to fetch the data - i am just testing that it is in fact a instance of the JustAReal interface.
#Test
public void testInvoke() throws Exception {
final CountDownLatch countDownLatch = new CountDownLatch(1); //1 is how many invokes we are waiting for
JustAClass justAClass = new JustAClass();
JustAClass.JustACallBack callBack = new JustAClass.JustACallBack() {
#Override
public void callFunc(final JustAClass.JustAResult result) {
assertNotNull("Result should not be null", result);
assertTrue("Result should be instance of JustAResultReal", result instanceof JustAClass.JustAResultReal);
countDownLatch.countDown();
}
};
justAClass.threadFunc(callBack);
if(!countDownLatch.await(1200, TimeUnit.MILLISECONDS)){
fail("Timed out, see log for errors");
}
}
I have next service class:
public class JDBCServiceImpl {
//////
public void writeTablesColumnsToFiles(DataSource dataSource, List<Table> tableInfos) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (Table table : tableInfos) {
Runnable worker = new Runnable() {
#Override
public void run() {
try {
writeTableColumnsToFiles(dataSource, table);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
executor.execute(worker);
}
executor.shutdown();
}
//////
public void writeTableColumnsToFiles(DataSource dataSource, Table tableInfo) {
//
try (Connection connection = dataSource.getConnection()) {
.....
}
}
}
I would like to test this service in JUnit class:
public class JDBCLoaderServiceImpl {
#Test
public void testExecutingOfJDBCService() {
.....
JDBCServiceImpl jdbcLoaderService = new JDBCServiceImpl();
jdbcLoaderService.writeTablesColumnsToFiles(dataSource, allTables);
}
}
The main problem that JUnit doesn't wait while executor complete it task (in debug mode I see that after this code try (Connection connection = dataSource.getConnection()) service class return control). So how to fix this issue? Thanks in advance.
I suggest to test writeTableColumnsToFiles(DataSource dataSource, Table tableInfo) and ignore method that work with threads.
But if you really want to test it you can mock ExecutorService and do all work in single thread.
In general, JUnit isn't for testing multi-threaded execution. (It's for unit testing... right there in the name.)
For instance, if one or even all of your worker threads were to throw exceptions and die, your JUnit test harness --- running in a completely different thread --- wouldn't notice. Unless your test specifically asserted that no such failure had occurred, JUnit would record it as having passed, since the test itself hadn't thrown or propagated any exceptions.
Okay I add next code to writeTablesColumnsToFiles method:
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
This solve my issue.
I am writing an integration test in JUnit for a Message Driven Pojo (MDP):
#JmsListener(destination = "jms/Queue", containerFactory = "cf")
public void processMessage(TextMessage message) throws JMSException {
repo.save(new Entity("ID"));
}
where repo is a spring-data repository
my unit test:
#Test
public void test() {
//sendMsg
sendJMSMessage();
//verify DB state
Entity e = repo.findOne("ID");
assertThat(e, is(notNullValue()) );
}
Now, the thing is that the processMessage() method is executed in a different thread than the test() method, so I figured out that I need to somehow wait for the processMessage() method to complete before verifying the state of the DB. The best solution I could find was based on CountDownLatch. so now the methods look like this:
#JmsListener(destination = "jms/Queue", containerFactory = "cf")
public void processMessage(TextMessage message) throws JMSException {
repo.save(new Entity("ID"));
latch.countDown();
}
and the test
#Test
public void test() {
//set the countdownlatch
CountDownLatch latch = new CountDownLatch(1);
JMSProcessor.setLatch(latch);
//sendMsg
sendJMSMessage();
try {
countDownLatch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//verify DB state
Entity e = repo.findOne("ID");
assertThat(e, is(notNullValue()) );
}
So I was very proud of myself and then I run the test and it failed. The repo.findOne("ID") returned null. In the first reaction I set up a breakpoint at that line and proceed with debugging. During the debugging session the repo.findOne("ID") actually returned the entity inserted by the #JMSListenerlistener method.
After scratching my head for a while here's the current theory: Since the spring-data repository is accessed in two different threads, it gets two different instances of EntityManager and therefore the two threads are in a differen't transaction. Eventhough there's some sort of synchronization using the CountDownLatch, the transaction bound to the thread executing the #JMSListener annotated method has not committed yet when the JUnit #Test annotated method starts a new transaction and tries to retrieve the entity.
So my question is:
Is there a way for one thread to wait for the commit of the other.
Can two threads share one transaction in such a synchronized context (ie, the two threads would not access the EntityManager simultaneously)
Is my testing approach a nonsense and there is a better way of doing this