We are using activiti for workflow in spring
I asked a question recently if it was possible to add an expression in timeDuration
Activiti Timer dynamic expression
I tried to put the expression like this
<timerEventDefinition>
<timeDuration activiti:expression="${myFlowDelegate.getTimeDuration(execution.parent.businessKey)}"/>
</timerEventDefinition>
I have a spring bean registered which has the logic to get timerDuration
public String getTimeDuration(String businessKey) {
Duration timer = Duration.ofHours(48);
if (businessKey.equals("x")) { //just for illustration
timer = Duration.ofHours(120);
}
log.info("Timer for {} is set to {}", businessKey, timer);
return timer.toString();
}
When I do this and start the spring application I get the following error
[Validation set: 'activiti-executable-process' | Problem: 'activiti-event-timer-missing-configuration'] : Timer needs configuration (either timeDate, timeCycle or timeDuration is needed)
I am not sure where did I go wrong
Related
I need to schedule a task to run after 2 minutes. Then when the time is up I need to check if we are still ONLINE. If we are still online I simple don't do anything. If OFFLINE then I will do some work.
private synchronized void schedule(ConnectionObj connectionObj)
{
if(connectionObj.getState() == ONLINE)
{
// schedule timer
}
else
{
// cancel task.
}
}
This is the code I am considering:
#Async
private synchronized void task(ConnectionObj connectionObj)
{
try
{
Thread.sleep(2000); // short time for test
}
catch (InterruptedException e)
{
e.printStackTrace();
}
if(connectionObj.getState() == ONLINE)
{
// don't do anything
}
else
{
doWork();
}
}
For scheduling this task should I use #Async? I may still get many more calls to schedule while I am waiting inside the task() method.
Does SpringBoot have something like a thread that I create each time schedule() gets called so that this becomes easy?
I am looking for something similar to a postDelay() from Android: how to use postDelayed() correctly in android studio?
I'm not sure about an exclusively spring-boot solution, since it isn't something that I work with.
However, you can use ScheduledExecutorService, which is in the base Java environment. For your usage, it would look something like this:
#Async
private synchronized void task(ConnectionObj connectionObj)
{
Executors.newScheduledThreadPool(1).schedule(() -> {
if(connectionObj.getState() == ONLINE)
{
// don't do anything
}
else
{
doWork();
}
}, 2, TimeUnit.MINUTES);
}
I used lambda expressions, which are explained here.
Update
Seeing as how you need to schedule them "on-demand", #Scheduling won't help as you mentioned. I think the simplest solution is to go for something like #Leftist proposed.
Otherwise, as I mentioned in the comments, you can look at Spring Boot Quartz integration to create a job and schedule it with Quartz. It will then take care of running it after the two minute mark. It's just more code for almost the same result.
Original
For Spring Boot, you can use the built in Scheduling support. It will take care of running your code on time on a separate thread.
As the article states, you must enable scheduling with #EnableScheduling.
Then you annotate your method you want to run with #Scheduled(..) and you can either setup a fixedDelay or cron expression, or any of the other timing options to suit your time execution requirements.
I'm running a scheduled task in my Spring application that runs a job. The job itself is fetched at the beginning of the task. After that a loop takes place that modifies the job in each iteration (++ a counter). After the loop I merge my instance using the entity manager. It works fairly well, but I'm facing an issue trying to modify the instance from another place. Since the instance has a 'paused' flag, I'm trying to set it. But whenever I do it's quickly reset again, due to the scheduled task unsetting it again (as far as I can tell).
Here's some code:
// This method is called using the #Scheduled annotation to be looping
// constantly with one second delay between invocations.
#Transactional
public void performActions() {
Job job = jobRepository.findFirstByPausedAtIsNull();
// Skip if no unpaused job exists
if(job == null) return;
// Iterate through batch of job actions
for(Action action : job.nextActions()) {
action.perform();
job.increaseActionsPerformedCount();
// Merge the action into the persistence context
entityManager.merge(action);
}
// Merge the job into the persistence context
entityManager.merge(job);
}
Now I'm trying to be able to pause the job at any time from the outside. I use a controller endpoint to call a pause method on the jobService. This method looks like this:
public Job pause(long id) throws JobNotFoundException, JobStatusException {
Job job = this.show(id);
if(job.getPausedAt() != null) throw new JobStatusException("The job is already paused");
job.pause(); // This sets the flag on the instance, same as job.setPausedAt(new Date())
return jobRepository.save(campaign); // Uses CrudRepository
}
Now calling the method works fine and it actually returns the Job with pausedAt set. But the value is reset quickly after.
I've tried just straight up fetching a fresh instance from the database at the end of performAction and setting the modified instance pausedAt to the freshly fetched one's value.
Any idea how this could be achieved properly?
As far as I understand , You need to stop the job when the pause flag is set ... you can achieve this by applying optimistic lock ... add a #Version field to Job .... apply LockModeType.OPTIMISTIC to the job that you retrieved in performAction() -either by adding it to the find() method or call a refresh() after retrieval -the first is better- ..... now if the other endpoint changes the pause flag the version field will be incremented and you will get OptimisticLockException at persisting .... this has some implications :
1- whatever state changes in the Job , the same behavior will happen (not only the pause field)
2- You will need to handle the Exception from inside the persistence context (i.e. inside performActions()) because after returning it might be mapped to any other exception type ... this is the idea I have now, may be there is something better that gives you more control (track only the pause attribute)
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.
Here I am using hibernate 4.0.1.Final,
For Example,
class MyClassListener extends DefaultPreLoadEventListener
{
#Override
public void onPreLoad(PreLoadEvent event)
{
<!-- do something -->
}
}
Hibernate EventListener Structure is,
1. pre ---> after completed,
2. run ---> want to stop this default listener.
3. post ---> This also no need.
In my Hibernate Service class, when I call entityManager.find(Employee.class, empId);
Before that MyClassListener will call. After Completing this listener process, I want to stop the Hibernate find method Listener. How it is possible? any one help me.
Following the documentation at the hibernate site
I believe all you need to do is to set this property:
javax.persistence.validation.mode = "none"
I have created simple example with #Singleton, #Schedule and #Timeout annotations to try if they would solve my problem.
The scenario is this: EJB calls 'check' function every 5 secconds, and if certain conditions are met it will create single action timer that would invoke some long running process in asynchronous fashion. (it's sort of queue implementation type of thing). It then continues to check, but while the long running process is there it won't start another one.
Below is the code I came up with, but this solution does not work, because it looks like asynchronous call I'm making is in fact blocking my #Schedule method.
#Singleton
#Startup
public class GenerationQueue {
private Logger logger = Logger.getLogger(GenerationQueue.class.getName());
private List<String> queue = new ArrayList<String>();
private boolean available = true;
#Resource
TimerService timerService;
#Schedule(persistent=true, minute="*", second="*/5", hour="*")
public void checkQueueState() {
logger.log(Level.INFO,"Queue state check: "+available+" size: "+queue.size()+", "+new Date());
if (available) {
timerService.createSingleActionTimer(new Date(), new TimerConfig(null, false));
}
}
#Timeout
private void generateReport(Timer timer) {
logger.info("!!--timeout invoked here "+new Date());
available = false;
try {
Thread.sleep(1000*60*2); // something that lasts for a bit
} catch (Exception e) {}
available = true;
logger.info("New report generation complete");
}
What am I missing here or should I try different aproach? Any ideas most welcome :)
Testing with Glassfish 3.0.1 latest build - forgot to mention
The default #ConcurrencyManagement for singletons is ConcurrencyManagementType.CONTAINER with default #Lock of LockType.WRITE. Basically, that means every method (including generateReports) is effectively marked with the synchronized keyword, which means that checkQueueState will block while generateReport is running.
Consider using ConcurrencyManagement(ConcurrencyManagementType.BEAN) or #Lock(LockType.READ). If neither suggestion helps, I suspect you've found a Glassfish bug.
As an aside, you probably want persistent=false since you probably don't need to guarantee that the checkQueueState method fires every 5 seconds even when your server is offline. In other words, you probably don't need the container to fire "catch ups" when you bring your server back online.