2009-12-02 7 views
2

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

myscript.pl:

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

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

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

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

+2

Вы понимаете, что 'exit (0)' достигается только в случае сбоя 'exec', правильно? –

+0

Да, я это понимаю. Я также попытался заменить exec на систему. – ankimal

+0

Где вы закрываете свои дескрипторы базы данных? –

ответ

2

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

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

Казалось, что это самое простое решение, и оно работает. – ankimal

2

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

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

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); 
} 
+0

Я предполагаю, что единственная проблема заключается в том, что выход в потоке является только Thread-> exit() и не обязательно выходит из всех потоков. – ankimal

+0

Это должно быть верно только в том случае, если вы переопределили поведение по умолчанию. Ссылка: http://perldoc.perl.org/threads.html#EXITING-A-THREAD – Adam

2

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

+0

Нет, я не ожидаю много соединений. Просто ожидайте много перезагрузок! – ankimal

+0

В этом случае проблема заключается в закрытии соединений, а не в их открытии. –

Смежные вопросы