跳转至

定时任务(Task)定义编写指南

目标:Agent 直接生成/修改 workspace 定时任务。知识以本文为准。不写原理;不依赖外链。

iScript:写 taskScript / terminateScript 时,先读 iscript-usage(含 GraalVM 差异) → task.md;本文只定调度字段与落盘(无文档/用户上下文)。

术语:实体类 cn.myapps.core.common.model.task.Task;产品「任务 / 定时任务」;设计器「应用-常用工具-任务」。是软件级 iScript 定时调度,**不是**流程待办(TaskInfo)、**不是**流程节点定时审批 Job、**不是**表单名偶然叫 task 的业务单据。

依赖:挂在**软件(Application)**下;软件须 activated=true 且企业域已绑定该软件,job 进程才会真正执行。startupType≠禁止 时由 Quartz(IscriptTaskJob)按 cron/runningTime 触发。

产出物一览

部分 落盘 形态
定时任务 task/{任务名}.task 单文件;JAXB 根 taskid 为根属性
storage/workspace/{软件名}.application/task/{任务名}.task

路径相对 storage/workspaceModelSuffixTASK_PATH_SUFFIX/TASK_FILE_SUFFIX=taskTASK_FILE_GROUP=/task

新建最低配置:

  1. 目录已存在:{软件}.application/task/
  2. {name}.taskidnameparentId=软件 id、type=1startupTypeperiod、非空 taskScript
  3. periodrunningTime / rTime / rDate / daysOfWeek / dayOfMonth / interval(见 §3)
  4. terminateScript 可空 CDATA;常用计数字段置 0
  5. 保存到设计器/job 侧后:startupType 决定是否注册 Quartz(纯落盘文件在 job 进程扫描/设计态保存 后才会调度)

