Spring StateMachine reusable statemachine instance - java

I have spring state machine like in the image below:
I want the state machine to be started at the start of the app. And after that it should go in the Re-State where on some time (Scheduled) it go in State GetOrders with SubStates (GetA, GetB and GetC). After that if there is some error it should go in the error, otherwise if everything is okay it should go in the Re-State where it should wait for the Scheduler.
This is my config
#Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {
config.withConfiguration()
.autoStartup(true)
.machineId("orderMachine");
}
And this is the method for the scheduler:
#Scheduled(cron = "0 0 1 1 * *")
public void startStateMachine() {
StateMachine<States, Events> sm = factory.getStateMachine();
sm.start();
sm.sendEvent(Events.ReState);
}
Everything is working okay but I have noticed that every time this method executes, the stateMachine that is starting have different UUID with the previous one but the Id is same. So I think I am making multiple instances of the state machine. Is it possible to reuse the same state machine or not finishing the process. Because in my case most of the time the state of the machine should be in Re-State. It can be considered as waiting state.

Try to use SpringStateMachineService to get a state machine instance instead of explicitly retrieving it from StateMachineFactory. You can use default implementation provided by Spring:
#Bean
public StateMachineService<State, Event> stateMachineService(
final StateMachineFactory<State, Event> stateMachineFactory) {
return new DefaultStateMachineService<>(stateMachineFactory);
}
So, your code will look like:
#Scheduled(cron = "0 0 1 1 * *")
public void startStateMachine() {
// here we need to get stateMachineId from some storage
stateMachineService.acquireStateMachine(stateMachineId, true)
.sendEvent(Events.ReState);
}
In the code above you need to provide particular state machine ids. Usually, I store them in the database, query them and instantiate state machine for each one.
Persisting state machine context is out of scope of the question. See Persisting State Machine

Well your state machine should be most likely public and static. So that you would make sure by that there is only one instance of your machine.

Related

Spring state machine with JPA persistence- Repository usage

I am trying to figure out how to easily use spring state machine including persistence with JPA.
This is the problem I am dealing with:
Incompatible data types - factory and persistence
At a certain point in the program I would like to use the state machine which is connected to a user. There are repositories for that purpose (project spring-statemachine-data-jpa).
At first there is a check if a state machine already exists for a player, using the repository. If not, creating a new state machine and persist it.
The problem is that I have different types of state machines. The factory creates a StateMachine<UserState, UserEvent>, the repository returns a JpaRepositoryStateMachine. These are not compatible to each other and for me it is not clear how to persist / create / restore the state machines.
Can you please clarify that for me?
#Autowired
private StateMachineRepository<JpaRepositoryStateMachine> repository;
public someMethod(User user) {
Optional<JpaRepositoryStateMachine> stateMachine = repository.findById(user.getId()); // JPA state machine
if(stateMachine.isEmpty()) {
StateMachine<UserState, UserEvent> createdStateMachine = factory.getStateMachine(user.getId()); // spring state machine
repository.save(createdStateMachine); // compile error
}
// here: ready-to-use statemachine - how?
}
Thanks for your help!
Try to use SpringStateMachineService to get a state machine instance instead of explicitly retrieving it from repository or factory. You can use default implementation provided by Spring:
#Bean
public StateMachineService<State, Event> stateMachineService(
final StateMachineFactory<State, Event> stateMachineFactory,
final StateMachinePersist<WorkflowState, WorkflowEvent, String> stateMachinePersist) {
return new DefaultStateMachineService<>(stateMachineFactory, stateMachinePersist);
}
So, your code will look like:
#Autowired
private StateMachineService<State, Event> stateMachineService;
public someMethod(User user) {
StateMachine<State, Event> stateMachine = stateMachineService.acquireStateMachine(user.getId(), false);
// here: ready-to-use statemachine - call stateMachine.start() for example
}
If you go inside the acquireStateMachine method you can see that it queries state machine from repository by id and creates a new one if nothing found.
You can use JpaPersistingStateMachineInterceptor to implicitly save and update state machine instance on every change.
#Bean
public JpaPersistingStateMachineInterceptor<State, Event, String>
jpaPersistingStateMachineInterceptor() {
return new JpaPersistingStateMachineInterceptor(stateMachineRepository);
}
See Persisting State Machine

Clearing Cache using spring schedule?

