Ohara Lab

gRPC Frame 開発ガイド

デバイスサーバー開発ガイド / gRPC Quick Start / トップ

このページは gRPC Frame を使用したデバイスサーバーの実装方法を扱う。機器操作そのものは DeviceClass に置き、通信上の要求・応答、ストリーミング、イベント配信は Frame とその周辺のクラスで扱う。導入方法はインストールマニュアルに分離する。

ストリーミングとイベントの詳細

1. API 公開:Describe / Call

create_grpc_server(ctrl_obj=...) は DeviceClass のインスタンスを受け取る。GrpcClient は接続時に Describe を実行し、公開メソッドをクライアントに動的にバインドする。呼び出しは Call を経由する。個々の DeviceClass のために RPC メソッドを .proto に逐一追加する必要はない。

from grpc_frame.grpc_server import create_grpc_server
server = create_grpc_server(ctrl_obj=ctrl, max_workers=10)

公開されるメソッド、戻り値の変換、例外の伝達は Frame のディスパッチ/アダプタに依存する。任意の Python オブジェクトが無条件に透過転送されるわけではない。公開対象とデータ型は動作試験で確認する。

2. 同期クライアントと専用クライアント

from grpc_frame.grpc_client import GrpcClient

class InstrumentGrpcClient(GrpcClient):
    def __init__(self, server_ip: str, server_port: int):
        super().__init__(server_ip=server_ip, server_port=server_port)

    def read_and_report(self):
        return self.read_value()  # DeviceClass 側で公開したメソッド

read_and_report はクライアント側の操作をまとめた例であり、Frameが自動生成するRPCではない。専用クライアントの実例は aandd_reader/server_grpc/aandd_reader_grpc_client.py にある。接続終了時は close() を呼ぶ。

3. 非同期クライアント

aandd_reader は AsyncAanddReaderGrpcClient を提供し、await client.meas() の形で利用する。非同期化の内部方式は、利用するクライアント実装を確認する。同期クライアントと同じ名前のメソッドが存在しても、戻り値や実行方式が同一とは限らない。

import asyncio
from aandd_reader import Config
from aandd_reader.server_grpc import AsyncAanddReaderGrpcClient

async def main():
    client = AsyncAanddReaderGrpcClient(config=Config)
    try:
        print(await client.meas())
    finally:
        client.close()

asyncio.run(main())

この例は Config がサーバーアドレス・ポートを設定済みであることを前提とする。

4. StreamCall:連続データ転送

StreamCall は通常の単一応答 Call とは別のRPCである。MiniPIXの実装では、サーバー側の _MiniPixStream が取得コールバックをキューへ渡し、ジェネレータで測定フレームを順次返す。制御用の ctrl_obj とストリーム用の stream_obj を分けて扱う実装がある。

# サーバー側:stream_obj を受け取る実装の概念例
server = create_grpc_server(ctrl_obj=ctrl, stream_obj=stream_obj)

stream_obj の具体的なメソッド名・引数とクライアントの stream_call(...) の対応は、MiniPIXの pixet_grpc_server.py と async_pixet_grpc_client.py を参照する。ストリームの中断、キューの滞留、取得側の例外、切断時の後始末を実装・検証する。

5. Event:購読型通知

gRPC Frameには EventBus を使用するイベント配信経路があり、GrpcClient.subscribe(topic=..., once=...) で受信する。ストリームによる測定データの逐次転送と、条件成立などを通知するイベント購読は別の機能である。

aandd_reader の専用クライアントは、イベント測定の準備操作を prepare_event_measurement() にまとめている。

client.prepare_event_measurement(
    topic="weight_threshold",
    threshold_g=10.0,
    above=True,
    once=True,
    trigger_mode="raw",
)
event = client.wait_event()
print(event)
client.stream_stop()

このAPIは aandd_reader固有の上位APIであり、GrpcClient 共通メソッドではない。内部では stream_start()、event_set_config()、set_trigger_mode()、event_arm() を呼び、wait_event() は subscribe(topic=..., once=True) を使用する。閾値判定はDeviceClass側の測定機能に属し、購読の通信経路はFrameが扱う。once の意味はイベントのarm側と購読側で区別する。

6. DeviceProxy・型定義

専用クライアントのメソッドを補完可能にするには、DeviceClassの公開メソッドだけでなく、クライアント側で追加・オーバーライドしたメソッドも型定義に反映する。MiniPIXとaandd_readerの server_grpc/make_pyi.py はその実装例である。DeviceProxy を使用しない直接クライアント接続も可能である。登録・生成の扱いはDeviceProxyとFactoryを参照する。

7. 動作確認と運用

サーバー起動時は add_insecure_port の戻り値を検査し、start() 後に接続を確認する。aandd_reader_grpc_server.py は channel_ready_future による自己接続確認、停止時の server.stop(...) と ctrl.close() を実装している。insecure_channel は暗号化しないため、配置ネットワークの安全性を別途検討する。大きなデータを扱う場合は grpc_options のメッセージサイズ制限も確認する。

8. 参照する実装

詳細な実装断片は既存のgRPC実装例を参照する。