31.7. 非同期通知

PostgreSQLは、LISTENNOTIFYコマンドを使用した、非同期通知をサポートします。 クライアントセッションは、LISTENコマンドを使用して処理対象とする特定の通知チャネルを登録します。 (通知監視を取り止めるにはUNLISTENコマンドを使用します。) 任意のセッションでそのチャネル名によるNOTIFYコマンドが実行されると、特定チャネルを監視しているすべてのセッションは非同期に通知を受け取ります。 監視者に追加データを通信するために"ペイロード"文字列を渡すことができます。

libpqアプリケーションは、通常のSQLによる問い合わせと同じようにLISTENUNLISTENおよびNOTIFYコマンドを発行することができます。 NOTIFYメッセージの到着は、続いてPQnotifiesを呼び出せば検出できます。

PQnotifies関数は、サーバから受信した通知メッセージの未処理リストから次の通知を返します。 保留中の通知がなくなればヌルポインタを返します。 PQnotifiesが通知を返すと、その通知は処理済みとみなされ、通知リストから取り除かれます。

PGnotify *PQnotifies(PGconn *conn);

typedef struct pgNotify
{
    char *relname;              /* 通知チャネル名 */
    int  be_pid;                /* 通知元サーバプロセスのプロセスID */
    char *extra;                /* 通知ペイロード文字列 */
} PGnotify;

PQnotifiesで返されたPGnotifyオブジェクトの処理が終わったら、PQfreememを使用して確実に解放してください。 PGnotifyポインタを解放することは重要です。 relnameextraフィールドは別の割り当てを表していません。 (これらのフィールド名は歴史的なものです。特にチャネル名はリレーション名と関係するものである必要はありません。)

例31-2で非同期通知を使用したサンプルプログラムを示しています。

PQnotifies()は実際にサーバのデータを読み出すわけではありません。 これは単に、他のlibpq関数が吸収してしまっていた通知メッセージを返すだけです。 libpqの以前のリリースでは、通知メッセージを適切な時点で確実に受け取るには、空の問い合わせでも何でも、とにかく一定時間ごとに問い合わせを送り、そしてPQexec()を実行するたびにPQnotifies()を検査するしかありませんでした。 今でもこの方法は動作しますが、処理能力の無駄使いをすることになるのでやめておくべきでしょう。

実行すべき問い合わせがない時に通知メッセージを検査するよい方法は、まずPQconsumeInput()を呼び出し、それからPQnotifies()を検査することです。 サーバからのデータの到着をselect()で待つことができ、不必要な動作でCPUパワーを消費してしまうことがありません。 (select()で使用するファイル記述子番号の取得については、PQsocket()を参照してください。) なお、これは問い合わせにPQsendQueryPQgetResultを使った時でも、またはおなじみのPQexecを使った時でも動作します。 しかし通知がコマンドの処理中に届いていないかどうか、PQgetResultあるいはPQexecの実行ごとにPQnotifies()を調べることを忘れないようにしておくべきです。