我在晚上使用 pg_cron 扩展在我的 postgres 数据库上运行一些自动化任务。我正在将某些旧记录移动到存档数据库表中。我在 5 个不同的后台工作者上同时运行 5 个存储过程,因此它们都同时启动并在不同的工作者上运行(我假设这类似于在 Java 中的不同线程上运行不同的任务) .这 5 个存储过程是独立的(将记录移动到存档表),因此它们可以同时运行。我使用像
这样的命令来安排它们cron.schedule (myJob1,
'* * * * *',
'call my_stored_proc_1()'
);
cron.schedule (myJob2,
'* * * * *',
'call my_stored_proc_2()'
);
.
..
...
cron.schedule (myJob5,
'* * * * *',
'call my_stored_proc_5()'
);
现在,我有更多依赖存储过程要运行。但是他们需要在这 5 个作业完成/完成后运行,因为他们正在执行一些DELETE... sql 操作。
如何在我的前 5 个存储过程作业完成后运行第二个存储过程(执行 DELETE 查询的那个)作业?我不想设置 CRON 表达式对于执行 DELETES 的第二个存储过程,因为我不知道前 5 个存储过程什么时候完成......
答案 0 :(得分:1)
我希望我理解 OP 描述的问题。
如果我错了,那么下面的所有内容都会无效。
我想这是关于 CPU 和/或 IO 繁重的周期性夜间任务。
例如:
所以只有在任务 A-E 完成后才运行任务 F 才有意义。
每个任务在一段时间内只需要运行一次:
是否符合 OP 要求 - IDK。
为了简单起见,我们假设每个任务在一个晚上只运行一次。很容易扩展到其他时期/要求。
例如
CREATE TABLE job_log (
log_id bigint,
job_name text,
log_date timestamptz
)
对每个工作职能进行检查:
IF EXISTS(
SELECT 1 FROM job_log
WHERE
job_name = 'TaskA' # TaskB-TaskE for each functiont
AND log_date::DATE = NOW()::DATE # check that function already executed this night
) OR EXISTS(
SELECT 1 FROM pg_stat_activity
WHERE
query like 'SELECT * FROM jobA_function();' # check that job not executing right now
) THEN RETURN;
END IF;
可能还可以添加其他条件:查找连接数量、是否存在锁等。
这样可以保证函数不会比需要的更频繁地执行。
INSERT INTO job_log
SELECT
(SELECT MAX(log_id) FROM job_log) + 1 # or use sequences/other autoincrements
,'TaskA'
,NOW()
它的含义变得不同了。
现在是:“尝试启动任务的执行”。
可以安全地在选定的时间段之间每隔一个小时或更频繁地安排一次。
Cronjob 无法知道服务器是否处于负载状态,表上是否有锁,或者有人手动开始执行任务。
工作职能在这方面可以更聪明。
同上,但检查 start 以查找其他任务的完成情况。
例如
IF NOT EXISTS(
SELECT 1 FROM job_log
WHERE
job_name = 'TaskA'
AND log_date::DATE = NOW()::DATE
) OR NOT EXISTS(
SELECT 1 FROM job_log
WHERE
job_name = 'TaskB'
AND log_date::DATE = NOW()::DATE
)
.... # checks for completions of other tasks
OR EXISTS(
SELECT 1 FROM job_log
WHERE
job_name = 'TaskF' # TaskB-TaskE for each functiont
AND log_date::DATE = NOW()::DATE # check that function already executed this night
) OR EXISTS(
SELECT 1 FROM pg_stat_activity
WHERE
query like 'SELECT * FROM jobF_function();' # check that job not executing right now
) THEN RETURN;
像其他函数一样写入 job_log。
在 cronjob 中创建多个计划。
例如
假设任务 A-E 将运行大约 10-15 分钟。
其中一两个可以工作 30-45-60 分钟。
为任务 F 创建一个计划,每 5 分钟尝试启动一次。
这将如何运作:
pg_stat_activity
中有一个正在执行的任务 F -> 退出pg_stat_activity
为空但在日志中我们看到任务 F 已执行 -> 无需工作 -> 退出很容易将这种方法扩展到任何需求:
概念保持不变:
我很高兴听到任何形式的批评——谁知道我可能忽略了一些东西。
答案 1 :(得分:0)
您可以使用 pg_stat_activity
view 来确保没有像您的作业 1-5 那样的活动查询。
注意:
<块引用>超级用户和内置角色 pg_read_all_stats
的成员(另见第 21.5 节)可以查看所有会话的所有信息
...
while (
select count(*) > 0
from pg_stat_activity
where query in ('call my_stored_proc_1()', 'call my_stored_proc_2()', ...))
loop
perform pg_sleep(1);
perform pg_stat_clear_snapshot(); -- needs to retrieve the fresh data
end loop;
...
只需在 stored proc 6
的开头插入此代码,并在作业 1-5 之后调用它几秒钟。
注 1:
条件可以使用正则表达式进行简化和概括:
when query ~ 'my_stored_proc_1|my_stored_proc_2|...'
注意事项 2:
您可以使用 clock_timestamp()
函数实现超时:
...
is_timedout := false;
timeout := '10 min'::interval; -- stop waiting after 10 minutes
start_time := clock_timestamp();
while (...)
loop
perform pg_sleep(1);
perform pg_stat_clear_snapshot(); -- needs to retrieve the fresh data
if clock_timestamp() - start_time > timeout then
is_timedout := true;
break;
end if;
end loop;
if is_timedout then
...
else
...
end if;
...
注意 3:
查看 pg_stat_activity
的其他列。您可能还需要使用它们。