Skip to content

任务与触发器

这一页解释调度器最核心的模型:任务是什么,触发器是什么,任务数据和标识如何组织。

适用场景

  • 已经跑通过最小示例
  • 想理解 JobBuilder 提供了哪些真实能力
  • 需要配置任务数据、任务标识、并发选项

核心问题

soulsoft_scheduler 里,一个被调度的任务本质上是一个 IJobDetail。它至少包含这些信息:

  • key
  • state
  • trigger
  • jobData
  • typeInfo
  • allowConcurrencyExecution

对应源码里的公开抽象是 IJobDetail

核心概念

IJob

任务类只需要实现一个方法:

cangjie
public interface IJob {
    func execute(context: IJobContext): Unit
}

调度器触发时,会调用这个 execute()

IJobContext

任务运行时能拿到两个主要入口:

  • context.jobDetail
  • context.jobData

其中 jobData 实际来自 jobDetail.jobData

Key

任务标识由 namegroup 组成:

cangjie
let key = Key("cleanup", "maintenance")
println(key.toString()) // maintenance:cleanup

如果不传分组,默认是 DEFAULT-GROUP

常见用法

JobBuilder

JobBuilder 是配置任务的主要入口,当前源码里公开的方法有:

方法作用
create<T>()为某个 IJob 类型创建构建器
withCronTrigger(expr)使用 Cron 触发器
withIntervalTrigger(interval)使用固定间隔触发器
withTrigger(trigger)传入自定义触发器
withIdentity(name) / withIdentity(name, group)设置任务标识
withJobData(jobData)直接设置任务数据
withJobData(configure)用 Lambda 写入任务数据
allowConcurrencyExecution()允许同任务并发执行
build()生成 IJobDetail

任务数据

cangjie
let jobDetail = JobBuilder
    .create<ReportJob>()
    .withCronTrigger("0 0 8 * * ?")
    .withIdentity("daily-report", "reports")
    .withJobData { d =>
        d.set<String>("reportType", "daily")
        d.set<Int64>("retryCount", 3)
    }
    .build()

读取方式:

cangjie
public class ReportJob <: IJob {
    public func execute(context: IJobContext): Unit {
        if (let Some(reportType) <- context.jobData.get<String>("reportType")) {
            println("report type: ${reportType}")
        }
    }
}

暂停、恢复、移除

IScheduler 提供的公开操作包括:

  • scheduleJob(jobDetail)
  • pauseJob(key) / pauseJobs(matcher)
  • resumeJob(key) / resumeJobs(matcher)
  • unScheduleJob(key) / unScheduleJobs(matcher)
  • checkExists(key)
  • getJobDetails()

按分组暂停的写法:

cangjie
scheduler.pauseJobs { key => key.group == "reports" }

关于并发

当前库默认是不并发执行同任务的。源码和 README 都明确了这一点。

如果确实需要并发,可以显式开启:

cangjie
let jobDetail = JobBuilder
    .create<ReportJob>()
    .withCronTrigger("*/2 * * * * ?")
    .allowConcurrencyExecution()
    .withIdentity("report")
    .build()

但这个选项要慎用。任务执行时间长于触发间隔时,容易出现线程堆积。

常见问题

JobBuilder 的 build() 可以重复调用吗

不可以。build() 调用后,构建器不再可用——每次创建新任务都需要新的 JobBuilder 实例。

withIdentity 不传 group 会怎样

默认分组为 DEFAULT-GROUP。建议为关联任务设置统一的 group,方便后续批量操作。

allowConcurrencyExecution 开启后能限制并发数吗

不能。该选项只是开关——要么禁止并发,要么完全放开。如果需要控制并发数上限,需要在任务内部用信号量等机制自行控制。

生产建议

  • 默认保持禁止并发,除非你非常明确任务是幂等且可重入的
  • namegroup 尽量按业务域设计,方便暂停、恢复和批量操作
  • 任务参数放进 jobData,不要硬编码到任务类里

相关专题