Tag Archives: error

Parallel::Preforkで「cannot start another process while you are in child process」

1
Filed under perl
Tagged as , ,

今日は、perlのParallel::Prefork(Parallel/Prefork.pm)で出たエラーについてメモ。
結論からいうと、今回のパターンは、Parallel::Preforkのバージョンと組み方の問題でした。
(※あくまでエラーメッセージの条件説明じゃなく、こんなパターンで出る場合があるよという感じで見てください)

では、簡単なテストスクリプトを書いてみます。

#!/usr/local/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/Parallel-Prefork-0.08/lib/";
use Parallel::Prefork;

my $pm = Parallel::Prefork->new({
        max_workers => 2,
        trap_signals => {
            TERM => 'TERM',
        },
    });

while ($pm->signal_received ne 'TERM') {
    $pm->start(sub {
        sleep(3);
        warn "end:" . time();
    });
}
$pm->wait_all_children();

これを実行すると、

cannot start another process while you are in child process at ...../Parallel/Prefork.pm line 42.

みたいなエラーが表示されます。

これは、手元にあった0.10未満のバージョンのParallel::Preforkを利用して、
0.10から実装された「- support new style: $pm->start(sub { … })」の形で
コードを実装してしまっている為です。

【0.10未満のParallel::Prefork】
$pm->start(sub{})に対応していないので、上記のコードだと、
何も処理されずにstartだけしてwhile分がまわります。
ここで問題なのは、Parallel::Prefoxkを正常終了するには、$pm->finishしないといけないという事。
この場合、$pm->start(sub{});で渡した内容が宙に浮きます。そして、finishが走る要素がなくなります。

sub start { 
    my $self = shift;
    :
    :
    die 'cannot start another process while you are in child process'
        if $self->{in_child};
    :
}

0.10以上のParallel::Preforkを利用している場合には、上記の$pm->start(sub{})の中が
Parallel::Prefork側の$cbに入り、$cb->();実行後に、$self->finish();されているので、問題ない。

sub start {
    my ($self, $cb) = @_;
    :
    :
       if ($cb) {
           $cb->();
           $self->finish();
       }
    :
}

ということで、コードをそのままに、libの読み込み先を

use lib "$FindBin::Bin/Parallel-Prefork-0.08/lib/";
                        ↓
use lib "$FindBin::Bin/Parallel-Prefork-0.13/lib/";

に変更したら、正常に動作しました。
まあ、通常はcpanmとかでParallel::Preforkを更新すればいいだけですね。
現時点の最新が、0.13なので、それにしてますが、多分Changesから見ると0.10以降なら何でも動くはず。

【もしも0.08のままいきたいなら】
コードを以下のように$pm->startの引数で渡すのを止めて、
かつ、$pm->finish;を明示的にするように修正すればいいだけですね

#!/usr/local/bin/env perl
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/Parallel-Prefork-0.08/lib/";
use Parallel::Prefork;

my $pm = Parallel::Prefork->new({
        max_workers => 2,
        trap_signals => {
            TERM => 'TERM',
        },
    });

while ($pm->signal_received ne 'TERM') {
    $pm->start;

    sleep(3);
    warn "end:" . time();

    $pm->finish;
}

まあ、そもそもが、Parallel::Preforkの0.10以上を利用していたシステムを
0.10未満のサーバに移植した(古いサーバに移設とかあまり無いですよね)とかしないと発生しないので、
この現象を調べる事になる人は、ほとんどいないと思いますけど。

[Memo]wordpressで「現在メンテナンス中のため、しばらくの間ご利用いただけません。」

1
Filed under php, wordpress
Tagged as , ,

久しぶりのブログ更新が、比較的どうでもいいネタで、
かつwordpressなんで、少し微妙ではありますが、メモ程度に。

wordpressの更新(いわゆるバージョンアップ)をしてみたら、
ブログページも、管理ページも以下のエラーが表示されて、何もできなくなったというお話です。

現在メンテナンス中のため、しばらくの間ご利用いただけません。

結論からいうと、処理中でなく、処理完了後もこのエラーがでているようなら、
SSHやFTPや、レンタルサーバならファイルマネージャみたいので、
サーバ上のwordpressを置いてあるディレクトリ(フォルダ)直下に
「.maintenance」ファイルができてると思うので、これを削除するか、
不安だったら、「.maintenance_org」など適当な名前にリネーム(変更)したら表示されます。


