-
-
Notifications
You must be signed in to change notification settings - Fork 192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ability to "pause" or disable tasks (recurring) #27
Comments
Hi, @kagkarlsson how is currently a recurring task is stopped? |
If you deploy a new version of the code where the Or are you talking of more temporary solutions? |
Apologies for the late response.
|
|
Thanks for the response. |
Yes, if you have some context data at scheduling-time that you want the task to have access to at execution-time you need to either encode it in the instance-id string, or use custom task-data |
Thanks, i was able to persist the task data. |
I was thinking about something like this: Setting This would enable to not necessarily have your application and task implementations to be aware of a "pause" feature (but they could, if they needed to, either by support i SchedulerClient or just updating In addition (and this is obviously further expanding the scope), db-scheduler could perhaps do some initial inspection on startup of the Edit: maybe a |
This enhancement would likely also enable this feature-request: #216 |
We might want to consider using something like |
@kagkarlsson Are there any plans to support the pause/resume feature ? |
@prem-cse Yes, but I cannot say when |
@kagkarlsson Is anybody working on it? If not then I would like to implement this as explained by @runeflobakk |
My original suggestion may be too specific for implementing as-is in db-scheduler, as I primarily use a certain subset of its features. @prem-cse It is possible to implement such a facility "outside db-scheduler", and I am happy to share how I have done it. The implementation does not change anything in db-scheduler, is fully separate from db-scheduler internals, and only uses its official API. We currently use the I have a separate table which acts as an "extension" to the standard
So, to make each execution triggered by db-scheduler "aware" of this added "enabled" flag, I have created an implementation of public class EnableSupportedVoidExecutionHandler<T> implements VoidExecutionHandler<T> {
private static final Logger LOG = LoggerFactory.getLogger(EnableSupportedVoidExecutionHandler.class);
private final TaskExecutionEnabler enabler;
private final VoidExecutionHandler<T> delegatedHandler;
private final AtomicBoolean loggedSkippedExecution = new AtomicBoolean(false);
public EnableSupportedVoidExecutionHandler(TaskExecutionEnabler enabler, VoidExecutionHandler<T> delegatedHandler) {
this.enabler = enabler;
this.delegatedHandler = delegatedHandler;
}
@Override
public void execute(TaskInstance<T> taskInstance, ExecutionContext executionContext) {
if (enabler.isExecutionEnabled()) {
loggedSkippedExecution.set(false);
delegatedHandler.execute(taskInstance, executionContext);
} else if (loggedSkippedExecution.compareAndSet(false, true)) {
LOG.info("Skipping execution of task '{}' ({}), because it is disabled", taskInstance.getTaskName(), taskInstance.getId());
}
}
} It contains the delegated execution handler, and an instance of ´TaskExecutionEnabler´ which only responsibility is to decide on each execution whether to proceed or not. Also has some facilities to log skipped execution at most once per instance, but it is not important. The ´TaskExecutionEnabler´ is a functional interface: @FunctionalInterface
public interface TaskExecutionEnabler {
boolean isExecutionEnabled();
} We have a class to interface with the public class ScheduledTasksExtension {
private final DataSource dataSource;
public ScheduledTasksExtension(DataSource dataSource) {
this.dataSource = dataSource;
}
public boolean isTaskEnabled(String taskName) {
String sql =
"""
SELECT enabled FROM scheduled_tasks_ext
WHERE task_name = ?
""";
try (Connection connection = dataSource.getConnection(); PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, taskName);
stmt.execute();
try (ResultSet resultSet = stmt.getResultSet()) {
if (resultSet.next()) {
return resultSet.getBoolean("enabled");
} else {
return true; // nothing explicitly configured, defaults to enabled: true
}
}
} catch (SQLException e) {
throw new RuntimeException(
"Unable to determine if task '" + taskName + "' is enabled, " +
"because " + e.getClass().getSimpleName() + ": '" + e.getMessage() + "'", e);
}
}
public TaskExecutionEnabler createTaskEnablerFor(String taskName) {
return () -> isTaskEnabled(taskName);
}
} So to tie all this together, here is an example for a made-up execution handler to send emails which is due: // typically a singleton, e.g. a Spring bean
ScheduledTasksExtension scheduledTasksExtension = new ScheduledTasksExtension(dataSource);
// per task
SendEmailsExecutionHandler sendEmails = new SendEmailsExecutionHandler();
String taskName = "send-emails-task";
VoidExecutionHandler<Void> sendEmailsWithEnableSupport = new EnableSupportedVoidExecutionHandler<>(
() -> scheduledTasksExtension.isTaskEnabled(taskName), sendEmails);
RecurringTask<?> sendEmailsTask = Tasks.recurring(
taskName, Schedules.fixedDelay(Duration.ofMinutes(1)).execute(sendEmailsWithEnableSupport)); If we want to disable a recurring task, we just insert a new row: INSERT INTO scheduled_tasks_ext (task_name, enabled) VALUES ("send_emails_task", false); To reenable it, we can flip the flag to true, or just remove the row, as the default is always that the task is enabled. Example query (PostgreSQL) to list scheduled tasks including the SELECT task_name, execution_time, enabled FROM scheduled_tasks
LEFT JOIN scheduled_tasks_ext USING (task_name); So to sum up, this is realized with a small database table, two classes, one functional interface, and every execution handler of ours needs to be wrapped in the A bit of code, so there may be a typo here and there, and perhaps some left out details, but this may get you and anyone else going, should you want to build support for this yourselves outside db-scheduler. The extra query which is performed for each execution triggered by db-scheduler obviously comes with a small performance hit, but for our cases this is negligible. So this is obviously not a suggestion on how first-class support for this could be implemented in db-scheduler, but to show that it is possible to implement this separately using only the APIs already offered by db-scheduler. We have had this mechanism running in production for 3 years with no problems. The way it is implemented should also make it easy to remove, should support for this be part of db-scheduler at a later time. |
Just wondering on the status of this issue. For our purposes, we just need to stop a task instance from being executed at the normal time (disabled) and then to enable it again. I'm using the scheduler to pull in cyber security feeds. If we see an issue with a feed, we would need to temporarily pause to check it and then enable it again. This way all the task history is kept intact. |
Add a method
SchedulerClient.pause(..)
to enable temporarily pausing the execution, i.e. not run when due.Consider adding status/state field to facilitate this. Candidates:
Additional use-cases this enables:
The text was updated successfully, but these errors were encountered: