We have a Play-Project that uses PlayFramework 2.5.4 and MongoDB. We want to update our database daily. At the moment we check the time everytime we get a Request and update if a day is over.
That leads to some Problems:
The current player has to wait a quiet long time until the request finishes
it can happen that there is one day no update (but we want everyday one, even if nothing changes)
we have to modify every request we insert.
So i found already the documentation of AKKA and old stackoverflowquestions (like How to schedule task daily + onStart() in Play 2.0.4?). But the solutions donĀ“t work anymore.
Akka.system().scheduler()
is deprecated
system.scheduler()
gives compilingerrors (from docu) and i dont know if an import is missing or what else.
As i know you should use #inject since Version 2.4, but i cant find proper examples on how to use it with schedule or how to use it afterall
Actually all i want to do is call PlayerDBHandler.newDay() every day on the same time.
Thanks for Help
Without seeing the compilation errors, I'm guessing that system isn't defined. Expanding the example from the documentation, something like this should work.
public class SchedulingTask {
#Inject
public SchedulingTask(final ActorSystem system,
#Named("update-db-actor") ActorRef updateDbActor) {
system.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay
Duration.create(1, TimeUnit.DAYS), //Frequency
updateDbActor,
"update",
system.dispatcher(),
null);
}
}
system is injected, and you can also inject a reference to the actor. Alternatively, you can look up the actor ref from system.
Once you've adapted this to do what you want, declare SchedulingTask in a module.
package com.example;
import com.google.inject.AbstractModule;
import play.libs.akka.AkkaGuiceSupport;
public class MyModule extends AbstractModule implements AkkaGuiceSupport {
#Override
protected void configure() {
bindActor(UpdateDbActor.class, "update-db-actor");
bind(SchedulingTask.class).asEagerSingleton();
}
}
Finally, update your application conf to enable the module.
play.modules.enabled += "com.example.MyModule"
Related
I'm using JobRunr 6.0.0 (OSS) to execute recurring jobs in a Spring Boot backend (2.7.4). I use the Spring Boot starter jobrunr-spring-boot-2-starter that allows me to schedule a job with the annotation #Recurring. This works very well. My problem is when I want to "unschedule" a recurring job: removing (or commenting) the #Recurring annotation does not unschedule the job.
To be more specific, here's an example of how I use JobRunr to schedule a task that should happen every 30 seconds:
#Service
public class MyService {
#Recurring(cron = "*/30 * * * * *", id = "my-id")
public void doSomething() {
LOGGER.info("did something");
}
}
There's nothing very special in the configuration. The part of the application.properties related to JobRunr looks like this:
org.jobrunr.background-job-server.enabled=true
org.jobrunr.dashboard.enabled=false
org.jobrunr.background-job-server.worker-count=2
org.jobrunr.background-job-server.poll-interval-in-seconds=10
So far, everything is working as expected. The job is indeed executed every 30 seconds. And an entry in the JobRunr table in charge of keeping tracks of the recurring jobs (jobrunr_recurring_jobs) is properly added.
My problem is when I remove the #Recurring annotation or when I completely remove the bit of code that was scheduled recurently (because the code of my backend has to evolve and this particular bit is not useful anymore, or because there was a bit of refactoring, or...) For instance, my code would look like this:
#Service
public class MyService {
// #Recurring(cron = "*/30 * * * * *", id = "my-id")
// public void doSomething() {
// LOGGER.info("did something");
// }
}
In this situation, the code that was previously scheduled has disappeared. But the entry corresponding to the old job is still present in the jobrunr_recurring_jobs table. This results in many errors in the logs because JobRunr is trying to execute a bit of code that does not exist anymore.
I could manually delete the entry in the jobrunr_recurring_jobs table or use the provided dashboard to do so (though, I don't plan to keep the dashboard in the production environment). This is quite error-prone.
Is there a way to configure JobRunr so that it would "clean automatically" the recurring jobs that are not scheduled anymore?
There are a couple of ways to delete Recurring Jobs:
there is the dashboard as you mentioned - if you can keep it accessible internally only in your PRD environment, you can delete it via there
give your recurring job an id - then you can delete it programmatically
JobRunr Pro comes with a migration api that will not only allow you to migrate these jobs (or delete them if you want) but also gives you the option to add a test case so that your CI/CD fails if you have jobs that are scheduled in PRD but not available anymore in your current code.
To give your recurring jobs an id and delete them, see the example below:
#Service
public class MyService {
#Recurring(id = "my-id", cron = "*/30 * * * * *")
public void doSomething() {
LOGGER.info("did something");
}
}
And to delete them:
jobScheduler.delete("my-id");
I have my following job in Liferay 7.1 :
#Component(
immediate = true, property = {"cron.expression=0 5 10 * * ? *"},
service = CustomJob.class
)
public class CustomJob extends BaseMessageListener {
....
#Override
protected void doReceive(Message message) throws Exception {
// HERE I CALL A SERVICE FUNCTION TO INACTIVATE USER, SEND MAILS, READ FILES TO IMPORT DATA
RunnableService rs = new RunnableService();
rs.run();
}
....
}
And my RunnableService :
public class RunnableService implements Runnable {
#Override
public synchronized void run() {
// DO MY STUFF
}
}
The job is working great, but another instance of the job can be started even when the service execution from the first call hasn't finished.
Is there any solutions to kill the first process ?
Thanks,
Sounds like there are several options, depending on what you want to achieve with this:
You shouldn't interrupt threads with technical measures. Rather have your long-running task check frequently if it should still be running, otherwise terminate gracefully - with the potential of cleaning up after itself
You can implement your functionality with Liferay's MessageBus - without the need to start a thread (which isn't good behavior in a webapp anyway). The beauty of this is that even in a cluster you end up with only one concurrent execution.
You can implement your functionality outside of the Liferay process and just interact with Liferay's API in order to do anything that needs to have an impact on Liferay. The beauty of this approach is that both can be separated to different machines - e.g. scale.
I have this structure in my Service component in my Spring:
#Autowired
PointController controller;
#Autowired
ParametroService parametroService;
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
};
public void doValidationsTask() {
Parametro parametroTempo = parametroService.getParametro("1", "ATRC_MEC", "TEMPO_VERIFICACAO");
timer.scheduleAtFixedRate(
timerTask,
Integer.parseInt(parametroTempo.getValor()) * oneMinute,
Integer.parseInt(parametroTempo.getValor()) * oneMinute
);
}
All that I want is that after the Spring Application fully initializes it will execute the method run() inside the TimerTask. Then, after a given time in minutes that will be get from the parametroService.getParametro(), execute this task again.
I tried to follow this link from the docs:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-annotation-support
But seems that I can't dinamically sets the Delay time that a specific task will be executed
You can annotate your run() method with #EventListener or create a new such annotated method which will call run():
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
run();
}
If you don't use context which supports refresh() operation, you should be fine.
If you use such context (and you don't want run() to execute on context refresh) make sure you store this state within your bean.
More info on standard Spring events.
You are correct that annotation #Scheduled does not allow you to read delay parameter dynamically. For that reason and because this annotation takes delay parameter only in milliseconds or as crone expression which is not user friendly, I wrote my own utility that does it. The Utility is available as part of Open Source MgntUtils library. You will need to write your classes that will extend classes provided in the library and then you will get the desired functionality. But it does require a little bit of work. However the library comes with example package that has source code of working example with detailed explanation in javadoc. If you are interested library is available at Github and at Maven Central. In both places it is available with sources and javadoc. The desired feature is described in detail in javadoc. If you download and unzip javadoc into folder c:\tmp then look at URL file:///C:/tmp/javadoc/com/mgnt/lifecycle/management/backgroundrunner/package-summary.html for detailed description on how to use this feature. For working code example look in the sources at package com.mgnt.lifecycle.management.backgroundrunner.example
Also, there is an article that explains about the features of the library, except that this particular feature is not described in that article yet. Here is the link: Open Source Java library with stack trace filtering, Silent String parsing, Unicode converter and Version comparison
You can implement a spring SmartLifecycle interface. This will get invoked when Spring context is loaded completely. And Then you can start the timertask.
public class TimerTaskInvoker implements SmartLifecycle{
#override
public void start(){
timer.scheduleAtFixedRate(timerTask);
}
}
You can check the reference - https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html
#PostConstruct may be the annotation you need.
https://www.baeldung.com/running-setup-logic-on-startup-in-spring
You can use spring scheduler and specify the initialDelay and fixedRate using the #Scheduled annotation.
#EnableScheduling
class CustomScheduler{
#Scheduled(fixedRate = 1000, initialDelay = 1000)
public void taskYouWantToPerform() {
List<IntRaptMec> allPointments = getNotValidated();
for(IntRaptMec pointment : allPointments) {
controller.validate(pointment.getIdTemp());
}
}
}
For more details refer this
I am trying to use the last version to date (3.0.1) of RoboGuice on my new Android application using Android Studio 1.5 (stable).
Long ago, I dealt with Guice & RoboGuice but I took on some reading on how to use Roboguice with new improvements & features it got since.
The point here is that I want to use a custom module for custom bindings.
In my specific case I have a SoundManager class that provides tools to play multiple audio tracks at will with an internal pool of MediaPlayer. The main constructor takes the applicationContext that will be used to create new MediaPlayer. Furthermore this class ought to be a singleton :
If a track is to be played throughout the entire application, the SoundManager cannot be destroyed / recreated ;
One pool of MediaPlayer is enough, much like a ExecutorPool. It ought to be re-used whenever necessary for better resources management.
So I did the following :
Creating an interface exposing the default behavior of my SoundManager : play, stop, resume, release etc... ;
Implementing this interface in a fully working class ;
Creating a Module extending com.google.inject.AbstractModule with the following code :
#Override
protected void configure() {
bind(SoundManagerInterface.class).to(SoundManager.class).asEagerSingleton();
}
Now the whole point of this SO post :
where did RoboGuice.setBaseApplicationInjector() go ?? All articles I read with modules examples, the most recent as early as 2014, expose the same method : creating an Application class extending android.app.Application and in the onCreate() method, use RoboGuice.setBaseApplicationInjector(). But it does not exist ! The only available methods I have are :
RoboGuice.getOrCreateBaseApplicationInjector()
RoboGuice.destroyInjector()
RoboGuice.newDefaultRoboModule()
RoboGuice.overrideApplicationInjector()
RoboGuice.setUseAnnotationDatabases()
RoboGuice.injectMembers()
In my case I used getOrCreateBaseApplicationInjector() because it seemed to be the closest to setBaseApplicationInjector() and finally went on testing my code.
Suprise, it worked ! My SoundManager is properly created and the applicationContext is somehow injected (from where, I do not know, but I hope it's not the calling Activity or else I am done for leaking memory...) and audio tracks are indeed played.
But is the instance of my SoundManager that of a singleton ? No it is not. I tried injecting 3 of those and there are all differents object as the debugger is showing...
So what am I doing wrong ?
This link : https://github.com/roboguice/roboguice/wiki/Advanced-Custom-Bindings#register-the-module-with-roboguice cannot be reproduced in my code :/
The correct setup code is as per the wiki :
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
RoboGuice.getOrCreateBaseApplicationInjector(this, RoboGuice.DEFAULT_STAGE, RoboGuice.newDefaultRoboModule(this),
new SoundManagerModule(),
);
}
}
From your use case (persistence throughout the entire activity, start/stop etc), it sounds like you want to create a RoboService and inject the SoundManager into that. Please see the documentation on Services. Merely creating a Singleton will not allow you to completely avoid standard Android architecture patterns.
I want to execute a call to a particular method every minute, and it should get called with the server startup. This should be a single thread.
I tried using the CRON job , but am facing some issues with it.
Is there any way through which I can achieve it
Use ExecutorServices...
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate( new Runnable()
{
#Override
public void run()
{
// call your method here
}
}, 0, 1, TimeUnit.MINUTES );
For a similar task i am using a Quartz scheduler. It is very easy to use. My intervals are larger than a minute though, but this should not matter.
You have the option to specify how many threads your scheduler will be using in a config file.
http://quartz-scheduler.org/
http://quartz-scheduler.org/api/2.0.0/
If you are using JBoss (may also apply to other AS, I have no data on them), you may want to try the bundled quartz scheduler. It offers very finegrained job control. You don't have to use the bundled version though, and are free to use it as dependency on the AS of your choice.
You can use Spring Tasks to achieve this easily using annotations. They are in the context jars so you shouldn't have to add any new jars to achieve this.
In your appContext add (adjust the pool-size accordingly):
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="2"/>
<task:scheduler id="myScheduler" pool-size="2"/>
You'll need to pull in the appropriate namespace too:
xmlns:task="http://www.springframework.org/schema/task"
After you do all of this you should be able to just annotate the method you want to be called. Since you want your method called every minute you should use fixedRate:
#Scheduled(fixedRate=60000)
Doing this should force the call to run on startup and every minute thereafter. The time as you can probably see is set in milliseconds.
Execute a particular method every minute? This sounds like you need a Timer. Have a look at this article for more information. Timer executes the method at a background thread - why is it important to execute the method within your main thread?
class DemoThread extends Thread {
public void run() {
while(true) {
try {
sleep(60000);
}
catch(InterruptedException e) {
}
// call some random method here
}
}
}
Init the Thread and run it.
DemoThread thread = new DemoThread();
thread.start();