-2

Postgre トリガー -> 通知の実行 -> PHP フローへのキャプチャーに問題または誤解があります。

私のプラットフォームは、Postgres を使用した centos の PHP(5.6) です。

通知テーブルを使用してトリガーを追加する必要があり、その通知に新しい通知が追加さ れるたびに、SMS がそのユーザーに送信する必要があります。

だからここにこのようなトリガーを追加しました

CREATE FUNCTION xxx_sms_trigger() RETURNS trigger
    LANGUAGE plpgsql
    AS $$
DECLARE
BEGIN
  PERFORM pg_notify('sms', NEW.id||'' );
  RETURN new;
END;

PHPでは、新しい通知の挿入は正常に機能します。

"pg_get_notify" によるこのキャプチャ pg_notify トリガーを追加した別のファイルがあります。ここでは、Postgres がサービスとして実行されていない未知の php スクリプトをトリガーする方法や、どのように機能させることができるかなど、このフローを完全に取得できませんでした。

4

5 に答える 5

3

サービスとして実行する php スクリプトが必要です。それがあなたが提供する通知を受け取る言語になる場合。@FelipeRosa が言うように、そのスクリプトはデータベースに接続してから、少なくとも 1 つのコマンドを発行する必要があります。

listen sms;

メイン サイト ( http://www.php.net/manual/en/function.pg-get-notify.php )にリッスンの良い例があります。

ここ数年、php でコーディングしていません。最近、このロジックを Python で実装しましたが、ほぼ同じはずです。私は少し調査を行い、php で select() を見つけることができますが、postgres ソケット記述子は php では使用できないようです。したがって、postgres ソケット記述子が見つからない限り、php で select() を使用することはできません。 .

とにかく、そのスレッドはここにあります(http://postgresql.1045698.n5.nabble.com/Is-there-any-way-to-listen-to-NOTIFY-in-php-without-polling-td5749888.html)。phpスクリプト側を下にして、下部近くにポーリングの例があります。前に選択したとおりにリッスンを (1 回) 実行してから、pg_get_notify() をループに入れて、通知をキューに入れたい時間だけそこにスリープ状態にすることができます。

ただfwiw、pythonではポーリングしません.select.select(pg_conn、...)、データがpostgres接続に到着すると、通知をチェックするため、「ポーリング」はありません。ループの代わりに php で select() を使用する方法を見つけることができれば幸いです。

-g

于 2014-05-09T20:09:58.740 に答える
3

これは、テーブル挿入への関心を登録し、通知 (またはタイムアウト) を待機し、呼び出し元に応答するまとまりのある例です。Postgres ではチャネル名が適切な識別子である必要があるため、文字「C」が前に付いたタイムスタンプを使用して通知チャネルを識別します。

ポストグル SQL

/*  We want to know when items of interest get added to this table.   
    Asynchronous insertions possible from different process or server  */
DROP TABLE IF EXISTS History;
CREATE TABLE History (
   HistoryId INT PRIMARY KEY,
   MYKEY CHAR(17),
   Description TEXT,
   TimeStamp BIGINT
);

/*  Table of registered interest in a notification  */
DROP TABLE IF EXISTS Notifications;
CREATE TABLE Notifications (
   NotificationId INT PRIMARY KEY,
   Channel VARCHAR(20),
   MYKEY CHAR(17)
);

/*  Function to process a single insertion to History table  */
CREATE OR REPLACE FUNCTION notify_me()
  RETURNS trigger AS
$BODY$
  DECLARE ch varchar(20);
  BEGIN
     FOR ch IN
     SELECT DISTINCT Channel FROM Notifications 
        WHERE MYKEY=NEW.MYKEY
     LOOP
        /* NOTIFY ch, 'from notify_me trigger'; */
        EXECUTE 'NOTIFY C' || ch || ', ' || quote_literal('from notify_me') || ';';
        DELETE FROM Notifications WHERE Channel=ch;
     END LOOP;
     RETURN NULL;
  END;
$BODY$
LANGUAGE 'plpgsql';

/*  Trigger to process all insertions to History table  */
DROP TRIGGER IF EXISTS HistNotify ON History CASCADE;
CREATE TRIGGER HistNotify AFTER INSERT ON History
    FOR EACH ROW EXECUTE PROCEDURE notify_me();

PHP コード

// $conn is a PDO connection handle to the Postgres DB
// $MYKEY is a key field of interest
$TimeStamp = time();  //  UNIX time (seconds since 1970) of the request
$timeout = 120;  //  Maximum seconds before responding

//  Register our interest in new history log activity
$rg = $conn->prepare("INSERT INTO Notifications (MYKEY, Channel)  VALUES (?,?)");
$rg->execute(array($MYKEY, $TimeStamp));

//  Wait until something to report
$conn->exec('LISTEN C'.$TimeStamp.';');  //  Prepend ‘C’ to get notification channel
$conn->exec('COMMIT;');  //  Postgres may need this to start listening
$conn->pgsqlGetNotify (PDO::FETCH_ASSOC, $timeout*1000);  //  Convert  from sec to ms

//  Unregister our interest
$st = $conn->prepare("DELETE FROM Notifications WHERE Channel=?");  
$st->execute(array($TimeStamp));
于 2015-11-19T22:55:39.363 に答える
2

@Greg が言及した「Python の方法」を PHP に移行する方法の例を次に示します。以下のスクリプトを開始した後、postgres db とクエリへの新しい接続を開きます。NOTIFY "test", 'I am the payload'

ソース:


<?php

$dsn = 'user=postgres dbname=postgres password=postgres port=5432 host=localhost';

$connection = \pg_connect($dsn);

if (\pg_connection_status($connection) === \PGSQL_CONNECTION_BAD) {
    throw new \Exception(
        sprintf('The database connect failed: %s', \pg_last_error($connection))
    );
}

\pg_query('LISTEN "test"');

while (true) {
    $read = [\pg_socket($connection)];
    $write = null;
    $except = null;
    $num = \stream_select(
        $read,
        $write,
        $except,
        60
    );
    if ($num === false) {
        throw new \Exception('Error in optaining the stream resource');
    }
    if (\pg_connection_status($connection) !== \PGSQL_CONNECTION_OK) {
        throw new \Exception('pg_connection_status() is not PGSQL_CONNECTION_OK');
    } elseif ($num) {
        $notify = \pg_get_notify($connection);
        if ($notify !== false) {
            var_dump($notify);
        }
    }
}
于 2017-12-17T14:21:47.117 に答える
0

これによれば、アプリケーションにメッセージを通知する前に、たとえば pg_query を介して、最初にアプリケーションにコマンド「LISTEN」を発行する目的のチャネルをリッスンさせる必要があります。

于 2014-05-09T19:06:11.480 に答える