перезапустите многопоточный сценарий Perl и закройте соединение с MySQL

StackOverflow https://stackoverflow.com/questions/1835773

Вопрос

У меня есть сценарий Perl, который читает командный файл и при необходимости перезагружается, выполнив:

myscript.pl:

exec '/home/foo/bin/myscript.pl';
exit(0);

Теперь все работает нормально, за исключением одной проблемы.Поток, читающий командный файл, не имеет доступа к используемому мной дескриптору DBI.И после нескольких перезапусков я, кажется, увеличиваю количество открытых соединений MySQL, пока не получаю ужасную ошибку «Слишком много соединений».В спецификации DBI говорится:

«Из-за этого (возможно, временного) ограничения вновь созданные потоки должны устанавливать собственные подключения к базе данных.Дескрипторы не могут использоваться совместно в разных потоках».

Есть ли способ закрыть соединения или, возможно, другой способ перезапустить сценарий?

Это было полезно?

Решение

Используйте переменную флага, которая является общей для всех потоков.Пусть поток чтения командной строки установит флаг для выхода, а поток, удерживающий дескриптор БД, отпустит его и фактически выполнит повторное выполнение:

#!/usr/bin/perl

use threads;
use threads::shared;

use strict; use warnings;
my $EXIT_FLAG :shared;

my $db_thread = threads->create('do_the_db_thing');
$db_thread->detach;

while ( 1 ) {
    sleep rand 10;
    $EXIT_FLAG = 1 if 0.05 > rand or time - $^T > 20;
}

sub do_the_db_thing {
    until ( $EXIT_FLAG ) {
        warn sprintf "%d: Working with the db\n", time - $^T;
        sleep rand 5;
    }
    # $dbh->disconnect; # here
    warn "Exit flag is set ... restarting\n";
    exec 'j.pl';
}

Другие советы

Вы можете попробовать зарегистрировать функцию atexit, чтобы закрыть дескриптор DBI в том месте, где он открыт, а затем использовать fork & exec для перезапуска сценария, а не просто exec.Затем родительский элемент вызовет выход, вызвав обратный вызов atexit, чтобы закрыть дескриптор DBI.Ребенок мог нормально перезапуститься.

Редактировать:Подумав еще пару минут, я считаю, что вы могли бы полностью пропустить atexit, потому что дескриптор автоматически закроется при выходе родителя.Если, конечно, вам не нужно выполнить более сложную операцию при закрытии дескриптора БД, чем простое закрытие дескриптора файла.

my $pid = fork();
if (not defined $pid) {
    #Could not fork, so handle the error somehow
} elsif ($pid == 0) {
    #Child re-execs itself
    exec '/home/foo/bin/myscript.pl';
} else {
    #Parent exits
    exit(0);
}

Если вы ожидаете большого количества связей, вам, вероятно, захочется ДБИ::Гофер действовать в качестве прокси-сервера DBI для вас.Вы создаете столько соединений в любом количестве сценариев, сколько захотите, и DBI::Gofer делится ими, когда это возможно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top