Как мне обрабатывать прерывания (например, SIGTERM или SIGINT)
У меня есть функция, которая выполняет довольно интенсивную обработку. Время от времени я должен быть в состоянии остановить это (то есть для обслуживания БД), даже если это в середине. Я хотел бы отправить 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 завершит работу). Таким образом, обработчик запускается в конце концов, но не сразу.
т.е.
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 ответа
Здесь вам нужно, чтобы ваш обработчик прерываний Perl вызывал тот же код C, что и CHECK_FOR_INTERRUPTS()
макрос делает, то есть:
if (InterruptPending)
ProcessInterrupts();
(Если вы находитесь на окнах, вам нужно немного больше, см. src/include/miscadmin.h
).
К сожалению, нет никакой функции-обертки, которую вы можете вызвать тривиально, и plperl только вызывает CHECK_FOR_INTERRUPTS
в plperl_spi_prepare
,
Таким образом, у вас есть один вариант - установить глобальную переменную в вашем обработчике прерываний Perl, которая заставляет основной цикл вашего приложения делать SELECT 1, когда он видит, что переменная установлена. Немного некрасиво, но это должно работать.
В противном случае вы можете использовать Perl Inline::C
или аналогичный, чтобы вызвать ProcessInterrupts
,
Было бы неплохо, если бы plperl выставил Perl-оболочку для CHECK_FOR_INTERRUPTS()
, Рассмотрите возможность отправки патча.
Я не смог полностью разобраться в этом, но я нашел способ обойти это. 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;