I have the following code which implements a simple cache.
public Observable<String> getSomethingEveryoneWants(String key) {
final Map<String, String>localCacheReference = GlobalCache.cache;
return Observable.create(subscriber -> {
if(!localCacheReference.containsKey(key)) {
localCacheReference.put(key, doAHeavyCallToGetValueFor(key));
}
subscriber.onNext(localCacheReference.get(key));
subscriber.onCompleted();
}).subscribeOn(Schedulers.io()).map(String.class::cast);
}
I also want the ability to clear the cache depending upon some configuration: so I did something
//By default run every mid night. This should be defined in propFile
#Scheduled(cron = "${corn.cronString:0 0 0 * * *}")
public void clearCache() {
GlobalCache.cache = new ConcurrentHashMap<>();
}
Do you see any thing wrong with this approach?
My application starts OK and works as expected for a while. But starts to fail randomly after the clearCache run about 20-30 times. Is there any side affect i need to know?
Update: Its a Spring boot application. The application is throwing null pointer While executing restTemplate.exchange() after clearCache run about 20-30 times.
If i turn off/remove the #Schedule; I am not getting any errors restTemplate.exchange() works as expected. restTemplate.exchange() executes irrespective of #Schedule is running or not and does not depend upon the cache.
The issue is not appering if i clear the cache by any other method, like checking time while reading the cache, and clearing the cache.
I am not able to understand why the restTemplete is failing when #Scheduled is used.

JavaEE - EJB/CDI Method Duration Mechanism

not sure how to title this issue but lets hope description may give better explaination. I am looking for a way to annotate a ejb method or cdi method with a custom annotation like " #Duration" or someothing aaand so to kill methods execution if takes too long after the given duration period. I guess some pseudo code will make everything clear:
public class myEJBorCdiBean {
#Duration(seconds = 5)
public List<Data> complexTask(..., ...)
{
while(..)
// this takes more time than the given 5 seconds so throw execption
}
To sum up, a method takes extremely long and it shall throw a given time duration expired error or something like that
Kinda a timeout mechanism, I dont know if there is already something like this, I am new to javaEE world.
Thanks in advance guys
You are not supposed to use Threading API inside EJB/CDI container. EJB spec clearly states that:
The enterprise bean must not attempt to manage threads. The enterprise
bean must not attempt to start, stop, suspend, or resume a thread, or
to change a thread’s priority or name. The enterprise bean must not
attempt to manage thread groups.
Managed beans and the invocation of their business methods have to be fully controlled by the container in order to avoid corruption of their state. Depending on your usecase, either offload this operation to a dedicated service(outside javaee), or you could come up with some semi-hacking solution using EJB #Singleton and Schedule - so that you could periodically check for some control flag. If you are running on Wildfly/JBoss, you could misuse the #TransactionTimeout annotation for this- as EJB methods are by default transaction aware, setting the timeout on Transaction will effective control the invocation timeout on the bean method. I am not sure, how it is supported on other applications servers.
If async processing is an option, then EJB #Asynchronous could be of some help: see Asynchronous tutorial - Cancelling and asynchronous operation.
As a general advice: Do not run long running ops in EJB/CDI. Every request will spawn a new thread, threads are limited resource and your app will be much harder to scale and maintain(long running op ~= state), what happens if your server crashes during method invocation, how would the use case work in clustered environment. Again it is hard to say, what is a better approach without understanding of your use case, but investigate java EE batch api, JMS with message driven beans or asynchronous processing with #Asynchronous
It is a very meaningful idea – to limit a complex task to a certain execution time. In practical web-computing, many users will be unwilling to wait for a complex search task to complete when its duration exceeds a maximally acceptable amount of time.
The Enterprise container controls the thread pool, and the allocation of CPU-resources among the active threads. It does so taking into account also retention times during time-consuming I/O-tasks (typically disk access).
Nevertheless, it makes sense to program a start task variable, and so now and then during the complex task verify the duration of that particular task. I advice you to program a local, runnable task, which picks scheduled tasks from a job queue. I have experience with this from a Java Enterprise backend application running under Glassfish.
First the interface definition Duration.java
// Duration.java
#Qualifier
#Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
#Documented
#Retention(RetentionPolicy.RUNTIME)
public #interface Duration {
public int minutes() default 0; // Default, extended from class, within path
}
Now follows the definition of the job TimelyJob.java
// TimelyJob.java
#Duration(minutes = 5)
public class TimelyJob {
private LocalDateTime localDateTime = LocalDateTime.now();
private UUID uniqueTaskIdentifier;
private String uniqueOwnerId;
public TimelyJob(UUID uniqueTaskIdentifier, String uniqueOwnerId) {
this.uniqueTaskIdentifier = uniqueTaskIdentifier;
this.uniqueOwnerId = uniqueOwnerId;
}
public void processUntilMins() {
final int minutes = this.getClass().getAnnotation(Duration.class).minutes();
while (true) {
// do some heavy Java-task for a time unit, then pause, and check total time
// break - when finished
if (minutes > 0 && localDateTime.plusMinutes(minutes).isAfter(LocalDateTime.now())) {
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
System.err.print(e);
}
}
// store result data in result class, 'synchronized' access
}
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
public UUID getUniqueTaskIdentifier() {
return uniqueTaskIdentifier;
}
public String getUniqueOwnerId() {
return uniqueOwnerId;
}
}
The Runnable task that executes the timed jobs - TimedTask.java - is implemented as follows:
// TimedTask.java
public class TimedTask implements Runnable {
private LinkedBlockingQueue<TimelyJob> jobQueue = new LinkedBlockingQueue<TimelyJob>();
public void setJobQueue(TimelyJob job) {
this.jobQueue.add(job);
}
#Override
public void run() {
while (true) {
try {
TimelyJob nextJob = jobQueue.take();
nextJob.processUntilMins();
Thread.sleep(100);
} catch (InterruptedException e) {
System.err.print(e);
}
}
}
}
and in a seperate code, the staring of the TimedTask
public void initJobQueue() {
new Thread(new TimedTask()).start();
}
This functionality actually implements a batch-job scheduler in Java, using annotations to control the end-task time limit.