约定:

  • JAXB;根 taskid根属性
  • 脚本用 CDATA:taskScriptterminateScript(及基类 description/remark
  • 文件名 = name + .task;同软件 task/name 不重名(设计态校验「任务名称已存在!」)
  • name 勿含 / % \(落盘替换为 =47/=37/=92
  • parentId = 软件 idapplicationid 基类**无** @XmlElement,落盘常缺;靠路径归属 / API 保存时 set
  • **勿**放到 module/ 下;永远在应用级 task/
  • 布尔以外字段用整型字面量(type/period/startupType 等)
  • runningTime:ISO-8601 或带时区的 xs:dateTime 串,如 2025-10-21T12:10:00.248+08:00

1. 心智模型

软件 Application(activated)
  └─ task/*.task          ← 本文;设计态定义 + iScript
        ▼ 保存 / InitJobScheduler.start(appId)
 Quartz:jobName=taskId,jobGroup=applicationId
        IscriptTaskJob
        ├─ 软件未激活 → return
        ├─ terminateScript 返回 Boolean true → deleteJob
        └─ Task.execute() → type=SCRIPT 跑 taskScript

企业域 Domain 管理端「定时任务」
  → 汇总域已绑定软件下各 .task 的运行态(监控/启停入口)
概念 说明
任务内容 taskScript 触发时执行的 iScript;无 Document / 无 WebUser 业务会话(runner 用空 Document + params)
终止条件 terminateScript 每次触发前跑;返回 Boolean true删 Job 并跳过本次 execute
启动类型 startupType 手动 / 自动 / 禁止 → 决定是否注册 Job、是否立刻按 cron 挂起
重复 period 映射 Quartz cron 或一次性;决定 UI 要哪些时间字段
运行态 state 设计盘常见 0;设计器 start API 会设 1不作为「是否调度」主开关(主开关是 startupType
累计次数 runtimes/totalRuntimes/executedCount 历史字段;现行 Job **不再回写**文件累加

与其它调度区分:

对象 用途
.task / IscriptTaskJob 应用级定时脚本(本文)
流程定时审批 / 跳过审批 Job 流程节点,不落 task/*.task
NotificationJob 通知类,不同实体
T_TRIGGER 等库表 历史/其它触发器;现行 Task 文件系统

2. Task 属性 → .task XML

属性表

属性 XML 类型 默认/样例 说明
id 根属性 string 须生成 __ + 短 UUID;亦为 Quartz jobName/triggerName
name 子元素 string 必填;文件名;应用内唯一
parentId 子元素 string = 软件 id
applicationid 常不落盘 string API 侧 = 软件 id
description CDATA string 可空 列表描述
remark CDATA string 基类备注;少用
type 子元素 int 1 仅脚本TASK_TYPE_SCRIPT=10x1);UI 只有此项
runningTime 子元素 dateTime 调度锚点;由 rDate+rTime 或当前时刻合成(见 §3)
interval 子元素 int 1 period 为每分/每时时:间隔分钟数或小时数
period 子元素 int 重复类型;见 §3 常量表
runtimes 子元素 int 0 历史「运行次数」;≥0(JSR @Min(0)
terminateScript CDATA string 可空 终止条件脚本;返回 Boolean
taskScript CDATA string 任务正文 iScript
modifyTime 子元素 dateTime 修改时间;设计器保存刷新
creator 子元素 string 创建人显示名
creatorid 子元素 string 创建人用户 id
totalRuntimes 子元素 int 0 总运行次数(文件可不更新)
state 子元素 int 0 运行状态标记;start API→1
startupType 子元素 int 0 手动 / 1 自动 / 2 禁止
daysOfWeek 重复元素 int period=32 每周;Calendar:1周日…7周六;可多个
dayOfMonth 子元素 int 1 period=512 每月第几天 1–31;其它 period 样例常仍写 1
repeatTimes 子元素 int 0 历史「一天中运行次数」;生成可 0
frequency 子元素 int 0 历史频率;生成可 0
executedCount 子元素 int 0 历史当日已执行次数;生成可 0
rDate 子元素 string yyyy-MM-dd仅不重复 period=0 用;其它常空串
rTime 子元素 string HH:mm:ss;日/周/月/不重复必填

daysOfWeek XML 形态

JAXB @XmlElement + Collection<Integer>,每周勾选时多个同名元素:

<daysOfWeek>2</daysOfWeek>
<daysOfWeek>4</daysOfWeek>
<daysOfWeek>6</daysOfWeek>

空集合:元素可省略。设计器 checkbox label:1=周日 … 7=周六(与 java.util.Calendar.DAY_OF_WEEK 一致)。cron 生成时映射:1→Sun7→Sat

id 生成

统一规则:__ + 短 UUID。示例:__MpEzTToulqZtNEFisw6改 id 等于换 Job 键;勿与其它任务冲突。

设计态校验

条件 文案/效果
name {*[page.name.notexist]*}
同应用其它任务同名 任务名称已存在!
日/周/月且 rTime {*[core.task.choosetime]*}
不重复且 rDate {*[cn.myapps.core.task.select_running_time]*}
不重复且 rTime {*[core.task.choosetime]*}
每分 interval 不在 0–60(前端) 提示输入 0–60
每时 interval 不在 0–3600(前端) 提示

设计器创建 API 会强制:parentId=applicationIdapplicationid=applicationId、新建时 dayOfMonth=1(即使非每月)。手写包应自己保证 parentId 正确。


3. period / startupType / 时间字段

startupTypeTaskConstants

常量 行为
0 STARTUP_TYPE_MANUAL 注册 Job,addObpmJob(..., startNow=false)按 cron 挂,不立刻 startNow
1 STARTUP_TYPE_AUTO 注册 Job,默认 startNow=true
2 STARTUP_TYPE_BANNED deleteJob;不调度

自动运维:job 模块 InitJobScheduler.start(applicationId) 对软件下全部任务按上表注册/删除。

period(重复类型;注意是十六进制常量,十进制原样写入 XML)

十进制 十六进制 常量 UI 文案 loop cron 要点 必填时间字段
0 REAPET_TYPE_NOTREAPET / REPEAT_TYPE_NONE 不重复 false ss mm HH dd MM ? yyyyYEAR,一次性) rDate+rTime → 合成 runningTime
8192 0x2000 REPEAT_TYPE_IMMEDIATE 立刻 false 无 crongetCron 返回 null)→ 用当前毫秒触发后删 设计器不采 rDate/rTime;runningTime≈now
34 0x22 REPEAT_TYPE_DAILY_MINUTES 每分 true 0 0/interval * * * ? interval(分钟);runningTime≈now
546 0x222 REPEAT_TYPE_DAILY_HOURS 每时 true 0 0 0/interval * * ? interval(小时);runningTime≈now
2 0x2 REPEAT_TYPE_DAILY 每日 true ss mm HH * * ?(取 runningTime 的时分秒) rTime
32 0x20 REPEAT_TYPE_WEEKLY 每周 true ss mm HH ? * Sun,Mon,... rTime + daysOfWeek
512 0x200 REPEAT_TYPE_MONTHLY 每月 true ss mm HH dayOfMonth * ? rTime + dayOfMonth

loop=false(不重复/立刻):TriggerExecutor 执行完后 deleteJob

setDate 合成规则(设计器/API):

period runningTime 算法
2 / 32 / 512 解析 rTime=HH:mm:ss,套到「今天」日历的时分秒
0 解析 rDate++rTime = yyyy-MM-dd HH:mm:ss
34 / 546 / 8192 runningTime = 当前时刻格式化回解析

手写文件:直接写对齐的 runningTime + rTime(及需要的 rDate/daysOfWeek/dayOfMonth/interval)。日/周/月样例常 rDate 为空串。

interval 与前端限制

  • period∈{34,546} 有意义;其它保存时前端常强制写 1
  • 每分:建议 1–60
  • 每时:建议 1–合理小时数;前端上限校验按 3600

4. 执行与脚本环境

触发链

  1. Quartz 触发 → TriggerExecutorIscriptTaskJob.execute
  2. findById 任务;null → deleteJob
  3. 软件 null 或 !activated → return(不删 Job)
  4. terminateScript 非空:runner.initBSFManager(null, params, null, null)Boolean true → deleteJob return
  5. task.execute():目前仅 type==TASK_TYPE_SCRIPT(1)
  6. JavaScriptFactory.getInstance(applicationid)ParamsTablesessionid=TaskScriptInfo_yyyy-MM-ddapplication=applicationid
  7. initBSFManager(new Document(), params, null, [])空文档
  8. runner.run(ScriptLabel TYPE.TASK.SCRIPT, taskScript)
  9. finally 关 session/connection

脚本约束(相对表单/视图脚本)

定时任务
环境变量(产品表) (无 doc、无 user、无字段上下文)
返回值 **无**要求(不消费 return;副作用执行即可)
getApplication() 可用(绑定当前软件 id)
Document API 可用 getDocumentProcess() / getDocProcess(appId) 等自行查建文档
数据源 queryByDSName / updateByDSName / DB.* / sys_function.DATASOURCENAME
设计态 SQL 服务 亦可见 DataSourceDesignTimeService*(文档示例);与运行态 DB.* 场景不同,按环境选用
#include 常见 #include "basic" / "baselibrary"
推荐外壳 IIFE:(function(){ ... })()

terminateScript

(function () {
  // 返回 true → 删除调度并不再执行 taskScript
  return false;
})()

必须能求值为 Boolean;其它类型不触发停止。空 CDATA / 空白 → 跳过终止检查。

最小任务脚本

(function () {
  println("do something...");
})()

常用模式(样例浓缩)

按数据源名改业务表:

(function(){
  var sql = "update tlk_xxx set item_status='5' where ...";
  updateByDSName("数据源name", sql);
})()

查文档 / 建文档(须自己设 domainid、WebUser):

(function(){
  var process = getDocumentProcess();
  var formProcess = getFormProcess();
  var Form = formProcess.doViewByFormName("表单名", getApplication());
  var params = createParamsTable();
  var userProcess = getUserProcess();
  var userv = userProcess.getUserByLoginno("loginno", domainid);
  var webuser = new (Java.type('cn.myapps.core.web.WebUser'))(userv);
  var zdoc = process.doNew(Form, webuser, params);
  zdoc.setDomainid(domainid);
  zdoc.addStringItem("字段名", "值");
  process.doCreate(zdoc);
})()

发邮件:

var WebUser = new (Java.type('cn.myapps.core.web.WebUser'))(getUserById(userId));
var EmailUtil = new (Java.type('cn.myapps.core.util.mail.EmailUtil'))(WebUser);
EmailUtil.sendEmailBySystemUser(email, subject, html);

设计态 DS 执行(文档用例,定时场景偶用):

var process = Packages.cn.myapps.designtime.common.service.DesignTimeServiceFactory
  .resolve("cn.myapps.designtime.datasource.service.DataSourceDesignTimeService");
process.queryInsert(dsName, sql, getApplication());
const DataSourceDesignTimeServiceImpl =
  new Packages.cn.myapps.designtime.datasource.service.DataSourceDesignTimeServiceImpl();
DataSourceDesignTimeServiceImpl.createOrUpdate(dataSourceName, sql, applicationId);

注意:定时任务脚本里若硬编码 domainid,多域部署会漏域;样例有「扫 t_domain + 每域执行」写法。


5. 完整 XML 模板

每日自动(最常见)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task id="__YourTaskIdHere0001">
  <name>每日示例任务</name>
  <parentId>软件UUID</parentId>
  <description></description>
  <type>1</type>
  <runningTime>2026-07-15T08:00:00.000+08:00</runningTime>
  <interval>1</interval>
  <period>2</period>
  <runtimes>0</runtimes>
  <terminateScript><![CDATA[]]></terminateScript>
  <taskScript><![CDATA[(function () {
  println("daily task");
})()]]></taskScript>
  <modifyTime>2026-07-15T08:00:00.000+08:00</modifyTime>
  <creator>admin</creator>
  <creatorid>用户UUID</creatorid>
  <totalRuntimes>0</totalRuntimes>
  <state>0</state>
  <startupType>1</startupType>
  <dayOfMonth>1</dayOfMonth>
  <repeatTimes>0</repeatTimes>
  <frequency>0</frequency>
  <executedCount>0</executedCount>
  <rDate></rDate>
  <rTime>08:00:00</rTime>
</task>

每周(工作日 09:30)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task id="__WeeklyTaskId0000001">
  <name>每周工作日任务</name>
  <parentId>软件UUID</parentId>
  <description></description>
  <type>1</type>
  <runningTime>2026-07-15T09:30:00.000+08:00</runningTime>
  <interval>1</interval>
  <period>32</period>
  <runtimes>0</runtimes>
  <terminateScript><![CDATA[]]></terminateScript>
  <taskScript><![CDATA[(function () {
  println("weekday task");
})()]]></taskScript>
  <modifyTime>2026-07-15T09:30:00.000+08:00</modifyTime>
  <creator>admin</creator>
  <creatorid>用户UUID</creatorid>
  <totalRuntimes>0</totalRuntimes>
  <state>0</state>
  <startupType>1</startupType>
  <daysOfWeek>2</daysOfWeek>
  <daysOfWeek>3</daysOfWeek>
  <daysOfWeek>4</daysOfWeek>
  <daysOfWeek>5</daysOfWeek>
  <daysOfWeek>6</daysOfWeek>
  <dayOfMonth>1</dayOfMonth>
  <repeatTimes>0</repeatTimes>
  <frequency>0</frequency>
  <executedCount>0</executedCount>
  <rDate></rDate>
  <rTime>09:30:00</rTime>
</task>

每月 1 号 12:10

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task id="__MonthlyTaskId000001">
  <name>每月汇总</name>
  <parentId>软件UUID</parentId>
  <description></description>
  <type>1</type>
  <runningTime>2026-07-01T12:10:00.000+08:00</runningTime>
  <interval>1</interval>
  <period>512</period>
  <runtimes>0</runtimes>
  <terminateScript><![CDATA[]]></terminateScript>
  <taskScript><![CDATA[(function () {
  println("monthly");
})()]]></taskScript>
  <modifyTime>2026-07-01T12:10:00.000+08:00</modifyTime>
  <creator>admin</creator>
  <creatorid>用户UUID</creatorid>
  <totalRuntimes>0</totalRuntimes>
  <state>0</state>
  <startupType>1</startupType>
  <dayOfMonth>1</dayOfMonth>
  <repeatTimes>0</repeatTimes>
  <frequency>0</frequency>
  <executedCount>0</executedCount>
  <rDate></rDate>
  <rTime>12:10:00</rTime>
</task>

不重复(指定日期时刻一次)

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<task id="__OnceTaskId000000001">
  <name>单次任务</name>
  <parentId>软件UUID</parentId>
  <description></description>
  <type>1</type>
  <runningTime>2026-12-31T23:00:00.000+08:00</runningTime>
  <interval>1</interval>
  <period>0</period>
  <runtimes>0</runtimes>
  <terminateScript><![CDATA[]]></terminateScript>
  <taskScript><![CDATA[(function () {
  println("once");
})()]]></taskScript>
  <modifyTime>2026-07-15T10:00:00.000+08:00</modifyTime>
  <creator>admin</creator>
  <creatorid>用户UUID</creatorid>
  <totalRuntimes>0</totalRuntimes>
  <state>0</state>
  <startupType>1</startupType>
  <dayOfMonth>1</dayOfMonth>
  <repeatTimes>0</repeatTimes>
  <frequency>0</frequency>
  <executedCount>0</executedCount>
  <rDate>2026-12-31</rDate>
  <rTime>23:00:00</rTime>
</task>

每 5 分钟 / 每 2 小时

  • period=34interval=5,cron:0 0/5 * * * ?
  • period=546interval=2,cron:0 0 0/2 * * ?
  • startupType 按需;rTime/rDate 可空;runningTime 写当前合理时刻即可

禁止调度

同一文件改 <startupType>2</startupType>。设计器保存会 deleteJob;仅改文件需 job 重载/进程侧再次 init。


6. 设计态 / Job API(便于对照,非必须手调)

设计器基路径(典型):/api/designtime/applications/{applicationId}/tasks

方法 路径 作用
GET .../tasks 列表;searchwordpageNolinesPerPage
GET .../tasks/{taskId} 详情
POST .../tasks?rTime=&rDate= 新建;body=Task JSON;daysOfWeek 数组;随后 insertOrUpdate Job
PUT .../tasks/{taskId} 更新;同步 Job
DELETE .../tasks body=id 数组;先 deleteJob 再删文件
PUT .../tasks/{id}/start state=1(历史启停 UI)

Quartz 键:jobName=taskIdjobGroup=applicationIdtriggerName=taskIdtriggerGroup=applicationId。Job XML 序列化 IscriptTaskJob(含 taskId/applicationId/loop/period/startupType)。


7. 部署与生效清单

  1. 软件目录存在且 parentId 指向该软件 id
  2. 文件在 …/task/{name}.task文件名=name
  3. 企业域 绑定 该软件;软件 activated=true
  4. **job 服务**运行(obpm-job / Quartz);保存任务或 InitJobScheduler 扫描后 Job 入库
  5. startupType≠2;否则不会跑
  6. 脚本依赖的默认库 / 具名数据源、表单名、角色、邮件、第三方 Token 等在目标环境可用
  7. 多节点:以 Quartz 集群/共享调度为准,避免重复执行需集群配置正确

仅复制 .task 到 workspace 而不**触发设计态保存/init:**可能不进调度。运维侧需重启 job 或走 API 保存。


8. 与其它技能边界

内容 本文 其它
.task 字段、period/startupType、脚本外壳、cron 对应
软件目录骨架、task/ 分组存在性 交汇 APPLICATION_SKILL
数据源 name、*ByDSName、设计态 DS 服务 脚本消费 DATASOURCE_SKILL
表单字段/Activity 脚本里 doViewByFormName 创建文档时 FORM_SKILL
角色 id/roleNo 脚本选人发信等 ROLE_SKILL
流程待办 / TaskInfo 流程运行时
Widget system_workflow 待办摘要 WIDGET_SKILL

附录 A:TaskConstants 速查

TASK_TYPE_SCRIPT          = 1          (0x1)
STARTUP_TYPE_MANUAL       = 0
STARTUP_TYPE_AUTO         = 1
STARTUP_TYPE_BANNED       = 2
REAPET_TYPE_NOTREAPET     = 0
REPEAT_TYPE_NONE          = 0
REPEAT_TYPE_DAILY         = 2          (0x2)
REPEAT_TYPE_DAILY_MINUTES = 34         (0x22)
REPEAT_TYPE_DAILY_HOURS   = 546        (0x222)
REPEAT_TYPE_WEEKLY        = 32         (0x20)
REPEAT_TYPE_MONTHLY       = 512        (0x200)
REPEAT_TYPE_IMMEDIATE     = 8192       (0x2000)
RUNNING / STOPPING        = 字符串文案 "Running" / "Stopped"(展示用)

附录 B:后缀常量(ModelSuffix)

常量
TASK_PATH_SUFFIX / TASK_FILE_SUFFIX task
TASK_FILE_GROUP /task

附录 C:常见失败

现象 原因
文件在但不执行 软件未激活 / 域未绑定 / job 未加载 / startupType=2
保存报名称已存在 同应用另一 .taskname 冲突
保存报选时间 日周月缺 rTime;或不重复缺 rDate/rTime
立刻/不重复只跑一次后消失 loop=false,执行后 deleteJob(预期)
terminate 后不再调度 terminateScript 返回了 true
脚本 NPE / 无用户 定时无登录态;须自建 WebUser / 写死或查用户
SQL 影响 0 行 / 错库 *ByDSName 用的是数据源 name;动态表在默认库
每周不触发 daysOfWeek 缺失或值不是 1–7;runningTime 时分秒与 rTime 不一致
每月日错 dayOfMonth 未改(创建 API 默认 1)
改名找不到 文件名与 <name> 不一致
根元素错误 必须小写 task
id 写成子元素 改为根属性
放进 module 移到应用级 task/
与流程「任务」混淆 本文是定时脚本;流程待办不是 .task

附录 D:生成检查清单

  • 路径:storage/workspace/{软件}.application/task/{name}.task
  • <task id="...">name=文件名去后缀parentId=软件 id
  • type=1startupType∈{0,1,2};period 为附录 A 合法十进制值
  • taskScript CDATA 可执行;建议 IIFE;依赖表/源/用户已存在
  • 按 period 填齐 rTime/rDate/daysOfWeek/dayOfMonth/interval,且与 runningTime 一致
  • 计数字段可全 0terminateScript 可空 CDATA
  • 同应用 name 不冲突;生效路径已考虑 job 注册与软件激活