我有一个功能,可以进行相当多的密集处理。偶尔我需要能够阻止它(即数据库维护),即使它是中途运行。我想给它发一个SIGINT,这样就可以结束它正在做的事情了。我发现的是,只要我引入一个普通的perl中断处理程序,该函数就会停止响应中断。
工作
CREATE OR REPLACE FUNCTION run_for_awhile() RETURNS void
AS $_X$
spi_exec_query('select pg_sleep(30)');
$_X$
LANGUAGE plperlu;
如果我在psql中执行select run_for_awhile()
,我可以输入Ctrl+C
并取消。在实际应用中我会做select pg_cancel_backend(PID)
,但我的测试通过该方法得到了相同的结果。
如果我修改了捕获SIGINT和/或SIGTERM的函数,则会发送信号,但函数在30秒后(pg_sleep结束时)才会注意到它。所以处理程序最终会运行但不是“立即”运行。
即
CREATE OR REPLACE FUNCTION run_for_awhile() RETURNS void
AS $_X$
$SIG{INT} = sub { die "Caught a sigint $!" };
spi_exec_query('select pg_sleep(30)');
$_X$
LANGUAGE plperlu;
答案 0 :(得分:2)
您需要做的是让Perl中断处理程序调用与CHECK_FOR_INTERRUPTS()
宏相同的C代码,即:
if (InterruptPending)
ProcessInterrupts();
(如果您在Windows上需要更多信息,请参阅src/include/miscadmin.h
)。
不幸的是,没有你可以轻易调用的包装函数,并且plperl似乎只在CHECK_FOR_INTERRUPTS
中调用plperl_spi_prepare
。
所以你有一个选项似乎是在你的Perl中断处理程序中设置一个全局,它使你的应用程序的主循环在看到变量设置时执行SELECT 1。有点难看,但它应该有用。
否则,您可以使用Perl的Inline::C
或类似内容来调用ProcessInterrupts
。
如果plperl公开CHECK_FOR_INTERRUPTS()
的Perl包装,那就太好了。考虑提交补丁。
答案 1 :(得分:0)
我无法完全理解这一点,但我找到了解决方法。 SIGINT和SIGTERM不可用,因此请勿使用它们。但我可以成功发送另一个中断,如SIGPROF。一旦发送,请跟进SIGINT,一切都按预期进行。
CREATE OR REPLACE FUNCTION run_for_awhile() RETURNS void
AS $_X$
$SIG{PROF} = sub { die "Caught a sigprof $!" };
spi_exec_query('select pg_sleep(30)');
$_X$
LANGUAGE plperlu;