投稿者

インターシステムズジャパン
記事 Toshihiko Minamoto · 7 hr 前 7m read

IRISアプリケーションからクライアントに通知する

はじめに

あるお客さんから、ワークフローの待受画面での新着通知方法についてご相談がありました。

  • 単純なポーリングだと、通知の遅延や、サーバリソースを消費する
  • ロングポーリングは、待ち受け画面のためにIRISのライセンスを消費する
  • MQTTなどを使うと専用のサーバプロセスが必要

何か良い方法は無いでしょうか。 といった内容です。

この課題に対して調査したところ、以下の方式が見つかりました。

  • ブラウザからSSE(Server-Sent Event)方式を使い、nginx上にアクセス
  • IRIS側から通知が必要なクライアントのIDに対してnginxにメッセージをPOST
  • nginxがルーティングを行い、当該クライアントにメッセージを通知

今回は以下の点について手順や設定等解説していきたいと思います。

  • nginx のソースビルドと Web Gateway のインストール
  • nginx-push-stream-module を使った SSE (Server-Sent Events) 通知
  • ブラウザ受信 (/subscribe) とサーバ送信 (/publish) の最小実装

全体構成

まずは全体像です。データの流れをシンプルに分けることで、役割が明確になります。

  • フロントエンド(クライアント)を nginx から配信
  • IRIS/API: /csp へのアクセスは Web Gateway 経由で IRIS へ接続
  • SSE購読: ブラウザは /subscribe?id=<channel> に `EventSourceインターフェースで接続、通知を待つ
  • SSE配信: サーバは /publish?id=<channel> に POST して配信

1. nginx 環境を準備する

まずは nginx 実行環境を準備します。IRIS用やSSE配信用モジュールを組み込む必要があるため、以下のnginxソースコードとモジュールのファイルが必要です。

  • nginx: 1.28.2

  • モジュール:

    • ngx_http_csp_module.c (IRIS Web Gateway 連携)
    • nginx-push-stream-module (SSE配信)

    ※ nginx 1.25.1よりngx_http_parse_chunked()の引数が変更され、オリジナルではエラーが出るため、第4引数に0を入れています。 ソースコードを修正したくない方は nginx 1.24.x を使用してください。

ダウンロードと展開は以下の処理を実行します。作業フォルダの下にnginx本体とモジュールのフォルダが作成され、コードが展開されます。

cd <作業フォルダ>
NGINX_VERION=1.28.2
wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz
tar -zxf nginx-${NGINX_VERSION}.tar.gz
wget -O nginx-push-stream-module.tar.gz https://github.com/wandenberg/nginx-push-stream-module/archive/refs/heads/master.tar.gz
tar -zxf nginx-push-stream-module.tar.gz

nginx本体のフォルダにngx_http_csp_module.cを配置します。

cd <作業フォルダ>/nginx-<nginxバージョン>
cp <WebGatewayのキットフォルダ>/install/nginx/ngx_http_csp_module.c .

ここでngx_http_csp_module.cを編集し、ngx_http_parse_chunked()の第4引数の0を追加します。

      ngx_int_t rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
            ↓
      ngx_int_t rc = ngx_http_parse_chunked(r, buf, &ctx->chunked, 0);

カレントフォルダにファイル config を作成し、以下の内容を保存します。

ngx_addon_name=ngx_http_csp_module
HTTP_MODULES="$HTTP_MODULES ngx_http_csp_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_csp_module.c"

nginxのモジュールを追加し、ビルド、インストールします。

./configure --prefix=/usr/local/nginx --add-module=. --add-module=<作業フォルダ>/nginx-push-stream-module-master

make

make install

ポイント:

  • 独自モジュール込みで nginx をビルドしているため、通常の apt install nginx では同じ構成になりません。

2. WebGatewayのインストール

1で展開しているWebGatewayキットフォルダの下のinstallフォルダにてGatewayInstallを実行します。今回は設定を入力する手間を省くため、自動インストールを行っています。

cd <WebGatewayキットフォルダ>/install
ISC_PACKAGE_MODE=unattended
ISC_PACKAGE_PLATFORM=lnxubuntu2404x64
ISC_PACKAGE_HOSTNAME=127.0.0.1
ISC_PACKAGE_SUPERSERVER_PORT=1972
ISC_PACKAGE_INITIAL_SECURITY=Normal
ISC_PACKAGE_WEB_CONFIGURE=N
./GatewayInstall

インストールが終わりましたら、/opt/webgateway/conf フォルダにCSP.iniを作成し、 以下の内容を登録します。

[SYSTEM]
SM_Timeout=28800
Server_Response_Timeout=60
No_Activity_Timeout=86400
Queued_Request_Timeout=60
Event_Log_Rotation_Size=2000000000
Configuration_Initialized=Thu Mar  5 18:55:44 2026
Configuration_Initialized_Build=2501.1851
System_Manager=192.168.10.*
Username=CSPSystem
Password=SYS

[SYSTEM_INDEX]
LOCAL=Enabled

[LOCAL]
Ip_Address=127.0.0.1
TCP_Port=1972
Minimum_Server_Connections=3
Maximum_Session_Connections=6
Username=CSPSystem
Password=SYS

[APP_PATH_INDEX]
/=Enabled
/csp=Enabled

[APP_PATH:/]
Default_Server=LOCAL

[APP_PATH:/csp]
Default_Server=LOCAL

ポイント:

  • Apacheを使用しないため、ISC_PACKAGE_WEB_CONFIGURE=N としています。
  • /opt/webgateway/binフォルダにあるCSPnsdをシステム起動時に自動起動させる必要があります。
  • System_managerパラメータにはWeb Gateway Managerを使用するクライアントIPアドレス(IPセグメント)が入ります。
  • Passwordパラメータは必ず変更してください。またCSPnsdが起動すると自動的に暗号化されます。

3. nginx.conf で Web/API/SSE を振り分ける

nginx.conf は大きく 3 つの責務を持ちます。 この切り分けを最初に決めておくと、後の運用がぐっと楽になります。

  1. SPA配信 (location /)
  2. IRIS連携 (location /csp : 必要に応じてIRISを起動するパスを追加してください)
  3. SSE (location /subscribe, /publish)

SPA配信は次の設定です。

location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    # ルーティングを index.html に集約させる設定
    try_files $uri $uri/ /index.html;
}

IRIS連携は次の設定です。

location /csp {
    CSP On;
    CSPFileTypes  csp cls zen cxw .jpg .gif .png .svg .css .js;
    CSPNSD_pass localhost:7038;
}

ここで、CSPNSD_pass は CSPnsdが受けているホスト名とポート番号(デフォルトが7038)です。

SSE 部分は次の設定です。

push_stream_shared_memory_size 32M;

location /subscribe {
    push_stream_subscriber eventsource;
    push_stream_channels_path $arg_id;
    push_stream_ping_message_interval 30s;
}

location /publish {
    push_stream_publisher admin;
    push_stream_channels_path $arg_id;
    allow 127.0.0.1;
    deny all;
}

ポイント:

  • push_stream_channels_path $arg_id; により、?id=ch1 のような URL パラメータでチャネルを分離できます。
  • /publishallow/deny で送信元を制限し、外部からの不正投稿を防ぎます。
  • push_stream_ping_message_interval により、長時間接続でも生存確認がしやすくなります。

4. クライアント側で SSE を受信する

client/src/app.js では EventSource を使って購読しています。 実装は最小限で、ブラウザ標準 API だけで始められるのが SSE の強みです。

const source = new EventSource("/subscribe?id=ch1");

source.onmessage = function (event) {
  const line = "[" + new Date().toLocaleTimeString() + "] " + event.data;
  setMessages(function (prev) {
    return prev.concat([line]);
  });
};

この実装では

  • 接続状態を connecting / connected / reconnecting で表示
  • 受信メッセージを時刻付きで画面に追記
  • コンポーネント破棄時に source.close() で接続を解放
  • リロードや一時的な切断時にも、自動再接続の恩恵を受けやすい構成

5. サーバ側から通知を送る

/publish に POST すると、同一チャネルの購読者へ配信されます。 「定期的に取りに行く」のではなく「来たときだけ受け取る」に変えることで、待ち受け画面の負荷を抑えやすくなります。 実行例は以下の通りです。

set req=##class(%Net.HttpRequest).%New()
set req.Server="localhost"
set req.Port=80
do req.EntityBody.Write("日本語メッセージ")
set sc=req.Post("/publish?id=ch1")

ローカル送信のみ許可する設定のため、IRISからの通知は安全です。

6. 運用時の注意点

  • 認証/認可: /publish は IP 制限に加えて、必要に応じて認証も追加
  • チャネル設計: クライアント単位などで id 命名規則を明確化
  • 監視: nginx の接続数・メモリ (push_stream_shared_memory_size) を監視
  • タイムアウト: プロキシや LB 配下で SSE が切断されないよう keep-alive 設定を確認

まとめ

この構成を使うと、IRIS/Web Gateway と同居した nginx 上で、比較的シンプルにリアルタイム通知基盤を提供できます。 特に「待ち受け画面のポーリング負荷やライセンス消費を減らしたい」という相談に対して、現実的な改善案として適用しやすいアプローチです。 まずは単一チャネルで検証し、次にチャネル設計とセキュリティを強化して本番へ展開するのがおすすめです。