JOB执行时间不断推后的问题

工作中我们经常用Oracle的JOB执行一些定时任务,实践中我们发现,设定执行时间和间隔后,每次执行的时间都会有点延迟,经过一段时间后,推迟累计的效应就相当明显,必须要重新调整时间才能满足要求,为什么会出现这种现象呢?经过研究,我们发现了问题所在。下面举例说明这个问题。

建立一个JOB,内容为插入系统时间到数据库,执行间隔为1分钟,即inteval是sysdate+1/(24*60),我们发现记录的时间是不断推迟的,即:

2012-06-27 12:32:08
2012-06-27 12:33:13
2012-06-27 12:34:18
2012-06-27 12:35:23
2012-06-27 12:36:28
2012-06-27 12:37:33
2012-06-27 12:38:38

检查JOB的执行时间,发现也是不断推后的,发生这种现象的原因是什么呢?

原因是计算下次执行时间用的间隔是sysdate+1/(24*60),可能是JOB的启动要时间或者是扫描精度的原因,计算下次执行时间时用的标准时间已经不是启动JOB的时间,而是推迟几秒,所以下次执行时间会不断推迟,找到问题所在,解决起来也就简单了,那就是选一个标准时间计算下次执行时间。如果每分钟执行一次,我们可以将当前时间截取到分钟作为标准时间,

inteval 取trunc(sysdate,'mi')+1/(24*60),这样就不会有累积效应了。看执行结果:
2012-06-27 12:42:03
2012-06-27 12:43:03
2012-06-27 12:44:03
2012-06-27 12:45:03
2012-06-27 12:46:03
2012-06-27 12:47:03
2012-06-27 12:48:03

对于不同的间隔,时间截取可以采用不同的精度,比如每天执行一次,可以用trunc(sysdate,'dd')将时间截取到00:00:00,如每天2:00执行,inteval 取trunc(sysdate,'dd')+2/24+1或者trunc(sysdate)+2/24+1就可以了。

关于trunc截断日期的用法,可以查相关资料。JOB的执行时间有以下实验结论:

1、JOB在运行结束之后才会更新next_date,但是计算的方法是JOB刚开始的时间加上interval设定的间隔。

2、如果interval的时长短于JOB执行的时间,作业仍然会继续进行,只是执行间隔变为了JOB真实运行的时长。

3、用于计算next_date的JOB启动时间总是比设定的时间推迟几秒,原因可能是JOB的启动时间或者是扫描精度。

4、如果JOB因为某些原因延迟执行了一次,就会导致下一次的执行时间也同样顺延了,如本文所描述的延迟累积。因此用正确的时间间隔就很重要。比如,我们要JOB在每天的凌晨2:30执行而不管上次执行到底是几点,设置interval为trunc(sysdate)+2.5/24+1就可以了。

附:oracle JOB常见的执行时间

1、每分钟执行
TRUNC(sysdate,'mi')+1/(24*60)

2、每天定时执行
例如:
每天凌晨0点执行
TRUNC(sysdate+1)
每天凌晨1点执行
TRUNC(sysdate+1)+1/24
每天早上8点30分执行
TRUNC(SYSDATE+1)+(8*60+30)/(24*60)

3、每周定时执行
例如:
每周一凌晨2点执行
TRUNC(next_day(sysdate,1))+2/24
TRUNC(next_day(sysdate,'星期一'))+2/24
每周二中午12点执行
TRUNC(next_day(sysdate,2))+12/24
TRUNC(next_day(sysdate,'星期二'))+12/24

4、每月定时执行
例如:
每月1日凌晨0点执行
TRUNC(LAST_DAY(SYSDATE)+1)
每月1日凌晨1点执行
TRUNC(LAST_DAY(SYSDATE)+1)+1/24

5、每季度定时执行
每季度的第一天凌晨0点执行
TRUNC(ADD_MONTHS(SYSDATE,3),'q')
每季度的第一天凌晨2点执行
TRUNC(ADD_MONTHS(SYSDATE,3),'q')+2/24
每季度的最后一天的晚上11点执行
TRUNC(ADD_MONTHS(SYSDATE+ 2/24,3),'q')-1/24

