I am planning to use Spring State Machine to control an execution workflow. The system is expected to receive requests from multiple users and each user may be assigned to multiple workflows. My initial idea was to have one instance of SM per workflow and every time an user perform a step in the workflow, I would use its identifier to restore the machine from a persistent storage, input the new event and store the updated SM.
I've read around that initialising a SM is an expensive operation and some people recommend having a single instance of it, but "rehydrate" that instance with some data. My understanding is that this would be more effective, but I think it would become a "blocking" operation, in other words, one workflow would need to wait for the previous one to be finished/released before-hand. Since I'm newbie on this topic, can anyone shed some light on the best alternatives for my use case and perhaps pieces of code to illustrate the differences? (PS: I'm using v2.4.0)
I was first implementing the "rehydrate" mechanism because as you said, it made sense and was also used in the "persist" example of spring-statemachine.
Howewer, running performance tests against my API showed that using a single instance fails when using the StateMachine as an #Autowired Bean with the prototype scope as it is described in that example. What happens is that simultaneous requests against my API override that Statemachine Bean and the first request fails as the statemachine changes when writing back to the DB (i used redis).
So now I actually build a fresh statemachine everytime a request comes in and rehydrate that object:
public String getStatesGuest(HttpServletRequest httpServletRequest) throws Exception {
StateMachine<States, Events> stateMachine = stateMachineConfig.stateMachine();
resetStateMachineFromStore(httpServletRequest.getSession().getId(), stateMachine);
return convertToJson(buildGetStateResponse(stateMachine));
}
It still is very performant, I was testing with around 30 reqs/s and still got a median of 12ms. (Docker with 2 Cores for spring boot, 1 Core for redis).
Related
I am developing REST APIs using Java Spring framework.
When calling these APIs, I have a need to check for permissions, where I will need to make a call to the DB to get the permission data. The thing is, there are multiple areas checking for permission in a single request, and I do not want to make multiple calls to the DB, so I intent to cache the permission data just for that single request.
I have tried creating a request scoped bean, which works, but not for all cases. There are times where the request scoped bean cannot be created, for example when running a scheduled code using #Scheduled annotation, simply because it is not a request. Another case is when checking for permissions using WebSecurityConfigurerAdapter, the bean is also not yet created at that time.
So, I looked into another possible solution, which is this: https://github.com/rinoto/spring-request-cache. If I use this solution, I will need to remove the cache from threadLocal every time an operation is complete. I am not very comfortable of using this solution since I'm not an expert in Java, and I've read that it is not recommended to use threadLocal as cache.
What's the best way to achieve my goal? My ask is simple, cache some data only for that request. Is there any library that supports it?
I find it hard to believe that my ask is not a normal use case, or is it not a normal use case?
You can use ThreadLocal as a cache in this case. No need to clear. As per the documentation
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the {#code ThreadLocal} instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).
eg: ThreadLocal<Map<String, Object>> THREAD_LOCAL_DATA = ThreadLocal.withInitial(HashMap::new)
I have a Spring application that is controlled with an API that we need to be single threaded, but I can not figure out how to accomplish this. The application is a re-factoring of an app that is single threaded. They want the same basic design for the new version, while using our new programming methods (i.e. Java, Spring, etc.) and adding extra functionality.
There is an API resource to start the application:
#RequestMapping("/start")
public String startProcess(){...}
If this gets called twice then the application will start another thread. We want to stop this from happening. But, we still want the stop API resource to work:
#RequestMapping("/stop")
public String stopProcess(){...}
The app has a typical Spring structure:
#SpringBootApplication
public class MyApplication{...}
#RestController
public class MyController{
#Autowired
private MyService myService;
...}
#Service
#Transactional
public class CarolService{
#Autowired
private MyDAO myDAO;
...}
#Repository
public class myDAO{...}
How do I make sure that there is only one instance of this application running at a time? Please Help! And, thanks in advance!
You have actually two different problems: making your API single-threaded and making sure that there is only one instance of this application running at a time.
The solution is conceptually the same: you have to synchronize on some mutex. But it's much easier to do in the first case than in the second.
To make your API single-threaded you'll need to synchronize on something. If you have just one controller, just make API methods synchronized. If you have more than one controller, you'll need to create some application scope bean, inject it in every controller and synchronize on it. In old times there was also something like SingleThreadModel, but I think it was deprecated. Haven't seen it around for a few years but I won't be surprized if Spring would have a way of setting it somehow.
Making sure that there is only one instance of this application running at a time is much harder. You basically want to prevent anybody to start several copies of the application in parallel. One of the way to achieve this is to have some central shared resource like a database. On start-up the application will try to "acquire" the mutex by creating a record in some table (which would allow at most one record). If the record was created successfully, the application starts normally, if not then fails. You'll need some mechanism to detect stale mutex record - probably as simple as saving the timestamp in the mutex record and constantly updating it via scheduled task (heartbeat).
We recently had a similar task in an application running many instances of many microservices. We needed exactly one microservice to regularly execute certain maintenance task. We solved it by synchronising over a central MongoDB database. Microservices try to acquire the mutex by creating a document in a database collection. By design, at most one document may exist in that collection and the microservice which created the document performs the regular task and removes the document at the end. The collection is configured with an automatic clean-up so if the microservice failed to remove the document for whatever reason, it will be removed automatically by the database.
My program has to go through a learning step that takes around 15 mins to complete. The result of this learning is two Models stored into two public objects which will be then used in other classes. I put this learning step in the following method:
public void init()
So as to be performed at the start of the server. The problem is, every time the server reloads, it re-does the learning step. I have to wait another 15 minutes just to see the effects of a small change. I was wondering if there is a way to retain the value of some objects throughout the running of the program and the server. Here is my code:
public static Model model1;
public static Model model2;
#Override
public void init()
{
model1= readModel(source1)
model2= readModel(source2)
}
PS. I am using Servlets with JSP pages and Tomcat Server.
Make it a session- or application-scoped bean, as appropriate, and access it as a bean rather than a normal object.
As a general solution, I would suggest for you to keep the learning part and the model out of service container. Possibly a different VM / process. This way you will be able to retain the model for as long as the process is required to run, independent of the state of client process that is your tomcat.
DETAILED
You can achieve this in few steps
First, you need to migrate model preparation and caching to a different program. This program will run as a daemon and you can use Daemon by Apache to run it as a background service
Second, Assuming your daemon is up and running, your model consumer can communicate with the model VM using standard protocols. The selection of protocol depends on your exact requirements. It can be an API exposed over TCP/HTTP or RMI or anything else.
ALTERNATIVELY
As I suggested in comments, you can also dump the model binary to file system once the model is trained. Cache the model on tomcat startup. The io will be much faster than learning phase.
You could have a look here?
The Idea is either save session somewhere and put your model objects there or just use Hazelcast (overkill probably :))
I'm just getting into Spring (and Java), and despite quite a bit of research, I can't seem to even express the terminology for what I'm trying to do. I'll just explain the task, and hopefully someone can point me to the right Spring terms.
I'm writing a Spring-WS application that will act as middleware between two APIs. It receives a SOAP request, does some business logic, calls out to an external XML API, and returns a SOAP response. The external API is weird, though. I have to perform "service discovery" (make some API calls to determine the valid endpoints -- a parameter in the XML request) under a variety of situations (more than X hours since last request, more than Y requests since last discovery, etc.).
My thought was that I could have a class/bean/whatever (not sure of best terminology) that could handle all this service discovery stuff in the background. Then, the request handlers can query this "thing" to get a valid endpoint without needing to perform their own discovery and slow down request processing. (Service discovery only needs to be re-performed rarely, so it would be impactful to do it for every request.)
I thought I had found the answer with singleton beans, but every resource says those shouldn't have state and concurrency will be a problem -- both of which kill the idea.
How can I create an instance of "something" that can:
1) Wake up at a defined interval and run a method (i.e. to check if Service discovery needs to be performed after X hours and if so do it).
2) Provide something like a getter method that can return some strings.
3) Provide a way in #2 to execute a method in the background without delaying return (basically detect that an instance property exceeds a value and execute -- or I suppose, issue a request to execute -- an instance method).
I have experience with multi-threaded programming, and I have no problem using threads and mutexes. I'm just not sure that's the proper way to go in Spring.
Singletons ideally shouldn't have state because of multithreading issues. However, it sounds like what you're describing is essentially a periodic query that returns an object describing the results of the discovery mechanism, and you're implementing a cache. Here's what I'd suggest:
Create an immutable (value) object MyEndpointDiscoveryResults to hold the discovery results (e.g., endpoint address(es) or whatever other information is relevant to the SOAP consumers).
Create a singleton Spring bean MyEndpointDiscoveryService.
On the discovery service, save an AtomicReference<MyEndpointDiscoveryResults> (or even just a plain volatile variable). This will ensure that all threads see updated results, while limiting them to a single, atomically updated field containing an immutable object limits the scope of the concurrency interactions.
Use #Scheduled or another mechanism to run the appropriate discovery protocol. When there's an update, construct the entire result object, then save it into the updated field.
The background: there is a requirement to attach auditing data to persisted entities, basically creation-timestamp + user ID and last-update-timestamp + user ID.
I'm not keen on passing the user ID as a method parameter through all layers/components. So I need to somehow pass user identifcation (derived from HTTP headers, the details are unimportant) through a REST endpoint (using RESTEasy, but that's probably not important, either) back to the data access/repository layer.
I've thought of using ThreadLocal but it feels a little hackish and might fail in a non-blocking IO environment. Maybe I'm wrong about that, not sure.
I also have a vague idea that AOP could help, though I'm not well-versed in AOP so not sure.
Any strategies appreciated, with or without code.
You can use entity lifecycle callback methods for your requirement: #PrePersist, #PostPersist, #PreUpdate, #PostUpdate.
It is one of the auditing strategies mentioned here.
It turns out that Spring's SecurityContextHolder is a reasonable place to do this (don't ask why the application isn't already integrating "properly" with Spring Security). It's basically the ThreadLocal option but with some nice interface around it.
The tradeoff is that you need to be acutely aware of the thread-bound nature of this solution. A controller that somehow uses other thread to do the work that needs the user context, will need to take some steps to make sure those threads can get it since they don't, by default, inherit the ThreadLocal. There is a mode you can set on SecurityContextHolder that will use inheritance of the ThreadLocal in any newly created threads, but that does not help if a thread pool is used (since threads won't be created by the request thread but rather pulled from the pool). Even then, most thread pools provide a way for the client thread to do "something" when obtaining and releasing threads, so it's possible to pass the security context on that way.