перезапустите многопоточный скрипт на Perl и закройте MySQL соединение - PullRequest
2 голосов
/ 03 декабря 2009

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

myscript.pl:

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 03 декабря 2009

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

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

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);
}
2 голосов
/ 03 декабря 2009

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

2 голосов
/ 03 декабря 2009

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

#!/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';
}
...