1

我有一个功能可以进行相当多的密集处理。有时我需要能够停止它(即用于数据库维护),即使它处于运行中期。我想给它发送一个 SIGINT,这样它就可以优雅地结束它正在做的事情。我发现,只要我引入一个普通的 perl 中断处理程序,该函数就会停止正确响应中断。

在职的

CREATE OR REPLACE FUNCTION run_for_awhile() RETURNS void
    AS $_X$
        spi_exec_query('select pg_sleep(30)');
$_X$
LANGUAGE plperlu;

如果我select run_for_awhile()在 psql 中执行,我可以输入Ctrl+C并取消。在我正在做的实际应用程序中,select pg_cancel_backend(PID)但我的测试通过该方法得到了相同的结果。

如果我修改函数以捕获 SIGINT 和/或 SIGTERM,则会发送信号,但该函数直到 30 秒后才注意到它(当 pg_sleep 完成时)。所以处理程序最终会运行,但不会“立即”运行。

IE

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;
4

2 回答 2

2

您需要在这里做的是让您的 Perl 中断处理程序调用与CHECK_FOR_INTERRUPTS()宏相同的 C 代码,即:

    if (InterruptPending)
        ProcessInterrupts();

(如果您在 Windows 上,您需要更多,请参阅src/include/miscadmin.h)。

不幸的是,没有可以简单调用的包装函数,而且 plperl 似乎只能CHECK_FOR_INTERRUPTSplperl_spi_prepare.

因此,您的一个选项似乎是在 Perl 中断处理程序中设置一个全局变量,使您的应用程序的主循环在看到变量已设置时执行 SELECT 1 。有点难看,但它应该工作。

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

如果 plperl 为CHECK_FOR_INTERRUPTS(). 考虑提交补丁。

于 2017-09-26T01:45:39.177 回答
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;
于 2017-09-26T16:55:49.603 回答