6、每半年定时执行
例如:
每年7月1日和1月1日凌晨1点执行
ADD_MONTHS(TRUNC(sysdate,'yyyy'),6)+1/24

7、每年定时执行
例如:
每年1月1日凌晨2点执行
ADD_MONTHS(TRUNC(sysdate,'yyyy'),12)+2/24

### 配置 Redis 在 ThinkPHP 中实现定时任务调度 在 ThinkPHP 框架中,可以通过集成 Redis 和 Swoole 或 APScheduler 等工具来实现高效的定时任务调度功能。以下是具体方法: #### 1. 使用 Redis 存储任务队列并配合 Swoole 定时器 通过 Redis 创建一个存储待处理任务的列表(List),并将这些任务推送到该列表中。随后可以使用 PHP 的 Swoole 扩展中的 `swoole_timer_tick` 方法定期轮询 Redis 列表以获取新任务。 ```php // 初始化 Redis 连接 $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); // 将任务加入到 Redis List 中 $taskData = json_encode(['id' => 1, 'name' => 'example_task']); $redis->lPush('tasks_queue', $taskData); ``` 接着,在后台服务中启动一个循环监听机制,读取 Redis 数据并执行相应操作: ```php use Swoole\Timer; // 启动每秒一次的任务检查 Timer::tick(1000, function () use ($redis) { while (($item = $redis->rPop('tasks_queue')) !== false) { $data = json_decode($item, true); handleTask($data); // 自定义任务处理器函数 } }); function handleTask(array $data): void { echo "Processing task with ID {$data['id']} and Name {$data['name']}" . PHP_EOL; } ``` 上述代码片段展示了如何利用 Swoole 提供的毫秒级计时器触发对 Redis 队列的操作[^4]。 #### 2. 结合 ThinkPHP 命令行指令与 Redis 实现更复杂的业务逻辑 如果希望进一步扩展,则可以在 ThinkPHP 控制台命令的基础上增加对 Redis 的支持。例如编写一个新的 Artisan Command 类型的服务端点用于接收来自外部系统的请求或者内部计划好的动作触发信号。 假设我们已经有一个名为 `ProcessTasksCommand` 的控制台类负责从 Redis 获取未完成的工作项并通过某种方式通知它们已完成: ```bash php think process-tasks ``` 此 CLI 应用程序会不断查询 Redis 并调用适当的方法去解决每一个找到的问题实例直到没有更多剩余为止. 为了使这个过程自动化,还可以将其注册至 Linux crontab 文件当中以便每天凌晨两点钟自动唤醒运行一次: ```bash 0 2 * * * cd /path/to/your/project && php think process-tasks >> logs/cron.log 2>&1 ``` 另外一种替代方案则是启用 Laravel Schedule Job 功能从而免去了手动编辑 cron 表达式的麻烦同时也能达到相同的效果即每隔一分钟重复执行一次特定脚本文件内的全部条目内容.[^3] #### 3. 引入第三方库如 APScheduler (仅限于 Python) 虽然题目提到的是基于 PHP 的解决方案但是考虑到跨语言协作场景有时也会遇到需要共享同一套基础设施的情况因此这里简单介绍一下 Advanced Python Scheduler(APScheduler)[^5]. 它允许开发者轻松安排各种类型的作业包括固定间隔时间触发的一次性事件以及周期性的长期活动等等而且兼容多种持久化后端其中包括 Redis!这意味着即使应用程序本身主要是由 PHP 构建而成仍然能够借助此类强大的开源项目快速搭建起满足需求的功能模块而无需重新发明轮子. --- ### 总结 综上所述,在 ThinkPHP 中要实现带 Redis 支持的高级版定时任务管理系统可以从以下几个方面入手考虑: - **纯 PHP 方案**:依靠原生 Redis API 加上 Swoole 提供的强大异步 IO 能力构建高性能实时响应架构. - **混合部署模式**:引入额外的语言生态比如 Python 来弥补单一技术栈可能存在的局限性进而获得更加灵活多样的组合拳效果. 无论采取哪种策略都需注意保障系统稳定性的同时兼顾性能表现这样才能真正发挥出各自优势最终达成预期目标!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值