Task Execution and Scheduling in Spring

I'm new in spring. Please help me to understand what I have to use (TaskExecutor, #Sceduled,Quarts Sceduler,...) to implement this problem:
I have an Order object and Contacts (connected with 1:N relationship. One Order can have many Contacts). So
When Order is created, application have to send email to all connected Contacts.
When new Contact lately is created and connected to the already created Order, this Contact also have to get an email.
When Order will expire , 2 days later Contact have to get an email.
Step1:
When Order is created, application have to send email to all connected Contacts.
Add 2 new columns into Contacts Table ( or similar table).
is_Send_Email -> boolean type
Email_Send_Time -> timestamp/date type
While inserting a new row ( new order is created), set is_Send_Email=true and Email_Send_Time = current time. for all related Contacts.
2.When new Contact lately is created and connected to the already created Order, this Contact also have to get an email.
When adding a contact to the Order,set is_Send_Email=true and Email_Send_Time = Current time (while inserting) for newly added Contacts.
3.When Order will expire , 2 days later Contact have to get an email.
Set is_Send_Email=true for all contacts in that expiring order and Email_Send_Time = Current time+2 days.
Step2:
Enable scheduling using #EnableScheduling in your configuration class.
#Configuration
#EnableScheduling
public class AppConfig {
#Bean
public MyBean bean() {
return new MyBean();
}
}
Step3:
Use #Scheduled annotation to call your mail sending method at specific intervals.
As per Spring documentation..
34.4.2 The #Scheduled Annotation
The #Scheduled annotation can be added to a method along with trigger
metadata.
For example, the following method would be invoked every 5
seconds with a fixed delay, meaning that the period will be measured
from the completion time of each preceding invocation.
#Scheduled(fixedDelay=5000) public void doSomething() {
// something that should execute periodically
}
If a fixed rate execution is desired, simply change the property name
specified within the annotation. The following would be executed every
5 seconds measured between the successive start times of each
invocation.
#Scheduled(fixedRate=5000) public void doSomething() {
// something that should execute periodically
}
For fixed-delay and fixed-rate tasks, an initial delay may be
specified indicating the number of milliseconds to wait before the
first execution of the method.
#Scheduled(initialDelay=1000, fixedRate=5000) public void
doSomething() {
// something that should execute periodically
}
If simple periodic scheduling is not expressive enough, then a cron
expression may be provided. For example, the following will only
execute on weekdays.
#Scheduled(cron="*/5 * * * * MON-FRI") public void doSomething() {
// something that should execute on weekdays only
}
[Tip] You can additionally use the zone attribute to specify the time
zone in which
the cron expression will be resolved. Notice that the methods to be
scheduled must have void returns and must not expect any arguments. If
the method needs to interact with other objects from the Application
Context, then those would typically have been provided through
dependency injection.
Step4:
Check each record in Order table, if is_Send_Email=true for an record, then trigger email for that Order/Contacts whatever.
How to send email using Spring , You can refer this article.
Happy Learning :-)

How to Stop running singleton class multiple times in play framework

