2

私はNet::FTPParallel::ForkManagerを利用する Perl プログラムに取り組んでいます。ForkManager で作成した各子プロセス内で、多数の Net::FTP メソッドを呼び出しています。残念ながら、これらは散発的に失敗します。接続の問題が原因だと思います。

Net::FTP ドキュメントでは、失敗したメソッド呼び出しを次のように処理できる/処理する必要があることを明確にしています。

$ftp = Net::FTP->new("some.host.name", Debug => 0) or die "Cannot connect to some.host.name: $@";

これはエラーを検出するためにはうまく機能しますが、ForkManager で子プロセスを強制終了します。これにより、各子が完了するまで実行するか、成功するまで再試行することを確認することが非常に難しくなっています。

私がやろうとしているのは、Net::FTP メソッドが失敗した場合、警告 (上記のダイメッセージと同様のメッセージで) return 0サブルーチン内からの両方です。私の考えでは、これにより、子プロセスを強制終了することなく、FTP に再接続して再試行できるようになります。そのように(これは単なるコードスニペットです):

foreach my $page (sort (keys %pages)) {
    my $pid = $pm1->start($page) and next;
    my $ok;
    my $attempts = 1;
    while (!($ok)) {
        print "Attempts on $page: $attempts\n";
        $ok = ftp_server_process($page);
        $attempts++;
    }
    $pm1->finish;
}

関連するサブルーチンを使用:

sub ftp_server_process {
    my $ftp = Net::FTP->new("some.ip", Debug => 0, Passive => 1, BlockSize => 1048576) or warn "Cannot connect to some.ip for page $page: $@" and return 0;
    $ftp->login("username", "password") or warn "Cannot login to some.ip\n", $ftp->message and return 0;
    $ftp->binary or warn "opening binary mode failed\n", $ftp->message and return 0;
    $ftp->cwd($ftp_input_folder) or warn "changing directory failed\n", $ftp->message and return 0;
    $ftp->put($pages{$page}{"ftp_upload_name"}) or warn "putting page $page failed\n", $ftp->message and return 0;
    $ftp->quit;
    return 1;
}

これは、この問題に取り組むための合理的な方法ですか? 構文はobject->method or warn "a message" and return 0;正しいですか、それとも私が見逃している問題がありますか? うまく機能しているように見えますが、不安定な感じがします。ジョブが完了するまですべての子プロセスが存続することを確認するという問題を解決するための、より確立されたパターンがあるかどうか疑問に思っています。

どんな提案でも大歓迎です。ありがとう!

4

1 に答える 1

4

die例外をキャッチする方が簡単です。

for my $page (sort keys %pages) {
    $pm->start($page) and next;

    my $attempts_left = 3;
    LOOP: {
        if (!eval { ftp_server_process($page); 1 }) {
           warn $@;
           if (--$attempts_left) {
              warn "Retrying...\n";
              redo;
           } else {
              warn "Aborting.\n";
              $pm->finish(1);
           }
        }
    }

    $pm->finish(0);
}

必要に応じて、親プロセスで失敗したものを記録することもできます。

$pm->run_on_finish(sub {
   my ($pid, $exit_code, $page, $signal) = @_;
   if ($exit_code || $signal) {
      print "Couldn't put page $page: ";
      if ($exit_code) {
         print "Exited with $exit_code\n";
      } else {
         print "Killed by signal $signal\n";
      }
   }
);
于 2013-08-07T02:42:02.177 に答える