为 Spring 应用程序寻找持久计时器

发布于 2024-12-05 08:57:14 字数 1026 浏览 4 评论 0原文

我正在寻找一个库,它允许我定义

  1. 一个工作人员,该工作人员将在未来的特定时间被调用一次(不需要重新安排/ cron 之类的功能),即计时器
  2. 工作人员应该接受一个上下文,其中包含一些参数/输入
  3. 都应该持久化在数据库(或文件)中workerworker
  4. 应该由spring管理——spring应该实例化worker,这样它就可以注入依赖项
  5. 能够通过API动态创建计时器,而不仅仅是通过静态创建计时器Spring XML beans

不错拥有:

  1. 支持集群,即拥有多个可以托管工作人员的节点。数据库中的每个存储作业都会导致在

我检查过的几种替代方案之一上执行一项工作,但没有一个满足要求:

  • Quartz

当使用 org.springframework.scheduling.quartz.JobDetailBean 使quartz 创建时 无法获得依赖注入(这将导致我使用我想避免的服务定位器)

您的工作实例(而不是通过 spring),因此您在使用时 org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 你无法获取上下文。您的 Worker 公开一个不接受参数的公共方法。此外,当使用 MethodInvokingJobDetailFactoryBean 时,您不能使用持久性(来自 Javadoc)

注意:通过此 FactoryBean 创建的 JobDetail 不可序列化,因此不适合持久作业存储。对于您希望将持久作业委托给特定服务方法的每种情况,您需要将自己的 Quartz 作业实现为瘦包装器。

  • Spring 的计时器和简单的 JDK 计时器不支持持久性/集群功能

,我知道我可以使用 DB 和 Spring(甚至 JDK)计时器来实现自己的功能,但我更喜欢使用 3r 方库。

有什么建议吗?

I'm looking for a lib that allow me to do

  1. define a worker that will be invoked once on a specific time in the future (not need the re-schedule / cron like featrure) i.e. a Timer
  2. The worker should accept a context which withe some parameters / inputs
  3. all should be persistent in the DB (or file) the worker
  4. worker should be managed by spring -- spring should instantiate the worker so it can be injected with dependencies
  5. be able to create timers dynamically via API and not just statically via spring XML beans

nice to have:

  1. support a cluster i.e. have several nodes that can host a worker. each store jobn in the DB will cause invokaction of ONE work on one of the nods

I've examined several alternatives none meets the requirements:

  • Quartz

when using org.springframework.scheduling.quartz.JobDetailBean makes quartz create your worker instance (and not by spring) so you can't get dependecy ijection, (which will lead me to use Service Locator which I want to avoid)

while using org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean you can't get a context. your Worker expose one public method that accepts no arguments.In addition when using MethodInvokingJobDetailFactoryBean you can't use persistence (form the Javadoc)

Note: JobDetails created via this FactoryBean are not serializable and thus not suitable for persistent job stores. You need to implement your own Quartz Job as a thin wrapper for each case where you want a persistent job to delegate to a specific service method.

  • Spring's Timer and simple JDK Timers does not support the persistence / cluster feature

I know I can impl thing myself using a DB and Spring (or even JDK) Timers but I prefer to use an a 3r party lib for that.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笑叹一世浮沉 2024-12-12 08:57:14

如果您想创建作业详细信息以在运行时生成触发器/作业详细信息,并且仍然能够在您的 bean 上使用 Spring DI,您可以参考 这篇博文,它展示了如何使用SpringBeanJobFactory 与 < 结合使用strong>ObjectFactoryCreatingFactoryBean 在运行时使用 Spring 注入的 bean 创建 Quartz 触发对象。

If you want to create the job details to generate triggers/job-details at runtime and still be able to use Spring DI on your beans you can refer to this blog post, it shows how to use SpringBeanJobFactory in conjunction with ObjectFactoryCreatingFactoryBean to create Quartz triggering objects at runtime with Spring injected beans.

肤浅与狂妄 2024-12-12 08:57:14

