With springboot is there a way to make the default crud methods provided by the #RepositoryRestResource annotation asynchronous(with mongodb)? Meaning for example when i make 1000 save or find method(database) request, the thread doesnt wait for every single request to complete, it makes a new thread for each save() request, instead of executing each database request sequentially on one thread.
Related
We started a new project with Quarkus and Mutiny, and created a bunch of endpoints with Quarkus #Funq, everything has been working fine so far. Now we want to process something very time-consuming in one of the endpoints, and what we are expecting is, once user clicks a button to send the http request from frontend and hits this specific endpoint, we are going to return 202 Accepted immediately, leaving the time-consuming operation processing in another thread from backend, then send notification email accordingly to user once it completes.
I understand this can be done with #Async or CompletableFuture, but now we want to do this with Mutiny. Based on how I read Mutiny documentation here https://smallrye.io/smallrye-mutiny/guides/imperative-to-reactive, runSubscriptionOn will avoid blocking the caller thread by running the time-consuming method on another thread, and my testing showed the time-consuming codes did get executed on a different thread. However, the http request does not return immediately, it is still pending until the time-consuming method finishes executing (as I observe in the browser's developer tool). Did I misunderstand how runSubscriptionOn works? How do I implement this feature with Mutiny?
My #Funq endpoint looks like this
#Inject
MyService myService;
#Funq("api/report")
public Uni<String> sendReport(MyRequest request) {
ExecutorService executor = Executors.newFixedThreadPool(10, r -> new Thread(r, "CUSTOM_THREAD"));
return Uni.createFrom()
.item(() -> myService.timeConsumingMethod(request))
.runSubscriptionOn(executor);
}
Edit: I found the solution using Uni based on #Ladicek's answer. After digging deeper into Quarkus and Uni I have a follow-up question:
Currently most of our blocking methods are not returning Uni on Service level, instead we create Uni object from what they return (i.e. object or list), and return the Uni on Controller level in their endpoints like this
return Uni.createFrom().item(() -> myService.myIOBlockingMethod(request)).
As #Ladicek explained, I do not have to use .runSubscriptionOn explicitly as the IO blocking method will automatically run on a worker thread (as my method on Service level does not return Uni). Is there any downside for this? My understanding is, this will lead to longer response time because it has to jump between the I/O thread and worker thread, am I correct?
What is the best practice for this? Should I always return Uni for those blocking methods on Service level so that they can run on the I/O threads as well? If so I guess I will always need to call .runSubscriptionOn to run it on a different worker thread so that the I/O thread is not blocked, correct?
By returning a Uni, you're basically saying that the response is complete when the Uni completes. What you want is to run the action on a thread pool and return a complete response (Uni or not, that doesn't matter).
By the way, you're creating an extra thread pool in the method, for each request, and don't shut it down. That's wrong. You want to create one thread pool for all requests (e.g. in a #PostConstruct method) and ideally also shut it down when the application ends (in a #PreDestroy method).
How can i call 3 different GET rest apis asynchronously in Spring Boot? Currently its taking alot of time to execute this apis sequentially. Let me know how to do this asynchronously?
You can use async-http-client as given in the following url : https://www.baeldung.com/async-http-client
2.You can use AsyncRestTemplate. In AsyncRestTemplate object you need to send the following three parameters.
* endpoint uri,
* request entity with headers,
*and response object.
Catch all those in to a ListenableFuture object where implement the override methods of callback in the case of failure and success.
For both of these approach, you have to create request objects and call the services. And the call backmethod will capture the result in the response objects. You can merge responses together and then do your business.
You can use #EnableAsync annotation at the configuration level to enable async processing and #Async at the method level which needs to be invoked asynchronously.
For further details please refer to the below link
https://www.baeldung.com/spring-async
We are using Jetty+Spring. My WebService HostService receives N requests in parallel (Logged the time as soon as request arrived to my webservice) but when tried calling Transactional add method, something similar to below snippet
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ClassA {
#Transactional
public Host add(Host host) {
//logging time
Thread.sleep(100);
}
}
Now From code service I made the call to ClassA's add method, and logged the time, only 8 out of 100 request are reaching here at a time, and then when one finishes other starts.
I have already tries removing Thread.sleep with actual webservice call and a local process call, that doesn't help. But when I remove #Transactional, all requests comes at the same time to the add method, so problem is with #Transactional.
I want to understand
how #Transactional actually works, and why it limits to 8 calls in a batch, can I change this batch to some higher number.
All my classes are of scope prototype, so on what its trying to grab the lock on?
What should I do, to process all the requests in parallel, as my app in not db dependent it just calling other webservices(3), I don't need any lock, I just need the thread level lock, so that I can rollback if one of the webservice fails.
I have a little bit trouble with Integration Test and the transactions.
I have a Rest Service System. Behind all I have a JPA-Repository, with a Postgres database. Now to test them I build JunitTest where I made the calls on the System. The test loads the web-context and an other xy-context where I have the configuration of security and database connections. On the test method I have the #Transactional annotation.
The test makes 2 requests (This is only one example I have more of similar scenarios on other Object):
insert a new user
on this user create a Group and after bind this to the user
The test makes the first call, and returns me a id where I use to perform the second call.
The second call take the id and make the post and there I have several problems.
Details of the second call:
Test make a post on a controller
Controller takes the request and forward it to the Service
Service method (with #Transactional) take the request and do:
a research to find the inserted user
insert a group object
update the user with the groupId (generated on point 2)
Now one of the problems I had, it was a AccessDeniedException on point 3.1, because I have also ACL, and I have to check if there are enough permissions.
One of the things that I tried to do is to set:
#Transactional(propagation=Propagation.REQUIRES_NEW)
on the Service Method.
What I get after is the result that the AccessDeniedException was disappeared but the research at 3.1 gives me empty result (the research is ok, because on other scenario I have correct results), but is strange because the first post was ok, and how I understand Spring handles the #Transactions and "commits" to database so that a commit is performed when a transaction is closed. This brings me to an other idea to try: remove the #Transaction annotation on the test, but when i made this, then the database has all the data of this scenario until the end of the tests session (If you have a lot of test this is not desirable), and this is not a very good thing.
Now I wrote a little bit where are my doubts, and problems without posting a lot of code and of privacy problems, but on request I can post little pieces of codes.
It's also probable that the approach is incorrect.
The questions are:
-how can I make this service work?
-It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
-It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
Txs a lot.
To make test I use mockMvc to make the request and some annotation on the class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = { ..... })
#Transactional
public class tests {
#Test
public void aTest(){
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter(new DelegatingFilterProxy("springSecurityFilterChain", webApplicationContext), "/*")
.build();
mockMvc.perform(post(.....))
}
}
To answer your question:
It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
No really, but you can. Because you are doing two requests, the second depends on the first, and http request will not remember your transaction, if you insist to do it, you need flush your session between requests.
It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
It depends. REQUIRES_NEW means it will start new transaction, the influence is that everything in the existing transaction will be invisible in the new transaction, because the old one is not commited yet! if this server is the entry point of the transaction, it makes no difference, but be aware of the visibility problem.
how can I make this service work?
OK, forget what my answers of the previous questions. If I have to write the test, I will do it this way:
The test is not transactional. If you are doing integration test, you don't need to rollback single tests. If you wanna rollback the commit, then you are having wrong task case, you should have two test cases insert user and update group.
3 parts of the test
Send request to insert user and get the ID (single transaction)
Send request to update group(another transaction)
Send request to fetch the user and do the checks.
Hope this can help you.
if there is a synchronized block in the service() method of say for example in ActionServlet of struts, how will multiple requests/threads work if it is a busy site having large number of hits.
Will each thread wait for the next other one to release lock from the synchronized block? Will that create delay in response
Don't synchronize the service method of a servlet.
If you synchronize the service method of a servlet, you are in fact making a "reservation on access" for a thread at a time for that instance of the Servlet.
The Struts ActionServlet class is a HttpServlet and basically the doGet and doPost methods are of interest here. If we are to speak about Struts, the process method is the main entry point, but the same principle applies to all methods as it does for the general service method.
The idea is this.
When you declare a servlet in your web.app, the servlet container (e.g. Tomcat) will create only one instance of that servlet. This means there is only one instance to serve all requests.
If more requests arrive at the same time, each request thread gets it chance at the service method because there is no synchronization enforced.
If you have 10 request threads, each will execute concurrently in the service method. This is normally safe because processing done in the service method does not involve any state related to the current request it is handling. You go into issues if you add state to your servlets. Here is an article with more details on the subject.
Now back to Struts.
Struts uses a pattern called a Front Controller with the ActionServlet being that controller. This will in turn delegate specific requests to specific Action classes as specified in its configuration (a.k.a struts-config.xml).
All incoming request pass though here. If you place synchronization at this point (the Struts process method or the servlet service method higher up) you are reserving the servlet for a thread at a time. In case of struts, you are reserving all processing of a request to a single thread at a time.
That means that if 10 request arrive simultaneousely, in the case without synchronization all can execute side by side, while in the case with synchronization request 2 will have to wait until request 1 is done, 3 waits for 2 and so on (i.e. requests are sequentially processed). And this means poor performance.
Maybe for the lucky user that made request 1 there will be no performance impact but number 10 will have to wait. Then how about number 100? 200?
There is no need to synchronize the entry point if you program your application with thread safety in mind. If your application is of the sort that you just can't avoid synchronization, then synchronizing the entry point will reduce performance.
P.S. Just one other thing. If you are thinking into moving the synchronization lower in the process, namely the Action classes, note that they are not thread safe either and there is only one instance of it inside the Struts framework.