2017-09-25 41 views
1

我有一个功能,可以进行相当多的密集处理。偶尔我需要能够停下来(即为了数据库维护),即使它在中途运行。我想发送它一个SIGINT,以便它可以优雅地结束它的工作。我发现只要我引入普通的perl中断处理程序,该函数就会停止正确响应中断。我该如何处理中断(即SIGTERM或SIGINT)

工作

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

你好,也许http://dba.stackexchange.com上的家伙可以帮助你更快? –

回答

2

你需要什么做的,是有你的Perl中断处理程序调用相同的C代码为CHECK_FOR_INTERRUPTS()宏呢,那就是:

if (InterruptPending) 
     ProcessInterrupts(); 

(如果您'你需要更多的窗户,请参阅src/include/miscadmin.h)。

不幸的是,没有包装函数可以简单地调用,plperl似乎只需调用plperl_spi_prepare中的CHECK_FOR_INTERRUPTS

所以,你有一个选择似乎是设置一个全球性的在你的Perl中断处理程序,使您的应用程序的主循环做一个SELECT 1时,看到的变量。有点丑,但它应该工作。

否则,您可以使用Perl的Inline::C或类似的方法调用ProcessInterrupts

这会是很好,如果plperl露出一个Perl包装为CHECK_FOR_INTERRUPTS()。考虑提交补丁。

+0

感谢克雷格,我不会去深,因为我找到了一个合理的选择......但是,这正是这样回答我一直在寻找的! – Ryley

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;