Closed gowy222 closed 1 year ago
感谢反馈,目前的计划任务不是通过 Linux 服务器的 crontab 来实现的,服务关闭后会停止,重启后,需要拉起数据库中的计划任务。
这里日志并不是去执行对应的任务,而是拉起过程中打的日志,具体执行时间可以看计划任务列表中的上次执行时间。
感谢反馈,目前的计划任务不是通过 Linux 服务器的 crontab 来实现的,服务关闭后会停止,重启后,需要拉起数据库中的计划任务。
这里日志并不是去执行对应的任务,而是拉起过程中打的日志,具体执行时间可以看计划任务列表中的上次执行时间。
为何要关闭此问题?这的确是个bug,确实时开机立即执行了计划任务,时间却没到。 早上8点多开机为何会执行11点半的计划任务? 确定不是bug? @wanghe-fit2cloud @ssongliu
感谢反馈,目前的计划任务不是通过 Linux 服务器的 crontab 来实现的,服务关闭后会停止,重启后,需要拉起数据库中的计划任务。 这里日志并不是去执行对应的任务,而是拉起过程中打的日志,具体执行时间可以看计划任务列表中的上次执行时间。
为何要关闭此问题?这的确是个bug,确实时开机立即执行了计划任务,时间却没到。 早上8点多开机为何会执行11点半的计划任务? 确定不是bug? @wanghe-fit2cloud @ssongliu
上面已经回复,重启 1Panel 是要拉起定时任务,并不是你所认知的使用 Linux 服务器的 crontab 管理。
具体执行去看计划任务列表中的上次执行时间。
这里我们在开发环境测试了 1panel 重启、服务器重启、断电都没有复现这个情况。 可以执行一下 1pctl restart 看一下是否会触发计划任务执行。
麻烦提供一下日志审计截图,手动执行会有操作记录如下图:
这里我们在开发环境测试了 1panel 重启、服务器重启、断电都没有复现这个情况。 可以执行一下 1pctl restart 看一下是否会触发计划任务执行。
麻烦提供一下日志审计截图,手动执行会有操作记录如下图:
2023-11-02 08:24:42 这个开机自动执行的 没有任何操作记录。 开机1panel日志里面也没有。而且上一天的日期不知为何变成2022年.
这里我们在开发环境测试了 1panel 重启、服务器重启、断电都没有复现这个情况。 可以执行一下 1pctl restart 看一下是否会触发计划任务执行。
麻烦提供一下日志审计截图,手动执行会有操作记录如下图:
这里我们在开发环境测试了 1panel 重启、服务器重启、断电都没有复现这个情况。 可以执行一下 1pctl restart 看一下是否会触发计划任务执行。
麻烦提供一下日志审计截图,手动执行会有操作记录如下图:
1pctl restart 软重启之后不会触发
晚点我试试 把1panel装到非overlay系统分区再看看
所以,这种情况,1panel这边能不能 先尝试修正 服务器当前时间,再启动Cronjob实列,再加入job到列队。
`func (c *Cron) run() { c.logger.Info("start")
// Figure out the next activation times for each entry.
now := c.now()
for _, entry := range c.entries {
entry.Next = entry.Schedule.Next(now)
c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next)
}
for {
// Determine the next entry to run.
sort.Sort(byTime(c.entries))
var timer *time.Timer
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
timer = time.NewTimer(100000 * time.Hour)
} else {
timer = time.NewTimer(c.entries[0].Next.Sub(now))
}
for {
select {
case now = <-timer.C:
now = now.In(c.location)
c.logger.Info("wake", "now", now)
// Run every entry whose next time was less than now
for _, e := range c.entries {
if e.Next.After(now) || e.Next.IsZero() {
break
}
c.startJob(e.WrappedJob)
e.Prev = e.Next
e.Next = e.Schedule.Next(now)
c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next)
}
case newEntry := <-c.add:
timer.Stop()
now = c.now()
newEntry.Next = newEntry.Schedule.Next(now)
c.entries = append(c.entries, newEntry)
c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next)
case replyChan := <-c.snapshot:
replyChan <- c.entrySnapshot()
continue
case <-c.stop:
timer.Stop()
c.logger.Info("stop")
return
case id := <-c.remove:
timer.Stop()
now = c.now()
c.removeEntry(id)
c.logger.Info("removed", "entry", id)
}
break
}
}
假设: 系统启动时,当前时间为2022年1月1日10:00。对于每一个entry,函数会计算其下一个执行时间。对于我的job,下一个执行时间会被设置为2022年1月1日11:00。
接着,主循环开始,并根据job的下一个执行时间设置一个定时器。定时器的时长是1小时。
1panel后来启动之后,系统时间被修复为2023年11月2日10:05。但此时,定时器仍然在计时,它并不知道时间发生了变化。
没有其他新的entry添加,也没有entry被移除或其他操作,因此我们可以忽略其他的select条件。
当定时器触发时,当前时间已经是2023年11月2日11:00。在for _, e := range c.entries循环中,会检查每个entry的下一个执行时间是否小于或等于当前时间。对于我们每天11的job,它的下一个执行时间(2022年1月1日11:00)确实小于当前时间(2023年11月2日11:00),因此job会被立即执行。
@ssongliu
换言之,1panel通过ntp发现系统时间错误的情况下,需要重启整个cronjob实列或者重置计算所有job的下一次启动时间来修正Schedule
意思是我现在建一个计划任务,每天 11.30 分执行,默认的下一次执行时间是 11-03 11:30,如果我的系统时间由 11-02 13:43 一下跳到 11-04 08:00,他就会立马执行一次是吧?
意思是我现在建一个计划任务,每天 11.30 分执行,默认的下一次执行时间是 11-03 11:30,如果我的系统时间由 11-02 13:43 一下跳到 11-04 08:00,他就会立马执行一次是吧?
是的。 if e.Next.After(now) || e.Next.IsZero() { break } //换言之就是 之前计算的下一次启动时间 小于等于当前时间就会被执行。now是每次都取新的,随系统时间变化,但是历史计算的下一次启动时间是写死到列队里面的。
你是有另外一个计划任务同时去同步时间吗?
我刚开启了一下计划任务设置为 每天 11:30 执行,然后上系统直接修改时间到 date -s "2023-11-05 13:51:00",无论重启系统还是断电都不会触发重新执行。
我也研究一下这个代码。
对,确实有
仔细读了一下源码,确实在计划任务过程中修改时间可能会导致执行的问题:
源码: 先遍历所有的任务,如果没有任务则休眠,有任务则根据下一次执行时间排序,然后加上一个定时器记录最近任务的执行时间点,这时候假如离下次执行时间还有 30 分钟,然后修改了系统时间到早上 8 点,在 8:30 的时候,定时器响起,开始执行任务。 if e.Next.After(now) || e.Next.IsZero() { break } 这里只是判断了执行时间和当前时间的先后,没有比较时间点是否满足时间格式,问题出在这,从 1panel 这边去控制不是很好操作,我看看能不能给他们提一个 issue。
暂时解决办法: 将时间同步的计划任务修改一下执行周期。
临时解决方案2?
https://github.com/1Panel-dev/1Panel/blob/dev/backend/cron/cron.go#L45 1panel这边 能不能 在 整个函数 func Run 第一步先强制尝试走网络ntp获取一次时间?再 global.Cron.Start(),至少给一次上层级提前纠正系统时间的机会 (脱机服务器就没办法了..) @ssongliu
临时解决方案2?
https://github.com/1Panel-dev/1Panel/blob/dev/backend/cron/cron.go#L45 1panel这边 能不能 在 整个函数 func Run 第一步先强制尝试走网络ntp获取一次时间?再 global.Cron.Start(),至少给一次上层级提前纠正系统时间的机会 (脱机服务器就没办法了..) @ssongliu
没问题,这样也是可以的,1.8 版本在服务器启动时,先尝试同步系统时间。
v1.8.0 版本已发布。
@wanghe-fit2cloud @ssongliu 老哥,还是不行。看看能不能还能咋优化一下,或者改一下机制。
昨晚(9号)更新的1.8
1.开机的时间2022年,首次获取ntp修复时间失败,(通电开机 但是路由器可能拨号还没完成,网还没通...) 2.[2022-12-22 19:55:55] [ERROR] App Store synchronization failed 这一条之后 系统时间被修复过来了... 换言之,路由器拨号通了.. 可是,这里没看到ntp请求..系统时间怎么恢复的? 3.ntp节点问题,有时候阿里云节点确实抽风,所以 ntp服务器 能不能配置多个地址,按顺序尝试?比如配置3个地址,每个都尝试一次? 建议: 加入 # 腾讯云 NTP 服务概述 内网 NTP 服务器 time1.tencentyun.com time2.tencentyun.com time3.tencentyun.com time4.tencentyun.com time5.tencentyun.com
外网 NTP 服务器 ntp.tencent.com ntp1.tencent.com ntp2.tencent.com ntp3.tencent.com ntp4.tencent.com ntp5.tencent.com
其实也就是开机(或者1panel启动)那10秒左右的时间..发生的.. 要不,给个总配置选项...1panel启动直接 sleep多少秒..? 让拨号的去拨号,让Linux系统底层该干嘛的先去干嘛...
不过也吐槽一下这个第三方cronjob模块,即使开机2022年,但是也没到2022年的中午11:30,还是被立即执行了job。 根本问题还是期望这个第三方模块尽快修复。
https://github.com/robfig/cron
这个模块最后一次更新是2020年? issues里面同类问题挺多... 要不咱换个第三方cron模块吧..
@wanghe-fit2cloud @ssongliu 老哥,还是不行。看看能不能还能咋优化一下,或者改一下机制。
昨晚(9号)更新的1.8
1.开机的时间2022年,首次获取ntp修复时间失败,(通电开机 但是路由器可能拨号还没完成,网还没通...) 2.[2022-12-22 19:55:55] [ERROR] App Store synchronization failed 这一条之后 系统时间被修复过来了... 换言之,路由器拨号通了.. 可是,这里没看到ntp请求..系统时间怎么恢复的? 3.ntp节点问题,有时候阿里云节点确实抽风,所以 ntp服务器 能不能配置多个地址,按顺序尝试?比如配置3个地址,每个都尝试一次? 建议: 加入 # 腾讯云 NTP 服务概述 内网 NTP 服务器 time1.tencentyun.com time2.tencentyun.com time3.tencentyun.com time4.tencentyun.com time5.tencentyun.com
外网 NTP 服务器 ntp.tencent.com ntp1.tencent.com ntp2.tencent.com ntp3.tencent.com ntp4.tencent.com ntp5.tencent.com
- 最后还是回到老问题,系统时间通电开机错误,但是每次面板彻底启动时间又能修复过来。有点不解,到底还有哪些地方自动调用了修复时间?计划任务的逻辑,能不能整体往后挪?
你这里时间同步超时了,可以在面板设置里面修改同步 ntp 服务器。
联系方式
No response
1Panel 版本
1.7.4
问题描述
2022/12/22 19:56:14 1420 :233 (断电开机 时间错乱?) [2022-12-22 19:56:14] [ERROR] App Store synchronization failed
[2023-10-31 14:14:58] [INFO] AppStore scheduled task in progress ...
[2023-10-31 14:14:58] [INFO] Starting synchronization with App Store...
[2023-10-31 14:14:58] [INFO] The scheduled certificate update task is currently in progress ...
[2023-10-31 14:14:58] [INFO] The scheduled certificate update task has completed
[2023-10-31 14:14:58] [INFO] Website scheduled task in progress ...
[2023-10-31 14:14:58] [INFO] Website scheduled task has completed
[2023-10-31 14:15:02] [INFO] start to handle remove expired, retain copies: 7
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x52d6c0]
goroutine 114 [running]: github.com/gin-gonic/gin.(Context).requestHeader(...) github.com/gin-gonic/gin@v1.9.1/context.go:833 github.com/gin-gonic/gin.(Context).GetHeader(...) github.com/gin-gonic/gin@v1.9.1/context.go:871 github.com/1Panel-dev/1Panel/backend/i18n.GinI18nLocalize.func1(0x7f02f902f9?, {0x205e8dd, 0x2}) github.com/1Panel-dev/1Panel/backend/i18n/i18n.go:71 +0x20 github.com/gin-contrib/i18n.(ginI18nImpl).getMessage(0x4001962840, {0x1a0e480, 0x40008ee140}) github.com/gin-contrib/i18n@v0.0.1/ginI18n.go:26 +0x64 github.com/gin-contrib/i18n.(ginI18nImpl).mustGetMessage(0x0?, {0x1a0e480?, 0x40008ee140?}) github.com/gin-contrib/i18n@v0.0.1/ginI18n.go:44 +0x24 github.com/gin-contrib/i18n.MustGetMessage(...) github.com/gin-contrib/i18n@v0.0.1/i18n.go:67 github.com/1Panel-dev/1Panel/backend/i18n.GetErrMsg({0x1f3fca0, 0x10}, 0x400196e840) github.com/1Panel-dev/1Panel/backend/i18n/i18n.go:41 +0xb8 github.com/1Panel-dev/1Panel/backend/buserr.BusinessError.Error({{0x1f3fca0, 0x10}, {0x0, 0x0}, 0x400196e840, {0x3e449c0, 0x400196e810}}) github.com/1Panel-dev/1Panel/backend/buserr/errors.go:20 +0x50 github.com/1Panel-dev/1Panel/backend/cron/job.(app).Run(0x400006b770?) github.com/1Panel-dev/1Panel/backend/cron/job/app.go:17 +0x68 github.com/robfig/cron/v3.DelayIfStillRunning.func1.1() github.com/robfig/cron/v3@v3.0.1/chain.go:71 +0x1a8 github.com/robfig/cron/v3.FuncJob.Run(0x0?) github.com/robfig/cron/v3@v3.0.1/cron.go:136 +0x24 github.com/robfig/cron/v3.(Cron).startJob.func1() github.com/robfig/cron/v3@v3.0.1/cron.go:312 +0x60 created by github.com/robfig/cron/v3.(*Cron).startJob github.com/robfig/cron/v3@v3.0.1/cron.go:310 +0xa8 [2023-10-31 14:15:09] [INFO] init logger successfully
[2023-10-31 14:15:09] [INFO] init db successfully
[2023-10-31 14:15:09] [INFO] Migration run successfully
[2023-10-31 14:15:09] [INFO] init cache successfully
[2023-10-31 14:15:09] [INFO] init session successfully
[2023-10-31 14:15:12] [INFO] add ntp job time successful
[2023-10-31 14:15:12] [INFO] start cronjob entryID: 5
[2023-10-31 14:15:12] [INFO] add shell job 重启docker_中午11点 successful
[2023-10-31 14:15:12] [INFO] start cronjob entryID: 6
[2023-10-31 14:15:12] [INFO] add shell job 重启frpc successful
[2023-10-31 14:15:12] [INFO] start cronjob entryID: 7
[2023-10-31 14:15:12] [INFO] add shell job 重启docker_晚上8点 successful
[2023-10-31 14:15:12] [INFO] start cronjob entryID: 8
[2023-10-31 14:15:12] [INFO] Starting synchronization with App Store...
[2023-10-31 14:15:12] [INFO] server run success on 233 with http
每一个重启docke任务都是分开定时的,不能同时运行,会相互卡bug(同样的docker命令同时并行),结果1panel通电开机就全部 每个都执行,导致docker完整卡住一个容器都跑不了。。。 如果通电开机就一个个启动计划任务,那设置指定时间还有何意义, start cronjob 都没做二次时间验证,都不判断当前系统时间到没到job指定的时间?
重现步骤
断电重启。
同一个 docker-compose -f /XXX.yml down --volumes && docker network prune -f && docker-compose -f /XXX.yml up -d --pull=always && sleep 5 && docker system prune --volumes -f 一个设置中午11点执行, 一个设置晚上8点执行, 通电开机并行,直接任务都 卡住 '一直运行中',容器一直不上线。
期待的正确结果
通电开机,计划任务不应该 就立即 不区分 该任务设置的时间 就运行。 start cronjob 应该引入协程来hook验证 当前任务配置的时间到没到。 如果start的逻辑有bug,那么这个协程就是一个安全锁。
而且说实话,任何计划任务,都应该在开机 1panel 默认强制获取一次 ntp时间之后,再开启整个进程。 当然需要考虑线下服务器断网单独开机无法获取ntp时间同步的情况。尽最大可能先确保服务器时间OK,才能进一步确认计划任务时间对得上。退而求其次,脱机服务器就只能跳过ntp直接开始计划任务总控进程。
ps,有没有一种可能,1panel缓存导致? 对于线下脱机服务器,想用1panel,能不能提供无缓存模式启动1panel?开机跳过缓存我觉得更合理。这几秒消耗初始化还是值得的。
相关日志输出
No response
附加信息
No response