计划任务

未匹配的标注
本文档最新版为 4.0,旧版本可能放弃维护,推荐阅读最新版!

计划任务

介绍

应用中经常要在特定时间执行一些周期性的任务,例如每个星期,每分钟或者每几月。这些任务可能是:

  • 从目录中读取XML文件并导入数据库
  • 检查是否在Stripe是否还有支付需要更新到数据库
  • 清除数据库中不需要的数据
  • 发送某些API来触发事件

或者一些其他的工作。有很多用例需要在一天某些时刻区执行,甚至是在员工下班后的离线工作。

入门

首先我们需要安装调度器功能。我们仅需使用pip来完成安装:

$ pip install masonite-scheduler

然后加入Service Provider 到config/providers.py的PROVIDERS 列表中:

config/providers.py

...
from masonite.scheduler.providers import ScheduleProvider

PROVIDERS = [
    AppProvider,
    ...
    ...
    ScheduleProvider, # 这里
]

该provider会为Masonite增加几个新功能。首先是增添了两个新命令。

第一个命令是craft schedule:run命令,用来执行所有需要执行的计划任务(待会我们会创建)。

第二个命令是craft task,用来在app/tasks目录下新增命令。

创建一个命令

现在我们已经增加好了Service Provider,我们现在可以开始创建任务了,首先我们来创建一个超级简单的任务,打印一个”Hi”。先创建任务:

$ craft task SayHi

新建的文件位于app/tasks/SayHi.py

from scheduler.Task import Task

class SayHi(Task):

    def __init__(self):
        pass

    def handle(self):
        pass

这就是我们任务的脚手架。

所有的任务都需要继承scheduler.task.Task类。这样为任务添加所需的方法,也可以为实现容器收集

确保学习收集对象,查看Service Container里的收集文档进行了解。

容器自动加载

为了使任务可以在在container内部可以自动发现。在容器收集后,会查看是否需要运行。

有两种方法从容器中获取到类。第一种使用手动创建Service Provider绑定到容器。如果不知道如何实现,你可以通过Service Providers文档来进行创建。

另外一种方式是使用 自动加载。Masonite从2.0开始,你可以使用容器加载一个目录的所有类。可以通过配置文件config/application.py里的AUTOLOAD配置项目来实现:

config/application.py:

...
AUTOLOAD = [
    'app',
    'app/tasks'
]
...

这里将查找所有app/tasks目录下的任务类,加载到容器中,使用类名作为键进行绑定。

手动加载任务

你不必非得使用自动加载,你可以手动来调度任务。你需要使用Service Provider来绑定。

如果你要手动来加载任务的话你需要继承CanSchedule类。它提供self.call()方法来让你更容易实现任务和命令。

你可以在Service Provider中的register方法来调度:

from masonite.scheduler import CanSchedule
from app.jobs.YourJob import YourJob

class YourServiceProvider(ServiceProvider, CanSchedule):

    def register(self):
       self.schedule(YourJob()).every('3 days')

你可使用如下的一些方法进行调度: every('5 minutes'), every_minute(), every_15_minutes(), every_30_minutes(), every_45_minutes(), daily(), hourly(), weekly(), monthly().

命令调度

你可以用相同的方法来实现命令调度。

如果是手动加载任务的话同样继承CanSchedule类。

from masonite.scheduler import CanSchedule
from app.jobs.YourJob import YourJob

class YourServiceProvider(Serv):

    def register(self):
        self.call('your:command --flag').daily().at('9:00')

实现Task类

我们的任务已经可以自动加载到容器中,现在让我们来实现该类:

构造器

首先,构造器中的依赖可使用容器来完成。你可以从容器中获取中获取到任意不需要WSGI服务器执行的对象(大部分都不需要)。例如Upload, Mail, Broadcast和Request都可以获取,如下:

from scheduler.Task import Task

from masonite.request import Request

class SayHi(Task):

    def __init__(self, request: Request):
        self.request = request

    def handle(self):
        pass

Handle 方法

handle方法就是任务所要实现的逻辑。

例如我们开源请求API:

from scheduler.Task import Task
import requests

class SayHi(Task):

    def __init__(self):
        pass

    def handle(self):
        requests.post('http://url.com/api/store')

何时运行

任务神奇的地方在于我们开源定义执行的时间。我们通过Task几个选项来实现:

一个完成的任务代码类似如下:

from scheduler.Task import Task
import requests

class SayHi(Task):
    run_every = '3 days'
    run_at = '17:00'

    def __init__(self):
        pass

    def handle(self):
        requests.post('http://url.com/api/store')

该任务只会在每3天下午5点执行。

所有选项默认值为False。存在的选项有:

属性 例子
run_every 接受单复数的时间单位:minutes, hours, days, months run_every = ‘1 day’
run_at 24时间制时间 (“17:00” for 5pm) run_at = ‘17:00’
run_every_hour 布尔值,指示是否每小时执行:True, False run_every_hour = True
run_every_minute 布尔值,指示是否每分钟执行: True, False run_every_minute = True
twice_daily 一个元组值,里面元素也是24小时制各式的小时数,用来指定一天两个运行时间。 (1, 13) 将在上午1时和下午1时执行。 twice_daily = (1, 13)