对于那些对 Quartz 替代方案感兴趣的人,请查看 db-scheduler (https ://github.com/kagkarlsson/db-scheduler)。持久任务/执行计划保存在单个数据库表中。它保证仅由集群中的调度程序执行一次。

  1. 是的,请参阅下面的代码示例。

  2. 当前仅限于单个字符串标识符,没有格式限制。调度程序将来可能会得到扩展,更好地支持作业详细信息/参数。

  3. 执行时间和上下文持久保存在数据库中。将任务名称绑定到工作线程是在调度程序启动时完成的。只要 Worker 实现了 ExecutionHandler 接口,就可以由 Spring 实例化。

  4. 参见 3)。

  5. 是的,请参阅下面的代码示例。

代码示例:

private static void springWorkerExample(DataSource dataSource, MySpringWorker mySpringWorker) {

    // instantiate and start the scheduler somewhere in your application
    final Scheduler scheduler = Scheduler
            .create(dataSource)
            .threads(2)
            .build();
    scheduler.start();

    // define a task and a handler that named task, MySpringWorker implements the ExecutionHandler interface
    final OneTimeTask oneTimeTask = ComposableTask.onetimeTask("my-onetime-task", mySpringWorker);

    // schedule a future execution for the task with a custom id (currently the only form for context supported)
    scheduler.scheduleForExecution(LocalDateTime.now().plusDays(1), oneTimeTask.instance("1001"));
}


public static class MySpringWorker implements ExecutionHandler {
    public MySpringWorker() {
        // could be instantiated by Spring
    }

    @Override
    public void execute(TaskInstance taskInstance, ExecutionContext executionContext) {
        // called when the execution-time is reached
        System.out.println("Executed task with id="+taskInstance.getId());
    }
}

For those interested in an alternative to Quartz, have a look at db-scheduler (https://github.com/kagkarlsson/db-scheduler). A persistent task/execution-schedule is kept in a single database table. It is guaranteed to be executed only once by a scheduler in the cluster.

  1. Yes, see code example below.

  2. Currently limited to a single string identifier for no format restriction. The scheduler will likely be extended in the future with better support for job-details/parameters.

  3. The execution-time and context is persistent in the database. Binding a task-name to a worker is done when the Scheduler starts. The worker may be instantiated by Spring as long as it implements the ExecutionHandler interface.

  4. See 3).

  5. Yes, see code example below.

Code example:

private static void springWorkerExample(DataSource dataSource, MySpringWorker mySpringWorker) {

    // instantiate and start the scheduler somewhere in your application
    final Scheduler scheduler = Scheduler
            .create(dataSource)
            .threads(2)
            .build();
    scheduler.start();

    // define a task and a handler that named task, MySpringWorker implements the ExecutionHandler interface
    final OneTimeTask oneTimeTask = ComposableTask.onetimeTask("my-onetime-task", mySpringWorker);

    // schedule a future execution for the task with a custom id (currently the only form for context supported)
    scheduler.scheduleForExecution(LocalDateTime.now().plusDays(1), oneTimeTask.instance("1001"));
}


public static class MySpringWorker implements ExecutionHandler {
    public MySpringWorker() {
        // could be instantiated by Spring
    }

    @Override
    public void execute(TaskInstance taskInstance, ExecutionContext executionContext) {
        // called when the execution-time is reached
        System.out.println("Executed task with id="+taskInstance.getId());
    }
}
我不吻晚风 2024-12-12 08:57:14

您的要求 3 和 4 对我来说并没有真正的意义:您如何将整个包(worker + work)序列化让它神奇地醒来并完成其工作?难道你的运行系统中的某些东西不应该在适当的时间执行此操作吗?这不应该是工人吗?

我的方法是这样的:创建一个 Spring 可以实例化并向其注入依赖项的计时器。然后,该计时器将从持久存储中加载其工作/任务,安排它们执行并执行它们。您的类可以是 java.util.Timer 的包装器,并且根本不处理调度内容。您必须自己实现集群相关的逻辑,以便只有一个 Timer / Worker 可以执行工作 / 任务。

Your requirements 3 and 4 do not really make sense to me: how can you have the whole package (worker + work) serialized and have it wake up magically and do its work? Shouldn't something in your running system do this at the proper time? Shouldn't this be the worker in the first place?

My approach would be this: create a Timer that Spring can instantiate and inject dependencies to. This Timer would then load its work / tasks from persistent storage, schedule them for execution and execute them. Your class can be a wrapper around java.util.Timer and not deal with the scheduling stuff at all. You must implement the clustering-related logic yourself, so that only one Timer / Worker gets to execute the work / task.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文