我如何处理中断(即 SIGTERM 或 SIGINT)
How do I handle interrupts (i.e. SIGTERM or SIGINT)
我有一个函数可以进行相当多的密集处理。偶尔我需要能够停止它(即为了数据库维护),即使它是 mid-运行。我想向它发送一个 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 and/or SIGTERM,信号被发送,但函数直到 30 秒后(pg_sleep 完成时)才注意到它。所以处理程序最终会 运行 但不会 "immediately".
即
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;
您在这里需要做的是让您的 Perl 中断处理程序调用与 CHECK_FOR_INTERRUPTS()
宏相同的 C 代码,即:
if (InterruptPending)
ProcessInterrupts();
(如果您使用 windows,您还需要更多信息,请参阅 src/include/miscadmin.h
)。
不幸的是,没有可以简单调用的包装函数,而且 plperl 似乎只在 plperl_spi_prepare
.
中调用 CHECK_FOR_INTERRUPTS
所以您的一个选择似乎是在您的 Perl 中断处理程序中设置一个全局变量,使您的应用程序的主循环在看到变量已设置时执行 SELECT 1。有点丑,但应该可以。
否则你可以使用 Perl 的 Inline::C
或类似的方法来调用 ProcessInterrupts
.
如果 plperl 为 CHECK_FOR_INTERRUPTS()
公开一个 Perl 包装器就好了。考虑提交补丁。
我还没有完全弄清楚这个问题,但我找到了解决方法。 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;
我有一个函数可以进行相当多的密集处理。偶尔我需要能够停止它(即为了数据库维护),即使它是 mid-运行。我想向它发送一个 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 and/or SIGTERM,信号被发送,但函数直到 30 秒后(pg_sleep 完成时)才注意到它。所以处理程序最终会 运行 但不会 "immediately".
即
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;
您在这里需要做的是让您的 Perl 中断处理程序调用与 CHECK_FOR_INTERRUPTS()
宏相同的 C 代码,即:
if (InterruptPending)
ProcessInterrupts();
(如果您使用 windows,您还需要更多信息,请参阅 src/include/miscadmin.h
)。
不幸的是,没有可以简单调用的包装函数,而且 plperl 似乎只在 plperl_spi_prepare
.
CHECK_FOR_INTERRUPTS
所以您的一个选择似乎是在您的 Perl 中断处理程序中设置一个全局变量,使您的应用程序的主循环在看到变量已设置时执行 SELECT 1。有点丑,但应该可以。
否则你可以使用 Perl 的 Inline::C
或类似的方法来调用 ProcessInterrupts
.
如果 plperl 为 CHECK_FOR_INTERRUPTS()
公开一个 Perl 包装器就好了。考虑提交补丁。
我还没有完全弄清楚这个问题,但我找到了解决方法。 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;