I am having troubles invoking a method asynchronously in Spring, when the invoker is an embedded library receiving notifications from an external system. The code looks as below:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
private NotificationClient client;
#Override
public void process(Notification notification) {
processAsync(notification);
}
#PostConstruct
public void startClient() {
client = new NotificationClient(this, clientPort);
client.start();
}
#PreDestroy
public void stopClient() {
client.stop();
}
#Async
private void processAsync(Notification notification) {
// Heavy processing
}
}
The NotificationClient internally has a thread in which it receives notifications from another system. It accepts a NotificationProcessor in its constructor which is basically the object that will do the actual processing of notifications.
In the above code, I have given the Spring bean as the processor and attempted to process the notification asynchronously by using #Async annotation. However, it appears the notification is processed in the same thread as the one used by NotificationClient. Effectively, #Async is ignored.
What am I missing here?
#Async (as well as #Transactional and other similar annotations) will not work when the method is invoked via this (on when #Async is used for private methods*), as long as you do not use real AspectJ compiletime or runtime weaving.
*the private method thing is: when the method is private, then it must been invoked via this - so this is more the consequence then the cause
So change your code:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
#Resource
private DefaultNotificationProcessor selfReference;
#Override
public void process(Notification notification) {
selfReference.processAsync(notification);
}
//the method must not been private
//the method must been invoked via a bean reference
#Async
void processAsync(Notification notification) {
// Heavy processing
}
}
See also the answers for: Does Spring #Transactional attribute work on a private method? -- this is the same problem
Related
I use Camunda as bpmn engine in my spring boot application
Main idea:
The first process is started in the controller, and after the response is returned to the client, the Second process should start.
I do this using #Async(spring framework) to start the second process and I have two bpmn diagrams:
firstProcess
secondProcess
Simple implementation of the idea:
#RestController
public class SimpleController {
#Autowired
private CustomService asyncService;
#Autowired
private CustomService syncService;
#GetMapping(value = "/request")
public ResponseEntity<String> sendQuestion() {
//start process described in first.bpmn
syncService.startProcess("firstProcess");
//start process described in second.bpmn asynchronously
//controller responses to client without waiting for ending secondProcess
asyncService.startProcess("secondProcess");
return new ResponseEntity<>("OK", HttpStatus.OK);
}
}
#Service
public class AsyncService implements CustomService {
#Autowired
private RuntimeService runtimeService;
#Async
public void startProcess(String key) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
//
}
runtimeService.startProcessInstanceByKey(key);
}
}
Questions:
Is there a way to do these two processes in one process (as shown at both processes)?
How should I implement this in the spring boot app?
bothProcess
You need use Call Activity Task specifying BPMN as CallActivity Type and corresponding process ids in Called Element field on the properties panel.
Also don't forget uncheck Startable checkbox for your subprocesses.
Is there any way in spring that we can send response immediately.
I want to create a thread which will do a job. But I don't want to make the user to wait till that job completed.
There is multiple way of doing so in Spring.
Here is their article.
If you want to make the operations asynchronously, the easiest way is to use the #Asyn annotation from Spring.
Here is a simple example :
// Interface definition for your async operation here
public interface AsyncOperator {
#Async
void launchAsync(String aBody);
}
And a simple implementation that uses the interface
// Need to be a bean managed by Spring to be async
#Component
class SimpleAsync implements AsyncOperator {
#Override
public void launchAsync(String aBody){
// Your async operations here
}
}
Then you need for Spring to configure how the async works. Using Spring boot a simple configuration class like this works:
#Configuration
#EnableAsync
public class AsyncConfiguration {
}
Then you can call your method and it will return right away and do the treatments asynchronously :
#Component
public class AController {
private final AsyncOperator async;
public AController(AsyncOperator async){
this.async = async;
}
public String aMethod(String body){
// here it will return right after call
this.async.launchAsync(body);
return "Returned right away !!";
}
}
The only downsides of this method is that all your classes for async operations must be managed by Spring.
I am trying to add a ErrorHandler via the EventProcessingConfigurer.registerErrorHandler() method and while it is showing on the configuration the class itself is not being called.
Am currently using Axon 4.1.1 (With out Axon server) and Spring Boot 2.1.6.RELEASE.
i have based my code off github/AxonFramework but it isn't acting the same.
Config:
#Autowired
public void configure(final EventProcessingConfigurer config) {
TestErrorHandler testErrorHandler = new TestErrorHandler();
config.registerErrorHandler("SolrProjection", configuration -> testErrorHandler);
}
ErrorHander:
public class TestErrorHandler implements ErrorHandler, ListenerInvocationErrorHandler {
#Override
public void handleError(final ErrorContext errorContext) throws Exception {
System.out.println("TestErrorHandler.handleError()");
}
#Override
public void onError(final Exception exception, final EventMessage<?> event, final EventMessageHandler eventHandler) {
System.out.println("TestErrorHandler.onError()");
}
}
Projection:
#Configuration
#RequiredArgsConstructor
#ProcessingGroup("SolrProjection")
public class SolrProjection {
#EventHandler
public void onEvent(final TestEvent event,
#SequenceNumber Long sequenceNumber,
#Timestamp final Instant requestTimestamp,
#MessageIdentifier final String messageIdentifier,
final MetaData metaData) {
if (true) {
throw new IllegalStateException();
}
}
even thou i am directly throwing an error, i do not ever see the two system.out's in console. and putting log statements in the #EventHandler are properly being called.
The ErrorHandler is tasked to dealing with different exceptions than what you expect.
When it comes to handling events, Axon Framework deduces two layers:
The internal EventProcessor layer
The Event Handling Components written by framework users
Exceptions thrown within the EventProcessor are dealt with by the ErrorHandler you've configured.
For customizing the process for handling exceptions from your own Event Handlers, you
will have to configure the ListenerInvocationErrorHandler.
To configure a general/default ListenerInvocationErrorHandler, you can use the following method in your first snippet:
EventProcessingConfigurer#registerDefaultListenerInvocationErrorHandler(
Function<Configuration, ListenerInvocationErrorHandler>
)
You can also check out Axon's Reference Guide at this page for more info on this.
Hope this helps you out #sherring!
I have a class with the following function:
public class classA{
...
...
void function_to_be_scheduled(String param){
...
...
}
}
I want to schedule the function using the scheduled-tasks element of the task namespace.
<task:scheduled-tasks>
<task:scheduled ref="beanA" method="function_to_be_scheduled" cron="${cron}"/>
</task:scheduled-tasks>
How do i pass the parameter to the function which i want to schedule?
According to the docs you cant.
Notice that the methods to be scheduled must have void returns and
must not expect any arguments.
The Spring doc about scheduling says:
Notice that the methods to be scheduled must have void returns and must not expect any arguments
Since the parameter comes from the Spring config file you can declare a bean (es beanB which wraps beanA) in the spring file, inject the parameter you need in the bean and the schedule the execution of a method of the bean which knows the parameter (it could be a simple wrapper of your beanA)
You can use TaskScheduler and encapsule your logic with a parameter in Runnable:
#Autowired
private TaskScheduler scheduler;
public void scheduleRules() {
MyTask task = new MyTaskImpl(someParam);
// new CronTrigger
scheduler.scheduleAtFixedRate(task, Duration.ofMinutes(1));
}
I've found that the only way to do this is to have a façade method that is #Scheduled and knows the default value required. The useful side-effect of this is that you can also provide an API through a #Controller to provide manual triggering with a specific parameter - useful if you need to re-run an activity.
#Scheduled(cron = "${myChronSchedule}")
public void generateActivities() {
this.generateActivities(LocalDate.now());
}
public void generateActivities(LocalDate theDate) {
// do the work
...
}
If you don't need the façade to be public, there's no reason why it can't be private and no-one is the wiser.
The Task Scheduler did the trick for me
First create a configuration class called ThreadPoolTaskScheduler class. Find details Here!
Then create a class where the magic happens
#Component
public class ThreadPoolTaskSchedulerExample {
#Autowired
private ThreadPoolTaskScheduler taskScheduler;
class EmailWatch implements Runnable{
private String userEmail;
public EmailWatch(String userEmail){
this.userEmail = userEmail;
}
#Override
public void run() {
System.out.println("This is the email "+ userEmail);
}
}
public void watchEmail(String userEmail) {
//refresh watch every minute
CronTrigger cronTrigger = new CronTrigger("0 * * ? * *");
taskScheduler.schedule(new EmailWatch(userEmail));
}
}
Is it possible to use callbacks with Spring to that they are managed by application context?
My problem is when a service is used from outer by #Autowired, but within that service there is a callback defined using new operator.
The following example executes a method that is worth retrying. Spring offers a RetryCallback for this case (I know this could be acchieved differently, but just to illustrate my callback problem).
#Service
class MyService {
//main method invoked
void run(DataVO dataVO) {
//new operator not usable in spring context
RetryCallback<Object> retryCallback = new RetryCallback<Object>() {
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
};
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
Is it possible to refactor this snippet so that the callback is managed by spring/injected/autowired?
Make your service implement the callback interface :
#Service
class MyService implements RetryCallback<Object> {
//main method invoked
void run(DataVO dataVO) {
}
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}