E.13. lt_cron

E.13.1. lt_cron 是什么?
E.13.2. 查看定时任务运行详细信息

E.13.1. lt_cron 是什么?

lt_cron 是 LightDB 的基于 cron 的简单作业调度程序,作为扩展运行在数据库内部。它允许您直接从数据库中调度 LightDB 命令:

            -- 每周六的凌晨3点30分(美国东部时区)进行 VACUUM 操作
            SELECT cron.schedule('30 3 * * 6', 'VACUUM');
            schedule
            ----------
            42

            -- 每天上午10点(美国东部时区)进行 VACUUM 操作
            SELECT cron.schedule('nightly-vacuum', '0 10 * * *', 'VACUUM');
            schedule
            ----------
            43

            -- 将每天的 VACUUM 操作时间改为美国东部时区的凌晨3点
            SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
            schedule
            ----------
            43

            -- 停止调度作业
            SELECT cron.unschedule('nightly-vacuum' );
            unschedule
            ------------
            t
            (1 row)

            SELECT cron.unschedule(42);
            unschedule
            ------------
            t
        

lt_cron 可以支持秒级精度:

            -- 每天上午10点零30秒(美国东部时区)进行 VACUUM 操作
            SELECT cron.schedule('30 0 10 * * *', 'VACUUM');
            schedule
            ----------
            45

            -- 每秒钟进行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '* * * * * *', 'VACUUM');
            schedule
            ----------
            46

            -- 将 VACUUM 操作时间改为每 10 秒钟一次
            SELECT cron.schedule('dayly-vacuum', '*/10 * * * * *', 'VACUUM');
            schedule
            ----------
            46
        

lt_cron 可以支持四种任务模式,包括一次性任务、尽快执行任务、下一个时间间隔任务和固定时间间隔任务。 您可以在第四个参数中传递任务模式,有四个参数可供选择 (如果您想配置任务模式,则必须传递第一个参数任务名称):

  • 'single' 表示一次性任务,这意味着当任务第一次执行时,任务将不会再次执行。

            -- 立即执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '* * * * * *', 'VACUUM', 'single');
             schedule
            ----------
                   46
    
            -- 每 30 秒钟执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '*/30 * * * * *', 'VACUUM', 'next');
             schedule
            ----------
                   46
    
            -- 仅在下一个上午10点零30秒(美国东部时区)执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '30 0 10 * * *', 'VACUUM', 'single');
             schedule
            ----------
                   46
    
            -- 每天上午10点零30秒(美国东部时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '30 0 10 * * *', 'VACUUM', 'next');
             schedule
            ----------
                   46
                    
  • 'asap' 表示尽快执行的任务,在同一任务中,每次最多运行一个作业实例。 如果第二次运行在第一次完成之前应该开始,则第二次运行将排队并在第一次运行完成后立即启动。

            -- 每 30 秒钟执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '*/30 * * * * *', 'VACUUM', 'asap');
             schedule
            ----------
                   46
    
            -- 每天上午10点零30秒(美国东部时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '30 0 10 * * *', 'VACUUM', 'asap');
             schedule
            ----------
                   46
                    
  • 'next' 表示下一个时间间隔调度任务,在同一任务中,每次最多运行一个作业实例。 如果第二次运行在第一次完成之前应该开始,则第二次运行将排队并在下一个计时周期的时间点启动。

    与以前版本兼容,模式参数输入 'timing''next' 相同。

            -- 每 30 秒钟执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '*/30 * * * * *', 'VACUUM', 'next');
             schedule
            ----------
                   46
    
            -- 每天上午10点零30秒(美国东部时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '30 0 10 * * *', 'VACUUM', 'next');
             schedule
            ----------
                   46
                    
  • 'fixed' 表示固定时间间隔调度任务,在同一任务中,默认情况下最多运行四个作业实例。 如果第二次运行在第一次完成之前应该开始,则第二次运行不会等待,而会在定时周期的时间点启动, 然后与第一个未完成的任务并行执行。

    当同一任务过期时,您可以通过在 lightdb.conf 中配置 'cron.max_connections_per_task' GUC 参数来修改最大并发执行数, 并重新启动数据库以生效。最大上限为 16。

            -- 每 30 秒钟执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '*/30 * * * * *', 'VACUUM', 'fixed');
             schedule
            ----------
                   46
    
            -- 每天上午10点零30秒(美国东部时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '30 0 10 * * *', 'VACUUM', 'fixed');
             schedule
            ----------
                   46
                    

lt_cron 可以支持时区配置。您可以在第五个参数中传递时区值。 如果您想配置时区,必须传递第一个参数任务名称和第四个参数任务模式。 如果未配置时区,则默认为美国东部时区:

            -- 每天上午10点(格林尼治标准时间)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '0 10 * * *', 'VACUUM', 'next', '0');
            schedule
            ----------
            46

            -- 每天上午10点(西十时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '0 10 * * *', 'VACUUM', 'next', '-10');
            schedule
            ----------
            46

            -- 仅在下一个上午10点(美国东部六时区)执行一次 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '0 10 * * *', 'VACUUM', 'single', '6');
            schedule
            ----------
            46
        

