GoravelGoravel
首页
视频
  • English
  • 简体中文
GitHub
首页
视频
  • English
  • 简体中文
GitHub
  • 前言

    • 升级指南

      • 从 v1.14 升级到 v1.15
      • 从 v1.13 升级到 v1.14
      • 历史版本升级
    • 贡献指南
    • 优秀扩展包
  • 入门指南

    • 安装
    • 配置信息
    • 文件夹结构
    • 编译
  • 核心架构

    • 请求周期
    • 服务容器
    • 服务提供者
    • Facades
  • 基本功能

    • 路由
    • HTTP 中间件
    • 控制器
    • 请求
    • 响应
    • 视图
    • Grpc
    • Session
    • 表单验证
    • 日志
  • 综合话题

    • Artisan 命令行
    • 缓存系统
    • 事件系统
    • 文件储存
    • 邮件
    • 队列
    • 任务调度
    • 本地化
    • 扩展包开发
    • 颜色
    • Strings
    • 辅助函数
  • 安全相关

    • 用户验证
    • 用户授权
    • 加密解密
    • 哈希
  • ORM

    • 快速入门
    • 模型关联
    • 数据库迁移
    • 数据填充
    • 模型工厂
  • 测试相关

    • 快速入门
    • HTTP Tests
    • Mock

任务调度

  • 简介
  • 定义调度
    • Artisan 命令调度
    • 日志级别
    • 调度频率选项
    • 避免任务重复
    • 任务只运行在一台服务器上
  • 运行调度程序
  • 关闭调度程序

简介

过去,你可能需要在服务器上为每一个调度任务去创建 Cron 条目。因为这些任务的调度不是通过代码控制的,你要查看或新增任务调度都需要通过 SSH 远程登录到服务器上去操作,所以这种方式很快会让人变得痛苦不堪。

Goravel 的命令行调度器允许你在 Goravel 中清晰明了地定义命令调度。在使用这个任务调度器时,你只需要在你的服务器上创建单个 Cron 入口。

定义调度

你可以在 app\console\kernel.go 的 Schedule 方法中定义所有的调度任务。在开始之前,我们来看一个例子:我们计划每天午夜执行一个 闭包,这个 闭包 会执行一次数据库语句去清空一张表:

package console

import (
  "github.com/goravel/framework/contracts/console"
  "github.com/goravel/framework/contracts/schedule"
  "github.com/goravel/framework/facades"

  "goravel/app/models"
)

type Kernel struct {
}

func (kernel Kernel) Schedule() []schedule.Event {
  return []schedule.Event{
    facades.Schedule().Call(func() {
      facades.Orm().Query().Where("1 = 1").Delete(&models.User{})
    }).Daily(),
  }
}

Artisan 命令调度

调度方式不仅有闭包调用,还可以使用 Artisan commands。例如,你可以给 Command 方法传递命令名称或类来调度一个 Artisan 命令:

package console

import (
  "github.com/goravel/framework/contracts/console"
  "github.com/goravel/framework/contracts/schedule"
  "github.com/goravel/framework/facades"
)

type Kernel struct {
}

func (kernel *Kernel) Schedule() []schedule.Event {
  return []schedule.Event{
    facades.Schedule().Command("send:emails name").Daily(),
  }
}

日志级别

当 app.debug 为 true 时,控制台将打印所有日志;否则,只打印 error 级别日志。

调度频率选项

我们已经看到了几个如何设置任务在指定时间间隔运行的例子。不仅如此,你还有更多的任务调度频率可选:

方法描述
.Cron("* * * * *")自定义 Crone 计划执行任务
.EveryMinute()每分钟执行一次任务
.EveryTwoMinutes()每两分钟执行一次任务
.EveryThreeMinutes()每三分钟执行一次任务
.EveryFourMinutes()每四分钟执行一次任务
.EveryFiveMinutes()每五分钟执行一次任务
.EveryTenMinutes()每十分钟执行一次任务
.EveryFifteenMinutes()每十五分钟执行一次任务
.EveryThirtyMinutes()每三十分钟执行一次任务
.Hourly()每小时执行一次任务
.HourlyAt(17)每小时第十七分钟时执行一次任务
.EveryTwoHours()每两小时执行一次任务
.EveryThreeHours()每三小时执行一次任务
.EveryFourHours()每四小时执行一次任务
.EverySixHours()每六小时执行一次任务
.Daily()每天 00:00 执行一次任务
.DailyAt("13:00")每天 13:00 执行一次任务

避免任务重复

默认情况下,即使之前的任务实例还在执行,调度内的任务也会执行。为避免这种情况的发生,你可以使用 SkipIfStillRunning 或 DelayIfStillRunning 方法:

方法描述
.SkipIfStillRunning()如果有正在执行的相同任务,则本次取消执行
.DelayIfStillRunning()如果有正在执行的相同任务,则本次等待正在执行的任务结束后再执行
facades.Schedule().Command("send:emails name").EveryMinute().SkipIfStillRunning()
facades.Schedule().Command("send:emails name").EveryMinute().DelayIfStillRunning()

任务只运行在一台服务器上

注意 要使用此功能,你的应用程序必须使用 memcached, dynamodb, 或 redis 缓存驱动程序作为应用程序的默认缓存驱动程序。此外,所有服务器必须和同一个中央缓存服务器通信。

如果您的应用运行在多台服务器上,可能需要限制调度任务只在某台服务器上运行。例如,假设您有一个每个星期五晚上生成新报告的调度任务,如果任务调度器运行在三台服务器上,调度任务会在三台服务器上运行并且生成三次报告,不够优雅!

要指示任务应仅在一台服务器上运行,请在定义计划任务时使用 OnOneServer 方法。第一台获取到该任务的服务器会给任务上一把原子锁以阻止其他服务器同时运行该任务:

facades.Schedule().Command("report:generate").Daily().OnOneServer()

如果你使用闭包来定义单服务器作业,则必须为他们定义一个名字:

facades.Schedule().Call(func() {
  fmt.Println("goravel")
}).Daily().OnOneServer().Name("goravel")

运行调度程序

现在,我们已经学会了如何定义计划任务,接下来让我们讨论如何真正在服务器上运行它们。

在根目录 main.go 文件中增加 go facades.Schedule().Run()。

package main

import (
  "github.com/goravel/framework/facades"

  "goravel/bootstrap"
)

func main() {
  // This bootstraps the framework and gets it ready for use.
  bootstrap.Boot()

  // Start schedule by facades.Schedule
  go facades.Schedule().Run()

  select {}
}

关闭调度程序

你可以调用 Shutdown 方法优雅的关闭调度程序,该方法将会等待所有任务处理完毕后再执行关闭操作。

// main.go
bootstrap.Boot()

// Create a channel to listen for OS signals
quit := make(chan os.Signal)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

// Start schedule by facades.Schedule
go facades.Schedule().Run()

// Listen for the OS signal
go func() {
  <-quit
  if err := facades.Schedule().Shutdown(); err != nil {
    facades.Log().Errorf("Schedule Shutdown error: %v", err)
  }

  os.Exit(0)
}()

select {}
Edit this page
Prev
队列
Next
本地化