【问题标题】:restart multi-threaded perl script and close mysql connection重启多线程perl脚本并关闭mysql连接
【发布时间】:2010-09-26 02:23:33
【问题描述】:

我有一个 Perl 脚本,它读取命令文件并在必要时通过以下方式自行重启:

myscript.pl:

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

现在,除了一个问题外,这一切正常。读取命令文件的线程无权访问我使用的 DBI 句柄。在多次重新启动后,我似乎建立了打开的 mysql 连接的数量,直到我得到可怕的“连接太多”错误。 DBI 规范说:

“由于这个(可能是临时的)限制,新创建的线程必须自己连接到数据库。句柄不能跨线程共享。”

有什么方法可以关闭连接,或者有什么方法可以重新启动脚本?

【问题讨论】:

  • 你知道exit(0)只有在exec失败时才能到达,对吧?
  • 是的,我确实意识到了这一点。我也尝试用 system 替换 exec。
  • 你在哪里关闭你的数据库句柄?
  • 我使用了 EXIT_FLAG 解决方案。分离主线程中的所有其他线程,关闭数据库句柄并退出。

标签: mysql database multithreading perl restart


【解决方案1】:

使用线程间共享的标志变量。让命令行读取线程设置标志退出,持有数据库句柄的线程释放它并实际执行重新执行:

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

【讨论】:

    【解决方案2】:

    您可以尝试注册一个 atexit 函数以在打开 DBI 句柄时关闭它,然后使用 fork & exec 重新启动脚本,而不是只执行 exec。然后父级调用exit,调用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);
    }
    

    【讨论】:

    【解决方案3】:

    如果您期望有很多连接,您可能希望DBI::Gofer 充当您的 DBI 代理。您可以在任意数量的脚本中创建任意数量的连接,DBI::Gofer 会尽可能地共享它们。

    【讨论】:

    • 不,我不希望有很多连接。期待很多重启!
    • 在这种情况下,您的问题是关闭连接,而不是打开连接。
    猜你喜欢
    • 2013-12-02
    • 2016-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    相关资源
    最近更新 更多