具体的な内容としては、まあ、既に巷に溢れてるんだろうと思いますが、
共有のレンタルサーバとかでwordpressを利用している場合に、FTPのポートが開いているので、
wordpressのバージョンアップを自ずとFTPで行う場面が多くなりそうですが、
バージョンアップ処理を開始して、実際に新しいバージョンのファイルをコピーする前に、
「wp-admin/includes/update-core.php」ファイルの「update_core関数」によって、
以下のようにメンテナンスにロックファイルが作成されます。(関係ないけど直前に古いロックファイルは消してるみたい)

$maintenance_string = ‘‘;
$maintenance_file = $to . ‘.maintenance’;
$wp_filesystem->delete($maintenance_file);
$wp_filesystem->put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE);

で、ブログページ側の挙動を追っていくと、 (wordpressを置いているフォルダを起点に書きます)
1. 「index.php」で「wp-blog-header.php」をrequire。

require(‘./wp-blog-header.php’);

2. 「wp-blog-header.php」で「wp-load.php」をrequire。

require_once( dirname(__FILE__) . ‘/wp-load.php’ );

3. 「wp-load.php」で、「wp-config.php」が存在すればrequire。

if ( file_exists( ABSPATH . ‘wp-config.php’) ) {
/** The config file resides in ABSPATH */
require_once( ABSPATH . ‘wp-config.php’ );

4. 「wp-config.php」で、「wp-settings.php」をrequire。

require_once(ABSPATH . ‘wp-settings.php’);

5. 「wp-settings.php」で、「wp_maintenance関数」を呼び出し。

// Check if we’re in maintenance mode.
wp_maintenance();

6. 「wp-includes/load.php」の「wp_maintenance関数」が呼び出され、
「.maintenance」ファイルがあり、かつファイル内に記載されているepoch値(エポック値)から
600秒(10分)以内の場合には、「wp-content/maintenance.php」があれば、それを表示。
それがなければ、「 _e( ‘Briefly unavailable for scheduled maintenance. Check back in a minute.’ )」が
表示される。

function wp_maintenance() {
if ( !file_exists( ABSPATH . ‘.maintenance’ ) || defined( ‘WP_INSTALLING’ ) )
return;

global $upgrading;

include( ABSPATH . ‘.maintenance’ );
// If the $upgrading timestamp is older than 10 minutes, don’t die.
if ( ( time() – $upgrading ) >= 600 )
return;

if ( file_exists( WP_CONTENT_DIR . ‘/maintenance.php’ ) ) {
require_once( WP_CONTENT_DIR . ‘/maintenance.php’ );
die();
}
:

7. 日本語設定になっている場合には、「 _e( ‘Briefly unavailable for scheduled maintenance. Check back in a minute.’ )」が
「wp-content/languages/ja.po」に基づいて「現在メンテナンス中のため、しばらくの間ご利用いただけません。」が表示される。

#: wp-includes/load.php:178
msgid “Briefly unavailable for scheduled maintenance. Check back in a minute.”
msgstr “現在メンテナンス中のため、しばらくの間ご利用いただけません。”

そして、管理者ページ側もほとんど同じですが、
「wp-admin/index.php」で

require_once(‘./admin.php’);

「wp-admin/admin.php」

require_once(dirname(dirname(__FILE__)) . ‘/wp-load.php’);

されているので、結果、ブログページの3番以降と同じフローにのります。

あとは、メンテナンスページとして自分の作成した内容を表示したい場合には、
「wp-content/maintenance.php」という名前のファイルを作って、表示させればいいです。

サンプルテキストを置くとしたら、

echo “メンテナンス中です。ご迷惑をお掛けしてすいません” > ./wp-content/maintenance.php

簡単にメンテナンスのテストするなら、コマンドラインから以下をたたいて今のepoch値でロックファイルを作ります。
(※当たり前ですが、wordpressはメンテ中になりますので、ご注意ください)

php -r “echo sprintf(‘‘, time());” > .maintenance

ということで、エラーがでたので、久しぶりにphpのコードを読んで、中身を追って、
どこにでもありそうな処理フローの解説をするという誰得っぽい記事を書いてみました。久しぶりの更新なのに。。