lt_cron 可以支持执行 Linux 操作系统命令。您可以在第六个参数中传递命令类型值。传递参数 'sql' 表示第三个参数为 SQL 命令, 传递参数 'linux' 表示第三个参数为 Linux 命令。如果要配置命令类型,必须传递第一个参数任务名称、第四个参数任务模式和第五个参数时区。 如果未配置命令类型,则默认为 SQL 命令。请注意,执行 Linux 命令必须是超级用户。

            -- 每天上午10点(美国东部时区)执行 VACUUM 操作
            SELECT cron.schedule('dayly-vacuum', '0 10 * * *', 'VACUUM', 'next', '8', 'sql');
            schedule
            ----------
            46

            -- 每天晚上23点59分删除日志文件(美国东部时区)
            SELECT cron.schedule('dayly-touch', '59 23 * * *', 'rm -rf $LTDATA/log/*', 'next', '8', 'linux');
            schedule
            ----------
            46
        

lt_cron 可以并行运行多个作业,默认使用下一个时间间隔模式,即每次最多运行一个作业实例。 如果第二次运行在第一次完成之前应该开始,则第二次运行将排队并在下一个计时周期的时间点启动。

lt_cron 支持 SQL 命令的计划任务默认超时时间为 3 分钟,适用于所有类型的任务。 如果任务执行超时,它将在 cron.job_run_details 中记录错误并返回,等待下一次执行。 您可以通过在 lightdb.conf 中设置 cron.task_running_timeout GUC 参数来修改定时任务的超时时间,并重新启动数据库以生效。 最大值为 60 分钟;如果设置为 0,则表示没有超时限制。

请注意,Linux 命令定时任务没有超时机制。

该计划使用标准的 cron 语法,其中 * 表示“每个时间段运行”,而具体的数字表示“但仅在此时间运行”:

            ┌───────────── 分钟 (0 - 59)
            │ ┌────────────── 小时 (0 - 23)
            │ │ ┌─────────────── 月份中的日期 (1 - 31)
            │ │ │ ┌──────────────── 月份 (1 - 12)
            │ │ │ │ ┌───────────────── 星期几 (0 - 6)(0 到 6 分别代表周日到周六,也可以使用名称;7 也代表周日)
            │ │ │ │ │
            │ │ │ │ │
            * * * * *
        

创建 cron 计划的简单方法是:crontab.guru

它在标准 cron 语法的基础上进行了增强,支持秒级任务:

            ┌────────────── 秒 (0 - 59)
            │ ┌───────────── 分钟 (0 - 59)
            │ │ ┌────────────── 小时 (0 - 23)
            │ │ │ ┌─────────────── 月份中的日期 (1 - 31)
            │ │ │ │ ┌──────────────── 月份 (1 - 12)
            │ │ │ │ │ ┌───────────────── 星期几 (0 - 6)(0 到 6 分别代表周日到周六,也可以使用名称;7 也代表周日)
            │ │ │ │ │ │
            │ │ │ │ │ │
            * * * * * *
        

出于安全考虑,作业以与当前用户相同的权限在调用 cron.schedule 函数的数据库中执行。 此外,用户仅能在 cron.job 表和 cron.lt_job 视图中看到自己的作业。

            -- View active jobs
            select * from cron.job;
        

E.13.2. 查看定时任务运行详细信息

可以在cron.job_run_details中查看正在运行和最近完成的定时任务运行的状态。

        select * from cron.job_run_details order by start_time desc limit 5;
        ┌───────┬───────┬─────────┬──────────┬──────────┬───────────────────┬───────────┬──────────────────┬───────────────────────────────┬───────────────────────────────┐
        │ jobid │ runid │ job_pid │ database │ username │      command      │  status   │  return_message  │          start_time           │           end_time            │
        ├───────┼───────┼─────────┼──────────┼──────────┼───────────────────┼───────────┼──────────────────┼───────────────────────────────┼───────────────────────────────┤
        │    10 │  4328 │    2610 │ postgres │ marco    │ select process()  │ succeeded │ SELECT 1         │ 2023-02-07 09:30:00.098164+01 │ 2023-02-07 09:30:00.130729+01 │
        │    10 │  4327 │    2609 │ postgres │ marco    │ select process()  │ succeeded │ SELECT 1         │ 2023-02-07 09:29:00.015168+01 │ 2023-02-07 09:29:00.832308+01 │
        │    10 │  4321 │    2603 │ postgres │ marco    │ select process()  │ succeeded │ SELECT 1         │ 2023-02-07 09:28:00.011965+01 │ 2023-02-07 09:28:01.420901+01 │
        │    10 │  4320 │    2602 │ postgres │ marco    │ select process()  │ failed    │ server restarted │ 2023-02-07 09:27:00.011833+01 │ 2023-02-07 09:27:00.72121+01  │
        │     9 │  4320 │    2602 │ postgres │ marco    │ select do_stuff() │ failed    │ job canceled     │ 2023-02-07 09:26:00.011833+01 │ 2023-02-07 09:26:00.22121+01  │
        └───────┴───────┴─────────┴──────────┴──────────┴───────────────────┴───────────┴──────────────────┴───────────────────────────────┴───────────────────────────────┘
        (10 rows)
        

cron.job_run_details中最多保留距当前时间最近的10万条定时任务记录,早期多余的记录会被定期自动删除。

如果不想使用cron.job_run_details记录任务状态,则可以通过在lightdb.conf配置文件中添加cron.log_run=off来关闭。