我如何处理中断(即SIGTERM或SIGINT)

时间:2017-09-25 22:31:54

标签: postgresql plperl

我有一个功能,可以进行相当多的密集处理。偶尔我需要能够阻止它(即数据库维护),即使它是中途运行。我想给它发一个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;

2 个答案:

答案 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;