简体   繁体   English

重启多线程perl脚本并关闭mysql连接

[英]restart multi-threaded perl script and close mysql connection

I have a Perl script that reads a command file and restarts itself if necessary by doing: 我有一个Perl脚本,可以读取命令文件并在必要时通过以下操作重新启动自身:

myscript.pl: myscript.pl:

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

Now, this works fine except for one issue. 现在,除了一个问题之外,这个工作正常。 The thread that reads the command file does not have access to the DBI handle I use. 读取命令文件的线程无权访问我使用的DBI句柄。 And over a number of restarts I seem to build up the number of open mysql connections till I get the dreaded "Too Many Connections" error. 在多次重新启动之后,我似乎积累了打开的mysql连接的数量,直到遇到可怕的“太多连接”错误为止。 The DBI spec says: DBI规范说:

"Because of this (possibly temporary) restriction, newly created threads must make their own connections to the database. Handles can't be shared across threads." “由于这种(可能是临时的)限制,新创建的线程必须建立自己的数据库连接。不能在线程之间共享句柄。”

Any way to close connections or perhaps a different way to restart the script? 有什么方法可以关闭连接,或者以其他方式重新启动脚本?

Use a flag variable that is shared between threads. 使用在线程之间共享的标志变量。 Have the command line reading thread set the flag to exit, and the thread holding the DB handle release it and actually do the re-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';
}

You could try registering an atexit function to close the DBI handle at the point where it is opened, and then use fork & exec to restart the script rather then just exec. 您可以尝试注册atexit函数以在打开DBI句柄时将其关闭,然后使用fork&exec重新启动脚本,而不是exec。 The parent would then call exit, invoking the atexit callback to close the DBI handle. 然后父级将调用exit,调用atexit回调以关闭DBI句柄。 The child could re-exec itself normally. 孩子可以正常地重新执行自己。

Edit: After thinking for a couple more minutes, I believe you could skip the atexit entirely because the handle would be closed automatically upon the parent's exit. 编辑:经过几分钟的思考,我相信您可以完全跳过atexit,因为在父项退出时该句柄将自动关闭。 Unless, of course, you need to do a more complex operation upon closing the DB handle than a simple filehandle close. 当然,除非您需要在关闭数据库句柄时执行比简单文件句柄关闭更复杂的操作。

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

If you expect a lot of connections, you probably want DBI::Gofer to act as a DBI proxy for you. 如果期望大量连接,则可能希望DBI :: Gofer充当您的DBI代理。 You create as many connections in as many scripts as you like, and DBI::Gofer shares them when it can. 您可以在任意数量的脚本中创建尽可能多的连接,并且DBI :: Gofer会尽可能共享它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM