计时器
计时器是一种 OutSystems 工具,允许在预定时间定期执行应用程序逻辑。这些也称为批处理作业batch jobs.。
不同的Timer可以同时执行,但是同一个Timer绝不会一次执行超过一个。
以下是您可以使用定时器的一些常见场景:
| 设想 | 例子 |
|---|---|
| 预定作业 | 每天在同一时间执行相同的工作。例如,每天凌晨 4 点向订阅者发送包含摘要新闻的电子邮件。 创建一个定时器来执行每天凌晨 4 点向订阅者发送电子邮件的操作 |
| 执行长时间运行的操作 | 执行通常需要很长时间才能完成的应用程序逻辑。例如,每个月的第一天凌晨2点,系统必须归档大量的数据库记录。大约需要2个小时。 创建一个计时器来执行一个归档记录的操作,并将其设置为在每个月的第一天凌晨 2 点运行,默认超时为 150 分钟(该值可以在服务中心进行调整)。 |
体系结构
下表列出了与计时器相关的 OutSystems 元素:
| 元素 | 描述 |
|---|---|
| OutSystems 调度程序服务 | 这是负责检查要执行的计时器的服务。它是一种多线程服务,允许同时执行不同的计时器。 |
| 运行时数据库 | 运行时数据库包含用于管理定时器的所有系统实体,例如: - 所有现有定时器的记录。 - 执行定时器的时间表。 - 定时器的当前执行:何时开始、超时或下一次执行。 |
| 日志数据库 | 执行计时器时,会在日志数据库中创建一个条目。 |
| 配置工具 | 该工具允许配置可以在每个前端服务器节点中同时执行的最大定时器数。 |
| 外系统日志 | 在服务中心,您可以访问环境中单个应用程序或所有应用程序的计时器日志。 |
| 已部署的模块(应用程序) | 已部署的应用程序包含计时器的代码。它具有在 Timer 执行的 Action 中设计的应用程序逻辑,以及使系统数据库更新有关 Timer 状态所需的一些存根代码。 |
运行时和日志数据库
本节介绍支持计时器的数据库实体及其功能。
实体 Meta_Cyclic_Job
该实体包含在模块中创建的计时器的定义,这些模块存储在ossys_Meta_Cyclic_Job数据库表的记录中。这些记录由 OutSystems 创建和管理,Effective_Timeout是唯一可以更改的属性。
以下是属性的完整描述:
| 属性 | 描述 |
|---|---|
| ID | 主键。 |
| Space_Id | 定义定时器的模块。 |
| 姓名 | 模块中定义的定时器名称。 |
| 默认_时间表 | 定时器的默认预定时间,如模块中所定义。 这是一个包含时间和定时器执行频率的字符串。它在 Service Studio 中有一个特殊的编辑器来设置它的值。 该值用于设置 Cyclic_Job_Shared 实体中的 Schedule 属性。 |
| 优先事项 | 模块中定义的定时器优先级。它是介于 1(最高)和 4(最低)之间的值。 当同时执行的 Timer 数量大于 Front-end Server 允许的最大值时,优先级最高的 Timer 先执行。 |
| 活跃 | 指示计时器是否处于活动状态。 |
| SS_Key | Service Studio 中的计时器键。 |
| 暂停 | 定时器默认超时,如模块中所定义。该值以分钟为单位。 如果 Timer 没有在这个时间限制内完成作业,则 Timer 执行将被系统中止。 |
| 有效超时 | 如果该值不为零,它将覆盖上面的定时器默认超时。 使用它来调整新的超时,这是在服务中心完成的,在计时器的详细信息页面中。 |
| 共享 | 当为 True 时,它表示 Timer 的实例是在Cyclic_Job_Shared实体中创建的,否则它们是在Cyclic_Job实体中创建的。 |
实体Cyclic_Job
该实体包含有关将由多租户模块中的调度程序服务执行的所有计时器的信息。您可以在服务中心浏览此信息(请参阅监控定时器的执行)。
由于可能有多个前端服务器节点执行定时器,每个节点都有自己的时间,因此执行定时器的时间参考始终是数据库时钟。
该实体的记录存储在数据库中的ossys_Cyclic_Job表中。它们由 OutSystems 创建和管理。
Schedule和Next_Run是您可以更改 的该实体的唯一属性。但是,不要在执行 Timer 时设置它们,这可以通过检查Is_Running_Since属性中的值来验证:********
- 如果设置: 定时器正在运行。
- 如果未设置: 定时器未运行。
以下是属性的完整描述:
| 属性 | 描述 |
|---|---|
| Meta_Cyclic_Job_Id | 对Meta_Cyclic_Job实体的引用 。 |
| 租户编号 | 对运行计时器的租户的引用。 |
| 日程 | Timer执行完毕后,该属性用于计算下一次执行的时间。 例如: Schedule:“02:00 10:00 18:00”(每天凌晨 2 点、上午 10 点和下午 6 点运行)。如果计时器在 10-23-2012 的 18:00:50 结束,则 Next_Run 将设置为 10-24-2012 的 2:00:00。此属性最初由Meta_Cyclic_Job实体的Default_Schedule 属性中定义的值设置,但可以在服务中心更改。******** |
| 上次运行 | Timer 开始最后一次执行的日期和时间(使用数据库时钟)。 |
| 下一步_运行 | 下一次执行的日期和时间(使用数据库时钟)。 调度程序服务执行具有Next_Run <= 当前日期时间的计时器。 |
| 最后持续时间 | Timer 完成最后一次执行所花费的时间(以秒为单位)。 |
| Is_Running_Since | 计划服务开始执行计时器的日期和时间(数据库时钟时间)。 此属性还用于同步多个前端服务器节点,因为调度程序服务不会执行具有此属性集的计时器(除非在错误恢复操作中)。 当 Timer 的执行完成时,该属性被清除。 |
| 正在运行 | 此属性具有执行计时器的前端服务器节点的名称。Is_Running_Since 属性也 已设置。 |
| Number_Of_Tries 次数 | Timer 连续执行失败的次数。 |
实体 Cyclic_Job_Shared
该实体包含由单租户模块中的调度程序服务执行的定时器的信息。您可以在服务中心浏览此信息(请参阅监控定时器的执行)。
由于可能有多个前端服务器节点执行定时器,每个节点都有自己的时间,因此执行定时器的时间参考始终是数据库时钟。
该实体的记录存储在数据库中的ossys_Cyclic_Job_Shared表中。它们由 OutSystems 创建和管理。
Schedule和Next_Run是您可以更改 的该实体的唯一属性。但是,不要在执行 Timer 时设置它们,这可以通过检查Is_Running_Since属性中的值来验证:********
- 如果设置: 定时器正在运行。
- 如果未设置: 定时器未运行。
以下是属性的完整描述:
| 属性 | 描述 |
|---|---|
| Meta_Cyclic_Job_Id | 对Meta_Cyclic_Job实体的引用。 |
| 日程 | Timer执行完毕后,该属性用于计算下一次执行的时间。 例如: Schedule: "02:00 10:00 18:00"(每天凌晨 2 点、上午 10 点和下午 6 点运行)。如果计时器在 10-23-2012 的 18:00:50 结束,则 Next_Run 将设置为 10-24-2012 的 2:00:00。此属性最初由Meta_Cyclic_Job实体的Default_Schedule 属性中定义的值设置,但可以在服务中心更改。******** |
| 上次运行 | Timer 最后一次开始执行的日期和时间。 |
| 下一步_运行 | 下次执行的日期和时间。 调度程序服务执行具有Next_Run <= 当前日期时间的计时器。 |
| 最后持续时间 | Timer 完成最后一次执行所花费的时间(以秒为单位)。 |
| Is_Running_Since | 计划服务开始执行计时器的日期和时间(数据库时钟时间)。 此属性还用于同步多个前端服务器节点,因为调度程序服务不会执行具有此属性集的计时器(除非在错误恢复操作中)。 当 Timer 的执行完成时,该属性被清除。 |
| 正在运行 | 此属性具有执行计时器的前端服务器节点的名称。Is_Running_Since属性也已设置。 |
| Number_Of_Tries 次数 | Timer 连续执行失败的次数。 |
表 oslog_Cyclic_Job_
这些表存储有关已执行计时器的所有日志记录信息。您可以在服务中心浏览它(请参阅检查计时器日志)。
以下是属性的完整描述:
| 属性 | 描述 |
|---|---|
| 立即的 | 计时器执行开始的日期和时间(服务中心中的“记录时间”)。 这是 IIS 时钟日期和时间。 |
| 期间 | 计时器完成执行所花费的时间(以秒为单位)。 |
| Cyclic_Job_Key | Service Studio 中的计时器键。 |
| Space_Id | 对创建计时器的模块的引用。 |
| 租户编号 | 对执行计时器的租户的引用。 |
| 执行者 | 执行计时器的前端服务器节点的名称(服务中心中的“服务器”)。 |
| 错误编号 | 对 [oslog_]Error_< N > 实体的引用。 如果设置,则表示执行计时器的应用程序逻辑时出错,并且在服务中心计时器日志页面中,计时器行中会显示一个名为“错误”的红色链接。 |
| 应该_有_运行_在 | 应该执行此 Timer 的日期和时间。 请注意,如果系统负载很大,则此值可能与 Instant 属性完全不同。这可能是因为同一个模块有很多租户并且都有相同的时间表,其他计时器执行时间太长等。 这是数据库时钟日期和时间。 |
| 下一步_运行 | 是一个日期时间,表示此 Timer 何时应该再次启动(基于时间表,如上所述)。 |
| 循环 | 供内部使用的记录周期数。 |
定时器是如何执行的
调度程序服务负责执行所有定时器。该服务是多线程的,因此它允许同时执行不同的定时器。为简单起见,以下步骤描述了单个定时器的执行。
执行Timers的步骤如下:
-
调度程序服务循环获取要执行的计时器 ( Next_Run )的数据库。
-
调度程序服务启动一个线程来执行定时器,该定时器在定义定时器的模块中调用 Web 服务以执行它。
-
Web 服务首先检查计时器是否已在任何前端服务器节点中执行。如果不是,则更新Cyclic_Job_Shared实体的 Is_Running_Since和Is_Running_By属性。这会锁定 Timer,使其无法在任何其他前端服务器节点中执行。****
-
该模块执行与定时器关联的动作。
-
动作执行完成后,清除Is_Running_Since和Is_Running_By属性,从而释放 Timer 以进行新的执行。 Next_Run 属性根据 Schedule 属性和当前日期和时间重新计算。
关于Next_Run属性,仅当它在操作执行期间未更改时才会更新。例如,如果操作更新该属性,就会发生这种情况。
-
包含有关计时器执行信息的记录将发送到日志服务,并将其存储在日志数据库中。
-
Web 服务将控制返回给调度程序服务,它现在准备好执行另一个计时器(步骤 1.)。
为什么定时器超时?
如前所述,调度程序服务通过调用在创建计时器的模块中构建的 Web 服务来执行计时器。这意味着计时器执行中涉及 Web 请求,并且与任何 Web 请求一样,允许它在服务器中执行的最长时间。这就是为什么计时器在 Service Studio 中具有“超时分钟数”属性的原因,默认情况下它设置为 20 分钟,但您可以根据每种情况进行调整。
超时在意外错误中的作用
如果 Timer 的执行由于意外错误而终止,只有在超时时间加上 20% 之后,Scheduler Service 才会恢复 Timer 并同步数据库。到那时,数据库中有关 Timers 的数据可能会不一致。
在 Timer 操作中实现逻辑也很重要,这样您可以确保在 Timer 执行意外终止的情况下数据保持一致。
执行错误后重试
每当 Timer 执行错误时,OutSystems 可能会再次执行 Timer 以进行多次重试。您可以在服务中心的“环境配置”屏幕的“管理”文件夹下设置此重试次数。默认情况下,它设置为 3 次重试。
动态更改定时器的时间表
除了为您的计时器设置定期和固定执行外,还可以根据您想要的逻辑动态安排计时器的执行。为此,只需编辑 Timer 操作,计算新的执行日期和时间,并在保存 Timer 执行信息的实体上更新它。
要访问所有必要的实体以设置动态执行,请执行以下操作:
-
在具有 Timer 操作的模块中,添加对以下系统实体的引用:
- 元循环作业
- 循环作业共享
-
计算下一次执行的日期和时间。
-
使用在步骤 2 中计算的值更新Cyclic_Job_Shared的Next_Run属性。****
例子:
考虑CleanUp Timer,它会定期从数据库中清理数据,并且会在最后一次执行结束 2 小时后执行。
打开 Timer 的动作并在流的末尾添加以下逻辑:
-
创建一个查询以获取计时器的Cyclic_Job_Shared记录。 Query 具有模块标识符 (eSpaceId)、Timer 名称和输入参数:
-
使用以下值设置查询参数:
- eSpaceId : GetOwnerSpaceIdentifier() 方法
- 计时器名称:“清理”
-
计算下一次执行日期和时间为从现在起2小时,并将其设置为Cyclic_Job_Shared记录的 Next_Run属性:AddHours(CurrDateTime(),2)****
-
更新数据库中的Cyclic_Job_Shared记录。
-
提交事务以清除对更新记录的锁定。
动作流程应该像这样结束:
在服务中心管理定时器
服务中心提供一组功能,允许您管理您的计时器,即:
- 监控定时器的执行
- 编辑定时器设置
- 强制执行定时器
- 停用/激活定时器
- 浏览以前执行的日志
监控定时器的执行
在 Service Center 中,您可以在Monitoring下的 Environment Health选项中监控计时器的执行。该页面有一个 Timers 部分,其中包含一个列表,显示了 Timers 的执行顺序。****
在列表中对计时器进行排序的标准基于以下内容:
- 计时器优先级。
- Timer 执行所需的时间,基于其之前的持续时间。执行时间较快的定时器首先执行。
- Timer 等待执行的时间。随着 Timer 等待时间的增长,它往往会在列表中上升。
下图是两个时刻Timers部分的例子,相差10分钟。
以Send Notifications Timer 为例,您可以看到:
- 它原定于 14:15:00 执行。
- 它实际上是在 14:14:10 执行的。
结论是 Timer 在预期之前执行。这可能是由于被应用程序明确唤醒或有人在服务中心强制执行。
检查计时器健康状况
在 Service Center 中,您可以在Environment Health选项中的 Monitoring下检查 Scheduler Service 正在执行的 Timer 线程。
在 Front-end Servers 部分中,单击Scheduler列中的详细信息链接以显示包含服务详细信息的页面。在这种情况下,关注与 Timer 相关的线程。****
在上面的示例中,调度程序服务具有以下与计时器相关的线程:
- Timers Fetcher是一个线程,它会时不时地被唤醒,以获取要执行的 Timer 作业,并将它们放入待挑选的队列中。目前,它正在睡觉。
- 有 3 个Timer Processor线程执行从队列中挑选 Timer 作业并执行它们。定时器处理器线程数在配置工具中配置。
您还可以得出以下结论:
- 没有定时器作业正在执行,因为所有定时器处理器线程都处于空闲状态。
- Queue没有条目,这意味着此时没有要执行的 Timer 作业 。
编辑定时器
您可以通过单击服务中心以下位置之一的计时器名称来编辑计时器:
- Module: 编辑定义Timer的模块,选择Timers选项卡,会显示Timers列表。
- 计时器日志: 转到计时器日志页面,列表中的每一行都有计时器名称。
- 环境健康: 转到环境健康页面,检查列表中每一行都有计时器名称的计时器部分。
在下面的示例中,您可以看到:
- 计时器每 15 分钟运行一次。
- 优先级设置为正常。
- 超时未设置,因此它是配置工具中的默认设置(20 分钟)。
- 最后一次执行发生在 08-01-2013 的 18:15:09。
- 下一次执行设置为 08-01-2013 的 18:30:00。
强制执行定时器
要在不等待下一次运行的预定时间的情况下强制执行计时器,请按页面底部的 “立即运行”按钮。
为已定义时间表的停用计时器按下 “立即运行” 按钮,将计时器设置为尽快运行并再次激活计时器。
停用/激活定时器
要停止执行计时器(由调度程序服务获取并消耗资源),请按页面底部的停用按钮。 调度程序服务将不再获取计时器。
如果定时器被停用,该按钮显示激活,您应该按下它以使定时器恢复工作。
检查计时器日志
在服务中心,您可以查看定时器的执行情况。为此,选择Monitoring下的Timers选项。如果出现错误,您可以单击错误链接查看详细信息。********
特性
| 姓名 | 描述 | 强制的 | 默认值 | 观察 |
|---|---|---|---|---|
| 姓名 | 标识定义范围内的元素,如屏幕、操作或模块。 | 是的 | ||
| 描述 | 记录元素的文本。 | 用于文档目的。 此属性的最大大小为 2000 个字符。 | ||
| 行动 | 定时器被唤醒时执行的动作。 | 是的 | ||
| 日程 | 安排定时器的开始时间和频率。 | 此属性的值只能使用 Timer Schedule Editor 指定。通过双击属性名称或单击“...”打开它。 | ||
| 先进的 | ||||
| 超时(分钟) | Platform Server 等待计时器执行结束的最长时间(分钟)。 | 是的 | 20 | |
| 优先事项 | 定义定时器的优先顺序。 | 是的 | 3 - 正常 | |
| 是多租户 | 设置为 Yes 为每个租户单独运行计时器,或设置为“No”为租户之间共享的数据运行一次。如果未设置,它将继承模块设置。 | 是的 |
运行时属性
| 姓名 | 描述 | 只读 | 类型 | 观察 |
|---|---|---|---|---|
| 日程 | 指示定时器被唤醒的时间和频率。 | 文本 | 设置此运行时属性时,您必须使用一种受支持的计划格式。计划格式区分大小写。示例:( "16:15"每天 16:15 唤醒定时器); "22:00 Mon Fri"(每周一和周五22:00唤醒定时器);(在每个月的第 16天的 15:30 "15:30 16"唤醒 Timer );(在每个月的第二个星期二 00:15唤醒计时器);(在每次 1-Click Publish 操作后唤醒 Timer)。 请注意,在开发时不进行格式验证。为 Schedule runtime 属性赋值时必须小心使用正确的格式,否则 Timer 可能无法运行。 "00:15 2nd Tue" "When Published" | |
| 最后一次 | 指示计时器自动或明确唤醒的最后一个日历日期和时间。 | 是的 | 约会时间 | |
| 下次运行 | 指示定时器计划唤醒的下一个日历日和时间。 | 是的 | 约会时间 |