singleExecutionで強制終了した場合でも大丈夫なように修正

| | トラックバック(0)

昨日作ったsingleExcutionですが、思いのほか好評なようでよかった。^o^

昨日作ったバージョンだと通常通りにスクリプトが終了すれば問題ないのですが、何らかの原因でプロセスが終了した場合にロックが残ってしまい、手動でロックを削除しないといけなかったのですが、これでは使いづらくてしょうがないので、ロックも自動で削除するように修正しました。

single_execution.php

シグナルハンドラを登録するようにした

次のようにしてシグナルハンドラを登録して、強制終了させられたタイミングでunlockするようにしてみました。
でもなぜか動かない...
なんでやねん!!

       if (singleExecution::loadExtension('pcntl')) {
            $this->key = $key;
            pcntl_signal(SIGTERM, array($this, 'unlockExit'));
            pcntl_signal(SIGHUP,  array($this, 'unlockExit'));
        }

ロックしたプロセスが存在するか調べるようにした

ロックディレクトリにプロセスIDを保存するようにしました。
このプロセスIDを使ってプロセスが存在するどうか調べて、存在しなければunlockするようにしました。

プロセスが存在するかどうか調べる

プロセスIDからプロセスが存在するかどうかは、シグナル番号0を送信してみれば分かります
phpの場合はposix拡張がないとシグナルが送れないので、その場合はpsコマンドを使って調べます。
このやり方だとpsコマンドの出力結果が変わると動かなくなるので、あまりよくないんですが...

    function processExists($pid)
    {
        if (!$this->loadExtension('posix')) {
            return posix_kill($pid, 0);
        } else {
            return intval(exec("ps -e|grep '^ *{$pid} '"));
        }
    }

ロックが不正な場合はunlock

これでロックが不正かどうか調べる準備が整ったので、不正な場合はunlockするようにしました。
不正なロックのunlock処理は不整合が起きないようにクリティカルセクションに入れました。

    function unlockIfInvalid($key)
    {
        $common_key = 'common';
    
        // spin lock
        $common_lock = $this->lockDirectory($common_key);
        while (!$this->mkdir($common_lock)) {
            usleep(10000);
        }
    
        // critical section
        if (!$this->isInvalidLock($this->lockDirectory($key))) {
            $this->unlock($key);
        }
    
        // unlock
        $this->unlock($common_key);
    }

かなり堅牢になった

想定されるケースはつぶしたので、かなり堅牢になったはず。
何かうまく動かない場合がありましたら、ご連絡ください。

トラックバック(0)

このブログ記事を参照しているブログ一覧: singleExecutionで強制終了した場合でも大丈夫なように修正

このブログ記事に対するトラックバックURL: http://blog.bz2.jp/bz2mt/mt-tb.cgi/262

ウェブページ

Powered by Movable Type 4.21-ja

このブログ記事について

このページは、masatoが2008年5月 5日 18:27に書いたブログ記事です。

ひとつ前のブログ記事は「PHPで拡張を動的に有効にする汎用的な方法」です。

次のブログ記事は「pseudoQueue作った(PHP)」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。