I have a singleton class in my play app. This singleton class is a long process which will generate reports from DB which consumes huge amount of memory. When i run my application in dev mode this singleton functionality is executing several times. I want this functionality to run only once. What should I do for that?
My code is:
public class DataGridManagerImpl extends ComponentContainer implements DataGridManager {
private static DataGridManager instance = null;
private DataGridManagerImpl(){
load();
}}
#Override
public void load() {
//Myreports function
}
public static DataGridManager getInstance(){
if (instance == null){
instance = new DataGridServiceManagerImpl();
}
return instance;
}
}
In my controller file inside a template function
DataGridManager dataGridMgr = DataGridManagerImpl.getInstance();
If i access the page it is executing the load reports function again.
Without code explaining how did you create your class it's hard to answer. From what I understand what you want is to run a process only once.
Problably the best approach is to use a Scheduled Job. This will trigger the process at a certain time, and Play ensures that only 1 instance of this process is running at the same time, even if the schedule would indicate another instance has to run. Let's say you have a process scheduled every hour and the process takes 3 hours. The initial process will be the only one running for 3 hours until it finishes.
Now, I would assume you want your process to be recurring as it generate reports. If not, if you only want to run it once, then you may want to use an asynchronous bootstrap job instead. This would run just once, at the beginning of the application.
EDIT on update: during development the #OnApplicationStart may execute several times, as Play may automatically reload the application when you do certain code changes. This is part of the dev process (the same that an #OnApplicationStart job won't start in Dev until the server gets a request).
As it's a job that you only want to run once, you may try to skip it in dev mode using the check:
if(Play.mode == Play.Mode.DEV)
If you need to run it at least once, add a dev-only url that you can access during dev to start the process.
Now, on your update you also mention that you are calling that code in a controller, and that every time the controller is acessed the method is called. That's expected. Singleton doesn't mean that it will run only once, but that there is only 1 object in the system. If in your controller you launch the calculation, that will happen everytime you access the controller.
SECOND EDIT (on comments): Arasu, the other issue is that you are calling the method load() when you construct the object. A singleton doesn't garantee that the object will only be constructed once. It garantees that, once constructed, only 1 object will exist. But it may happen that the object is removed by GC, in this case as per your code if you construct it again then you'll call load() and redo the processing.
The best solution is to not call "load" on constructor, but to force the user (you) to call it after retrieving the instance. An alternative is to set some flag at the beginning of load that detects if the code has been run. Be aware that Play is stateless, so that flag will need to be stored in the database.
the defition of a singleton is that it can run only once, it's practically the nature of the pattern. If you somehow manage to run it multiple times, you might have implementation errors in your singleton.
Recheck the singleton pattern in Wikipedia.
Edit:
This code makes it impossible to fetch more than one instance. How would you get more than one?
public class Singleton {
private static Singleton _instance;
private Singleton() { }
public static synchronized Singleton getInstance() {
if (null == _instance) {
_instance = new Singleton();
}
return _instance;
}
}
Or do you mean that you instanciate the Singleton class, instead of calling Singleton.getInstance()?
It is possible to have a Singleton doing a time consuming processing and be called the same time by two different threads. I think this is the situation here. The same Singleton object's method is called multiple times from the program.
I have run a little test... two thread calling the same Singleton object and here is the result
Thread[Thread 1,5,main] internal loop number = 0 Object = example.Singeton#164f1d0d
Thread[Thread 2,5,main] internal loop number = 0 Object = example.Singeton#164f1d0d
Thread[Thread 1,5,main] internal loop number = 1 Object = example.Singeton#164f1d0d
and here is the code.
package example;
public class Singeton {
private static final Singeton INSTANCE = new Singeton();
private Singeton() {}
public static Singeton getInstance(){
return INSTANCE;
}
public boolean doTimeConsumingThing(){
for (int i=0; i<10000000;i++){
System.out.println(Thread.currentThread() + " internal loop number = " + i + " Object = " + toString());
}
return true;
}
}
package example;
public class MulThread extends Thread{
public MulThread(String name) {
super(name);
}
#Override
public void run() {
while(true){
Singeton s = Singeton.getInstance();
System.out.println("Thread " + getId());
s.doTimeConsumingThing();
}
}
public static void main(String[] args) {
MulThread m1 = new MulThread("Thread 1");
MulThread m2 = new MulThread("Thread 2");
m1.start();
m2.start();
}
}
Please correct my notion above if i am wrong.
Hence what you need is a variable to keep track of the state of the time consuming procedure (i.e. a boolean isRunning) or the times the procedure has been called.
You can also make the pertinent time consuming method of the Singleton synchronized so only one thread can access the method while it is running (in my example if you make the doTimeConsumingThing() synchronized, the second thread will block until the singleton's method called from the first thread is finished.
Hope it helps
I had the same problem in DEV mode, and what I did is create a module for the tasks I don't want to be run at every #OnApplicationStart.
The trick is to launch those tasks in a overriden "onLoad()" method, in the module:
public void onLoad()
{
// tasks to run one time only
}
The onLoad() method is called one time only, not each time the application is restarted.
I don't know if this will help, but here are some things to check:
The code in your question is not thread-safe. You're missing the synchronized keyword in getInstance. That could cause the constructor to be called more than once by different threads.
Could DataGridManagerImpl be getting loaded by different classloaders? That static instance variable isn't static for the whole JVM, just static for that class' classloader.
load is public. Could some other code being calling that method?

Categories

Resources