This is my scenario:
My app has Mongo Auditing enabled, with a custom AuditorAware which gets the current user from the SecurityContext. This works well with synchronous methods, and the current auditor is successfully saved, but I can't make it work properly with #Async methods.
I have an async method (CompletableFuture) that makes some updates on my Mongo Database. When the AuditorAware.getCurrentAuditor() is called, no authentication info exists, and I can't get the current auditor (SecurityContextHolder.getContext().getAuthentication() returns null).
#Override
public User getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()
|| authentication instanceof AnonymousAuthenticationToken) {
log.error("Not authenticated");
return null;
}
[...]
}
I'm using a DelegatingSecurityContextAsyncTaskExecutor:
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(200);
executor.initialize();
return new DelegatingSecurityContextAsyncTaskExecutor(executor);
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new ItacaExceptionHandler();
}
}
How can I make it work properly?
Spring security context is always bound to Threadlocal.
Probabably you may to additionally set MODE_INHERITABLETHREADLOCAL for the security context.
#Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
http://www.ogrigas.eu/spring/2010/04/inherit-spring-security-context-in-child-threads
How to set up Spring Security SecurityContextHolder strategy?
Following the comments on kuhajeyan's answer, it appears you are not properly using CompletableFuture with Spring #Async.
If you launch your tasks by using e.g. CompletableFuture.supplyAsync(Supplier), they will be executed by the common ForkJoinPool and not the one you have configured for #Async. You could use the overloads that take an Executor as argument, but it would not actually benefit from the advantages of #Async.
What you should do, instead, is let Spring handle the task execution, and simply return a completed CompletableFuture like this:
#Async
public CompletableFuture<String> someMethod() {
// do some computation, but return a completed future
return CompletableFuture.completedFuture("Hello World!");
}
Spring will then execute your method asynchronously in the configured executor while immediately return a CompletableFuture which will be completed when your method returns.
If you are using Spring 4.2 or above, this is supported out of the box. Otherwise there is a bit of implementation required, but that would be for another question.
Related
I have spring integration flow that gets triggered once a every day, that pulls all parties from database and sends each party to an executorChannel.
The next flow would pull data for each party and then process them parallelly by sending in to a different executor channel.
Challenge i'm facing is how do i know when this entire process ends. Any ideas on how to acheve this .
Here's my pseudo code of executor channels and integration flows.
#Bean
public IntegrationFlow fileListener() {
return IntegrationFlows.from(Files.inboundAdapter(new
File("pathtofile"))).channel("mychannel").get();
}
#Bean
public IntegrationFlow flowOne() throws ParserConfigurationException {
return IntegrationFlows.from("mychannel").handle("serviceHandlerOne",
"handle").nullChannel();
}
#Bean
public IntegrationFlow parallelFlowOne() throws ParserConfigurationException {
return IntegrationFlows.from("executorChannelOne").handle("parallelServiceHandlerOne",
"handle").nullChannel();
}
#Bean
public IntegrationFlow parallelFlowTwo() throws ParserConfigurationException {
return IntegrationFlows.from("executorChannelTwo").handle("parallelServiceHandlerTwo",
"handle").nullChannel();
}
#Bean
public MessageChannel executorChannelOne() {
return new ExecutorChannel(
Executors.newFixedThreadPool(10));
}
#Bean
public MessageChannel executorChannelTwo;() {
return new ExecutorChannel(
Executors.newFixedThreadPool(10));
}
#Component
#Scope("prototype")
public class ServiceHandlerOne{
#Autowired
MessageChannel executorChannelOne;
#ServiceActivator
public Message<?> handle(Message<?> message) {
List<?> rowDatas = repository.findAll("parties");
rowDatas.stream().forEach(data -> {
Message<?> message = MessageBuilder.withPayload(data).build();
executorChannelOne.send(message);
});
return message;
}
}
#Component
#Scope("prototype")
public class ParallelServiceHandlerOne{
#Autowired
MessageChannel executorChannelTwo;;
#ServiceActivator
public Message<?> handle(Message<?> message) {
List<?> rowDatas = repository.findAll("party");
rowDatas.stream().forEach(data -> {
Message<?> message = MessageBuilder.withPayload(data).build();
executorChannelTwo;.send(message);
});
return message;
}
}
First of all no reason to make your services as #Scope("prototype"): I don't see any state holding in your services, so they are stateless, therefore can simply be as singleton. Second: since you make your flows ending with the nullChannel(), therefore point in returning anything from your service methods. Therefore just void and flow is going to end over there naturally.
Another observation: you use executorChannelOne.send(message) directly in the code of your service method. The same would be simply achieved if you just return that new message from your service method and have that executorChannelOne as the next .channel() in your flow definition after that handle("parallelServiceHandlerOne", "handle").
Since it looks like you do that in the loop, you might consider to add a .split() in between: the handler return your List<?> rowDatas and splitter will take care for iterating over that data and replies each item to that executorChannelOne.
Now about your original question.
There is really no easy to say that your executors are not busy any more. They might not be at the moment of request just because the message for task has not reached an executor channel yet.
Typically we recommend to use some async synchronizer for your data. The aggregator is a good way to correlate several messages in-the-flight. This way the aggregator collects a group and does not emit reply until that group is completed.
The splitter I've mentioned above adds a sequence details headers by default, so subsequent aggregator can track a message group easily.
Since you have layers in your flow, it looks like you would need a several aggregators: two for your executor channels after splitting, and one top level for the file. Those two would reply to the top-level for the final, per-file grouping.
You also may think about making those parties and party calls in parallel using a PublishSubscribeChannel, which also can be configured with a applySequence=true. This info then will be used by the top-level aggregator for info per file.
See more in docs:
https://docs.spring.io/spring-integration/docs/current/reference/html/core.html#channel-implementations-publishsubscribechannel
https://docs.spring.io/spring-integration/docs/current/reference/html/message-routing.html#splitter
https://docs.spring.io/spring-integration/docs/current/reference/html/message-routing.html#aggregator
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'm trying to copy Spring context to Runnable/Callable tasks for a special case. I want other threads to run as they run before.
I've read this How to enable request scope in async task executor
and implemented a custom ThreadPoolTaskExecutor + decorator.
#Configuration
public class ContextCopyConfig {
private Integer connectionsLimit=10;
#Bean(name = "contextExecutor")
public Executor contextExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setTaskDecorator(new ContextCopyingDecorator());
poolExecutor.setMaxPoolSize(connectionsLimit);
poolExecutor.setCorePoolSize(connectionsLimit);
poolExecutor.initialize();
return poolExecutor;
}
}
I was planning to use this executor as follows:
#Autowired
#Qualifier(value = "contextExecutor")
private Executor contextExecutor;
public void parallelHere() throws IOException, InterruptedException, ExecutionException {
Collection<Callable<Pair<String, OutputStream>>> tasks = new ArrayList<>(); //some tasks
//ExecutorService executor = Executors.newFixedThreadPool(connectionsLimit);
List<Future<Pair<String, OutputStream>>> results = ((ThreadPoolTaskExecutor) contextExecutor).getThreadPoolExecutor().invokeAll(tasks);
((ThreadPoolTaskExecutor) contextExecutor).getThreadPoolExecutor().shutdown(); //always reclaim resources
}
However, contextExecutor is always invoked (in any thread!).
How can I fix it?
This post:
How to create additional TaskExecutor beside TaskExecutionAutoConfiguration?
describes the issue. Springboot creates a default Executor only if user did not create a custom one.
In SpringBoot 2+ you have to use
#AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
on your custom configuration.
In previous Spring versions however, no TaskExecutionAutoConfiguration exists and Executor is created by a factory. Using lines below, you can create the exect copy of default executor, created by Spring.
#Primary
#Bean
//see package org.springframework.aop.interceptor.AsyncExecutionInterceptor
public Executor getDefaultExecutor(){
// Executor defaultExecutor = super.getDefaultExecutor(beanFactory);
// return (defaultExecutor != null ? defaultExecutor : new SimpleAsyncTaskExecutor());
return new SimpleAsyncTaskExecutor();
}
Can anybody tell my is there a way of using the Spring Framework's #Async annotation without blocking / waiting on the result? Here is some code to clarify my question:
#Service
public class AsyncServiceA {
#Autowired
private AsyncServiceB asyncServiceB;
#Async
public CompletableFuture<String> a() {
ThreadUtil.silentSleep(1000);
return asyncServiceB.b();
}
}
#Service
public class AsyncServiceB {
#Async
public CompletableFuture<String> b() {
ThreadUtil.silentSleep(1000);
return CompletableFuture.completedFuture("Yeah, I come from another thread.");
}
}
and the configuration:
#SpringBootApplication
#EnableAsync
public class Application implements AsyncConfigurer {
private static final Log LOG = LogFactory.getLog(Application.class);
private static final int THREAD_POOL_SIZE = 1;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
final AsyncServiceA bean = ctx.getBean(AsyncServiceA.class);
bean.a().whenComplete(LOG::info);
};
}
#Override
#Bean(destroyMethod = "shutdown")
public ThreadPoolTaskExecutor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(THREAD_POOL_SIZE);
executor.setMaxPoolSize(THREAD_POOL_SIZE);
executor.initialize();
return executor;
}
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
// omitted
}
}
When I run the application the executor goes through calling AsyncServiceA.a() and leaves, but it still holds the thread from the pool waiting on the CompletableFuture.get() method. Since there is just a single thread in the pool the AsyncServiceB.b() cannot be executed. What I'm expecting is that thread to be returned to the pool after it executes the AsyncServiceA.a() and then be available to execute the AsyncServiceB.b().
Is there a way to do that?
Note 1: I've tried with ListenableFuture also but the result is the same.
Note 2: I've successfully did it manually (without the #Async) by giving the executor to each method like so:
AsyncServiceA
public CompletableFuture<String> manualA(Executor executor) {
return CompletableFuture.runAsync(() -> {
LOG.info("manualA() working...");
ThreadUtil.silentSleep(1000);
}, executor)
.thenCompose(x -> asyncServiceB.manualB(executor));
}
AsyncServiceB
public CompletableFuture<String> manualB(Executor executor) {
return CompletableFuture.runAsync(() -> {
LOG.info("manualB() working...");
ThreadUtil.silentSleep(1000);
}, executor)
.thenCompose(x -> CompletableFuture
.supplyAsync(() -> "Yeah, I come from another thread.", executor));
}
Here is the ThreadUtil if someone was wondering.
public class ThreadUtil {
public static void silentSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Update: Added issue for non-blocking Async annotation https://jira.spring.io/browse/SPR-15401
The #Async support has been part of Spring since Spring 3.0 which was way before the existence of Java8 (or 7 for that matter). Although support has been added for CompletableFutures in later versions it still is to be used for simple async execution of a method call. (The initial implementation reflects/shows the call).
For composing callbacks and operate non blocking the async support was never designed or intended to.
For non blocking support you would want to wait for Spring 5 with its reactive/non-blocking core, next to that you can always submit a ticket for non-blocking support in the async support.
I've responded on the ticket https://jira.spring.io/browse/SPR-15401 but I'll respond here as well to qualify the response by M. Deinum.
#Async by virtue of how it works (decorating the method call via AOP) can only do one thing, which is to turn the entire method from sync to async. That means the method has to be sync, not a mix of sync and async.
So ServiceA which does some sleeping and then delegates to the async ServiceB would have to wrap the sleeping part in some #Async ServiceC and then compose on ServiceB and C. That way ServiceA becomes async and does not need to have the #Async annotation itself..
When the first runnable is submitted is an inject ExecutorService, the security Principal is correctly set for that runnable. Each subsequently submitted runnable is given the security principal of the original user instead of keeping the current runnable. My development machine is running Wildfly 8.2 .
I am creating a reporting system for asynchronous processing. I created a service that checks which user created the task and ensures that only that user can start or complete the task. The code for the service is below.
#Stateless
public class ReportingService {
//EE injection security context
#Resource
SessionContext context;
//CDI security Principal
#Inject
Principal principal;
//this method handles getting the username for EE injection or CDI
private String getCurrentUser() {
if (context != null) {
return context.getCallerPrincipal().getName();
}
if (principal != null) {
return principal.getName();
}
return null;
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Transactional
public void registerTask(String taskId) {
//Create task
//set task.submittedBy = getCurrentUser()
//persist task
//code has been omitted since it is working
}
private void validateCurrentUserRegisteredJob(String taskId) {
String user = //get user that created task with id = id from DB
String currentUser = getCurrentUser();
if (!user.equals(currentUser)) {
throw new EJBAccesException("Current user "+currentUser+" did not register task");
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Transactional
public void startTask(String taskId) {
validateCurrentUserRegisteredJob(taskid);
//retrieve task entity, set start time to now, and merge
}
...
}
Below is my Runnable code
public TaskRunner() implements Runnable {
//CDI principal
#Inject
Principal principal;
#Inject
ReportingService rs;
private taskId;
public void setTaskId() {...}
public void run() {
log.debug("Inside Runner Current User: "+principal.getName());
rs.startTask(taskId);
....
}
}
The following is the code from the Stateless Bean that is called by a REST endpoint that kicks off the process
#Stateless
public ProjectService() {
#Inject
Instance<TaskRunner> taskRunner;
#Inject
ReportingService reportingService;
//ExecutorService that is create from Adam Bien's porcupine project
#Inject
#Dedicated
ExecutorService es;
//method that is called by rest enpoint to kick off
public void performAsynchAction(List<String> taskIds, ...rest of args...) {
taskIds.stream().forEach(t -> {
//registers task with user that made REST call
reportingService.registerTask(t);
TaskRunner runner = taskRunner.get();
runner.setTaskId(t);
log.debug("Created runner. Principal: "+runner.principal.getName());
es.submit(runner);
});
}
}
Here is the chart of the call flow
REST -> ProjectService.performAsynchAction(...)
-> reportingService.registerTask(...)
-> create CDI injected Runnable
-> submit runner to executor service
-> ExecutorService calls Runner.run()
-> rs.startTask(taskId)
I call the Rest end point as user1 for the first time and register tasks: 1-2. They all work as expected and I get the following output in my log.
Created runner. Principal: user1
Created runner. Principal: user1
Inside Runner Current User: user1
Inside Runner Current User: user1
The next time I make the same REST call as user2 and I get the following output in the log
Created runner. Principal: user2
Inside Runner Current User: user1
EJBAccessException Current user user1 did not register task
It appears that the Security Principal of the Runnable is correctly set the first time a Runnable is submitted to the ExecutorService. But for each subsequent Runneable that is submitted to the ExecutorService uses the security Principal of the first submitted runnable. Is this a bug or the intended behavior? Does anyone know of a potential work around?
EDIT: I figure out that the porcupine project I was using to create the ExecutorService was not being managed by the container. Once I switched to a ManagedExecutorService, the SessionContext was being properly propagated.
#Resource(lookup = "java:jboss/ee/concurrency/executor/customExecutor")
private ManagedExecutorService es;
I figured out the issue. I looked into the porcupine code and found out that the ExecutorService was not being managed by the Container. I created a ManagerExecutorService and the SessionContext was then being properly propogated.
#Resource(lookup = "java:jboss/ee/concurrency/executor/customExecutor")
private ManagedExecutorService es_;
I think the problem is, that you #Inject a #Dependent scoped ExecutorService into a #Stateless bean.
#Stateless beans can be pooled and reused, while #Dependent CDI beans are stored by reference and therefore are not recreated when the #Stateless bean is reused.
Without knowing the implementation of your ExecutorService, I guess that it creates contextual threads during the first run and reused them in the second run without adjusting the context.
You could "force" your ProjectService to create a new ExecutorService by encapsulating it into a #RequestScoped bean:
#RequestScoped
public class ESHolder {
#Inject
#Dedicated
ExecutorService eS;
public ExecutorService getES() {
return eS;
}
}
#Stateless
public ProjectService() {
// ...
#Inject
ESHolder esHolder;
public void performAsynchAction(List<String> taskIds, ...rest of args...) {
taskIds.stream().forEach(t -> {
// ...
esHolder.getES().submit(runner);
});
}
}