如果时间里的单位是days或者months,同样也可以使用run_at来指定确切的执行时间。默认,设置了days时会在午夜(半夜12点)执行,months时就会在当月第一个天的午夜执行。我们也可以通过在设置了run_every属性时,同时设定run_at来控制确切的执行时间点。该选项设定的话,如果run_every设置的值为minutes或者hours时会忽律。

时区

你也可以在单个任务里执行timezone时区属性:

from scheduler.Task import Task
import requests

class SayHi(Task):
    run_every = '3 days'
    run_at = '17:00'
    timezone = 'America/New_York'

    def __init__(self):
        pass

    def handle(self):
        requests.post('http://url.com/api/store')

警告

此功能被设计无需单独的服务器命令来执行,所以需要一个注意事项,请务必阅读本节来全面了解其工作原理。

何时执行

由于调度器并不知道服务器是何时启动,它不知道从哪一天开始计数。为了解决这个问题,Masonite使用一个模数运算符来计算当前日期,通过查看任务时间和当前时间的模数是否为0。

例如,如果上面的任务执行时间为(every 3 days),那么将在5月3日,5月6日,5月9日,5月12日的午夜执行,以此类推。所以,需要注意是如果任务创建在5月11日,并且设定为每3天执行,那么12日就会被执行。

执行任务

在我们加入AUTOLOAD列表后,我们就可以通过schedule:run命令来找到要执行的命令了。

$ craft schedule:run

Masonite将会从容器里拿到所有继承scheduler.tasks.Task子类的任务,检查它们是否到了执行时间,然后执行。

即使我们运行任务,也应该看不到任何输出.我们修改一下任务添加 printing “Hi” 和其设置为每分钟运行:

from scheduler.Task import Task


class SayHi(Task):

    run_every = '1 minute'

    def __init__(self):
        pass

    def handle(self):
        print('Hi!')

现在,让我们再次运行命令:

$ craft schedule:run

现在我们应该看到”hi!” 输出在终端窗口.

执行一个具体的任务

您也可以通过运行带有–task标志的schedule:run命令来运行特定任务。标志值是容器绑定(通常是任务类名称):

 craft schedule:run --task SayHi

或者,您可以为任务明确命名:

from scheduler.Task import Task


class SayHi(Task):

    run_every = '1 minute'
    name = 'hey'

    def __init__(self):
        pass

    def handle(self):
        print('Hi!')

然后按名称运行命令

 craft schedule:run --task hey

Cron Jobs

设置定时任务仅适用于基于UNIX的机器,例如Mac和Linux. Windows 有一个类似schedule 叫 Task Scheduler 该方式与此类似 但是需要不同的方式来设置它.

尽管上面的方式很有用, 但在生产环境中不是很实用. 在生产中, 我们应该设置一个每分钟执行的定时任务 以便Masonite可以决定需要执行哪些任务.

我们将向您展示一个示例 定时任务,然后介绍如何逐步构建它.

PATH=/Users/Masonite/Programming/project_name/venv/bin:/Library/Frameworks/Python.framework/Versions/3.6/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Python.framework/Versions/3.6/bin
* * * * * cd /Users/Masonite/Programming/project_name && source venv/bin/activate && craft schedule:run

获取路径

当cron job运行时,它将使用/bin/sh命令来执行,而不是/bin/bash。因此,有可能不能正常在机器上找到craft命令,所以我们需要告诉cron job放置其路径到PATH环境中。我们可以简单通过如下命令来获取PATH变量:

$ env

这将打印类似如下信息:

...
__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0
PATH=/Library/Frameworks/Python.framework/Versions/3.6/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Python.framework/Versions/3.6/bin
PWD=/Users/Masonite/Programming/masonite
...

如果你使用的是针对开发目的的虚拟环境,那么你需要在虚拟环境下执行env

我们现在可以拷贝PATH环境变量放置到cron job。

要进入cron,只需执行:

$ env EDITOR=nano crontab -e

然后粘贴拷贝的PATH内容。一旦我们操作完内容类似如下:

PATH=/Users/Masonite/Programming/masonitetesting/venv/bin:/Library/Frameworks/Python.framework/Versions/3.6/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Python.framework/Versions/3.6/bin

退出nano。现在我们只需要设置真正的cron job:

配置 Cron 任务

现在我们需要设置cron任务了。同样使用nano拷贝粘贴方式来完成。不过稍微有些许变化。

首先是* * * * *部分是必须的,它意味这“每分钟执行一次”。下一部分是Masonite应用程序的位置。

接下来部分取决于你应用程序安装方式。如果是虚拟环境的话还需要追加&& source venv/bin/activate 到cron任务中来激活环境。如果没有使用虚拟环境的话你直接可以忽略它。

最后我们需要通过&& craft schedule:run执行调度器命令。

真棒!现在我们已经有了cron job来每分钟执行craft命令。Masonite会觉得哪些类需要被执行。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/masonite/2.3/us...

译文地址:https://learnku.com/docs/masonite/2.3/us...

上一篇 下一篇
贡献者:4
讨论数量: 0
发起讨论 只看当前版本


暂无话题~