db-scheduler icon indicating copy to clipboard operation
db-scheduler copied to clipboard

add a recurring task after scheduler have been started.

Open Nikhil12894 opened this issue 3 years ago • 9 comments

I Have a use case where I Have to create a Task from UI. So I want to add a task after App has started as well as the schedular. `public class CronMain extends Example {

public static void main(String[] args) {
	new CronMain().runWithDatasource();
}

@Override
public void run(DataSource dataSource) {
	Schedule cron = Schedules.cron("*/10 * * * * ?");
	RecurringTask<Void> cronTask = Tasks.recurring("cron-task", cron)
			.execute((taskInstance, executionContext) -> {
				System.out.println("Task Instance-> " + taskInstance.getTaskName());
				System.out.println(Instant.now().getEpochSecond() + "s  -  Cron-schedule!");
			});

	final Scheduler scheduler = Scheduler.create(dataSource)
			.startTasks(cronTask)
			.pollingInterval(Duration.ofSeconds(1))
			.deleteUnresolvedAfter(Duration.ofSeconds(5))
			.build();
	ExampleHelpers.registerShutdownHook(scheduler);
	scheduler.start();
	
	// After Scheduler has started.
	Schedule cron1 = Schedules.cron("*/5 * * * * ?");
	RecurringTask<Void> cronTask1 = Tasks.recurring("cron-task1", cron1)
			.execute((taskInstance, executionContext) -> {
				System.out.println("Task Instance-> " + taskInstance.getTaskName());
				System.out.println(Instant.now().getEpochSecond() + "s  -  Cron-schedule!");
			});
	
	scheduler.add(cronTask1)//TODO  Expected ....
}

}` In My Understanding, the workaround for this is to create a separate scheduler for every Task. Shay my App has 10000 tasks then there will be 10000 schedulers one for each Task. since My App Have Different Scheduled times for every Task.

Nikhil12894 avatar Nov 20 '21 14:11 Nikhil12894

Many have asked about this. The important bit is that db-scheduler need to know about the implementation on startup, that cannot be added dynamically (and also, that is very likely not what you are trying to do either). The implementation of a task tells what code should be run when it finds a due execution for that task. You need to create the task that should run and feed it to the Scheduler on startup, but then you can, as in your example, add instances of that task at runtime. For RecurringTasks the schedule need to be known compile-time, you have to create a CustomTask that uses a Schedule persisted per task instans.

Here is an example: https://github.com/kagkarlsson/db-scheduler/blob/master/examples/features/src/main/java/com/github/kagkarlsson/examples/PersistentDynamicScheduleMain.java

kagkarlsson avatar Nov 22 '21 06:11 kagkarlsson

I will consider creating a superclass DynamicRecurringTask to make this a bit easier..

kagkarlsson avatar Nov 22 '21 06:11 kagkarlsson

I think, I am not able to explain my case let me try once more. My App is a Task Scheduling App(web app). Case 1- when the app is starting I know x no of task is going to schedule I scheduled those on startup. Case 2 - At some point of time a user come to and configure a new task and wants to schedule it, But it can be only done by stopping the scheduler then adding the new task and starting the scheduler again.

Is there any way to add the task without stopping the scheduler?

Nikhil12894 avatar Nov 23 '21 04:11 Nikhil12894

Yes, you can schedule execution at runtime. An example:

scheduler.schedule(myTask.instance("1045", Instant.now());

Is it recurring tasks or one-time tasks?

kagkarlsson avatar Nov 23 '21 11:11 kagkarlsson

It will be a recurring task. `

            List<ATSExecuter<TestData>> list = new ArrayList<>();

	for (int i = 0; i < 3; i++) {
		String cronExp = "*/%d * * * * ?";
		cronExp = String.format(cronExp, getRandomInteger(60, 15));
		Schedule cron = Schedules.cron(cronExp);
		ATSExecuter<TestData> cronTask = new ATSExecuter<>("cron-task" + i, cron, TestData.class);
		list.add(cronTask);
	}

	SchedulerBuilder schedulerBuilder = Scheduler.create(dataSource);
	Scheduler scheduler = schedulerBuilder
			.startTasks(list)
			.pollingInterval(Duration.ofSeconds(5))
			.deleteUnresolvedAfter(Duration.ofSeconds(5))
			.build();
	ExampleHelpers.registerShutdownHook(scheduler);
	scheduler.start();

	/*After Scheduler have started.*/
	Schedule cron1 = Schedules.cron("*/5 * * * * ?");
	ATSExecuter<TestData> cronTask1 = new ATSExecuter<>("After Scheduler Started", cron1, TestData.class);
	scheduler.schedule(cronTask1.instance("recurring"), Instant.now()); // not getting executed

`

Nikhil12894 avatar Nov 23 '21 13:11 Nikhil12894

but then you can, as in your example, add instances of that task at runtime

Doesn't that defeat the whole purpose of having a scheduler? If one needs to calculate what fires when and feed it to scheduler, what is the added value of a scheduler? Why does the scheduler need to know all used tasks beforehand?

kibertoad avatar Dec 30 '21 17:12 kibertoad

Doesn't that defeat the whole purpose of having a scheduler? If one needs to calculate what fires when and feed it to scheduler, what is the added value of a scheduler?

With the suggested solution, you only have to calculate the initial execution-time (using the Schedule). Though with the normal static RecurringTasks it is automatically handled.

The Scheduler need to know the mapping between task name and implementation. The alternative would be a bit crazy. The code to run need to be known compile-time.

kagkarlsson avatar Jan 01 '22 14:01 kagkarlsson

The Scheduler need to know the mapping between task name and implementation. The alternative would be a bit crazy.

Why can't random lambda be passed at a runtime?

With the suggested solution, you only have to calculate the initial execution-time (using the Schedule).

That feels confusing. Wouldn't it be perfectly sufficient to use boolean flag instead, because typically user wants either to fire a task right away and keep firing it each X units, or fire it in X units and keep doing so?

kibertoad avatar Jan 01 '22 14:01 kibertoad

Why can't random lambda be passed at a runtime?

You could design a task that handles that. Again, might require some api change to make the initial scheduling more intuitive, but it is currently possible. You have to handle serializing/deserializing the lambda yourself. As a feature supported out of the box, I think this has fairly low priority

That feels confusing. Wouldn't it be perfectly sufficient to use boolean flag instead, because typically user wants either to fire a task right away and keep firing it each X units, or fire it in X units and keep doing so?

Yeah, that is definitely an option. Might also make it more intuitive with some api changes

kagkarlsson avatar Jan 01 '22 15:01 kagkarlsson