この記事で学べること
- 数秒〜数時間かかる実験をObservable Commandで扱う理由
- Waiting、Running、Finished Successfully、Finished With Errorの状態遷移
- Command Execution UUIDとLifetime of Executionの役割
- 進捗、残り時間、中間応答、最終Responseの違い
- 入力エラー、実行時エラー、通信断を分けて処理する方法
- 公式Python SDKを使った模擬温度保持実験の実装と検証結果
測定、加熱、反応、分注、分析などは、結果が返るまで数秒から数時間かかることがあります。通常の同期的なAPI呼び出しとして待ち続けるだけでは、「装置が待機中なのか」「処理中なのか」「通信だけが切れたのか」が分かりません。再試行によって同じ実験を二重に開始する危険もあります。
SiLA 2では、このような処理をObservable Commandとして表し、実行そのものと、進捗・中間結果・最終結果の取得を分離できます。SiLA 2全体における位置づけは、実験自動化の通信・制御・標準を整理するも参照してください。
結論:長時間実験は「開始」と「追跡」を分けて設計する
長時間Commandの基本設計は次のとおりです。
- Clientが実験条件を送ってCommandを開始する。
- Serverは受付後、Command Execution UUIDを返す。
- ClientはUUIDを使って状態、進捗、残り時間、中間応答を追跡する。
- 終了後、同じUUIDで最終Responseまたは実行エラーを取得する。
- 通信が切れても、受理済みCommandを安易に再送しない。
SiLA公式仕様では、Observable Commandを受け付けたServerはCommand Execution UUIDを返さなければなりません。ServerはCommandを直ちに実行するだけでなく、待ち行列へ入れることもできます[1]。このため「開始要求が返った」ことと「実験が完了した」ことを明確に分離できます。
Unobservable Commandとの違い
| 観点 | Unobservable | Observable |
|---|---|---|
| 適した処理 | 短い設定変更、即時処理 | 測定、反応、加熱保持、長い校正 |
| 開始時の応答 | 処理結果 | Execution UUID |
| 状態・進捗 | 追跡できない | 取得・購読できる |
| 中間応答 | 定義できない | 必要に応じて定義できる |
| 通信断後 | 結果を受け取れない可能性 | UUIDの有効期間内なら追跡可能 |
公式仕様は、進捗や状態を観察する意味がある処理、または接続断が起きても結果を失いたくない処理をObservableにすることを推奨しています。単に設定値を送る処理はUnobservableが適する場合があります[1]。判断の中心は「何秒以上」ではなく、利用者が完了を待つか、途中状態が必要か、再実行が危険かです。
Observable Commandの状態遷移
Command Execution Statusは、次の順序で進みます[1]。
| 状態 | 意味 | Client側の行動 |
|---|---|---|
| Command Waiting | 受付済みだが、資源待ちなどで未開始 | 再送せず待機する |
| Command Running | 処理中 | 進捗や中間応答を監視する |
| Command Finished Successfully | 正常完了 | 最終Responseを取得する |
| Command Finished With Error | 実行中に失敗 | エラーを取得し、復旧方針を選ぶ |
状態は前の状態へ戻りません。RunningになったCommandがWaitingへ戻る設計は避けます。再試行のために再度待ち行列へ入れる必要があるなら、同じ実行内の内部状態として扱うか、失敗を確定して新しいCommandとして開始します。
Execution UUIDとLifetime of Execution
Execution UUIDは実験実行を識別する鍵
Execution UUIDは、特定のCommand呼び出し1回を識別します。Feature名や試料IDだけでは、同じ条件を繰り返した2回の実験を区別できません。ServerはUUIDを使って、状態、Response、中間応答、エラーを同じ実行へ結び付けます。仕様上、Clientは状態やResponseを取得するときにこのUUIDを使用します[1]。
実務ではUUIDをワークフロー実行ID、試料ID、実験計画IDと一緒に記録します。これにより、「試料Aの測定要求」と「装置上で実際に動いたCommand」を後から対応づけられます。実験データ全体の識別子設計は実験装置・LIMS・データベースを連携する設計にも関係します。
Lifetime of ExecutionはUUIDを保持する期間
Lifetime of Executionは、Execution UUIDが有効であり続ける期間です。指定しない場合、UUIDはSiLA ServerのLifetime中有効でなければなりませんが、Server資源を管理できるよう、仕様では有限のLifetimeを返すことが推奨されています[1]。
Lifetimeは実験のタイムアウトとは違います。「実験を何分で中止するか」ではなく、「終了後を含め、いつまで状態や結果を問い合わせられるか」です。実験が予定より長引く場合、Lifetimeは延長できますが、いったん示した絶対的な有効期限を短縮してはいけません[1]。
進捗・残り時間・中間応答・最終結果を分ける
| 情報 | 目的 | 温度保持の例 | 確実性 |
|---|---|---|---|
| Status | 実行段階を判断 | Waiting、Running、Finished | 状態機械として必須 |
| Progress Info | 概算進捗を表示 | 保持時間の67% | 推定値になり得る |
| Estimated Remaining Time | 残り時間の目安 | 残り1秒 | 条件変動で変わり得る |
| Intermediate Response | 途中で得られた実データ | 経過秒、途中スペクトル | 購読型で取りこぼし得る |
| Command Response | 完了後の確定結果 | 完了時刻、最終データ | 後工程に必要な情報を置く |
Intermediate ResponseはObservable Commandにだけ定義できます。公式仕様は、長時間処理の途中結果に有用としながら、購読型のため必ず受信される保証はないと注意しています。失ってはいけない結果はIntermediate Responseだけに置かず、最終Command Responseにも含める必要があります[2]。
進捗率は根拠のある分母から計算する
「処理中だから50%」のような固定値は役に立ちません。保持時間3秒なら、経過秒数÷3で計算できます。一方、目標温度への到達時間が予測できないなら、加熱段階を全体の何%とするかは不確かです。その場合は、CurrentTemperatureやOperatingStateをObservable Propertyとして公開し、Progress Infoは保持工程だけに限定する方が誠実です。
SiLA Part AはProgress Infoを0〜100%として説明します[1]。今回検証したPython SDK v0.14.0のServer APIでは0〜1の値を設定し、Client表示時に100倍しました。これはSDK固有のAPI表現なので、規格の記述と区別してください[3]。
温度保持CommandのFeature設計例
公開可能な仮想装置に、次のCommandを定義しました。
<Command>
<Identifier>RunTemperatureHold</Identifier>
<DisplayName>Run Temperature Hold</DisplayName>
<Description>Moves to a target temperature and holds it.</Description>
<Observable>Yes</Observable>
<Parameter>...TargetTemperature...</Parameter>
<Parameter>...HoldDuration...</Parameter>
<Response>...CompletedAt...</Response>
<IntermediateResponse>...ElapsedSeconds...</IntermediateResponse>
<DefinedExecutionErrors>
<Identifier>TargetNotReached</Identifier>
</DefinedExecutionErrors>
</Command>
TargetTemperatureとHoldDurationは開始前に検証できるParameterです。CompletedAtは確定結果、ElapsedSecondsは途中経過です。目標温度が入力範囲内でも、ヒーター故障などで到達できない場合はTargetNotReachedというDefined Execution Errorにします。
Python Serverで進捗と中間応答を送る
2026年10月13日時点で、公式sila_pythonのv0.14.0を使用して検証しました。これはSiLA規格そのものではなく、Python向け実装です[3][4]。Feature Definitionから生成したBaseクラスを継承し、Observable Commandを次のように実装します。
def RunTemperatureHold(
self, TargetTemperature, HoldDuration, *, metadata, instance
):
instance.begin_execution()
instance.progress = 0.0
instance.estimated_remaining_time = timedelta(seconds=HoldDuration)
if TargetTemperature == 199.0: # 模擬故障
raise TargetNotReached("simulated heater fault")
for elapsed in range(1, HoldDuration + 1):
time.sleep(1)
instance.send_intermediate_response(
RunTemperatureHold_IntermediateResponses(elapsed)
)
instance.progress = elapsed / HoldDuration
instance.estimated_remaining_time = timedelta(
seconds=HoldDuration - elapsed
)
return RunTemperatureHold_Responses(datetime.now(timezone.utc))
実機ではtime.sleepの代わりに、装置ドライバの状態確認、イベント通知、PLC信号などを使います。SiLA Serverのスレッド内で安全制御を行うのではなく、装置・PLC側が保証した状態を上位へ報告する構成にします。
Python Clientで開始・監視・結果取得を行う
command = client.TemperatureController.RunTemperatureHold(40.0, 3)
updates = command.subscribe_to_intermediate_responses()
print(command.execution_uuid)
while not command.done:
progress = None if command.progress is None else command.progress * 100
print(command.status, progress, command.estimated_remaining_time)
time.sleep(0.4)
response = command.get_responses()
elapsed = [x.ElapsedSeconds for x in updates]
print(response.CompletedAt, elapsed)
開始直後にget_responses()を呼ぶと、まだ実行中であるためCommandExecutionNotFinishedになります。完了フラグや状態を確認してから最終Responseを取得します。
実行して確認した結果
Python 3.12.14、sila2 v0.14.0、ローカルの暗号化なし接続で、次を確認しました。暗号化なし接続は閉じた検証環境だけに限定し、本番環境では証明書とネットワーク設計が必要です。
| 試験 | 入力・操作 | 結果 |
|---|---|---|
| 正常完了 | 40℃、3秒保持 | UUID発行、Running、正常完了 |
| 早すぎる結果取得 | 開始直後にget_responses | CommandExecutionNotFinished |
| 進捗 | 3秒処理を監視 | 0%、33%、67%、完了を確認 |
| 中間応答 | ElapsedSecondsを購読 | [1, 2, 3]を受信 |
| 入力制約違反 | HoldDuration=-1 | ValidationError |
| 実行時エラー | 模擬故障条件199℃ | TargetNotReachedをDefinedExecutionErrorとして取得 |
公式リポジトリのTimerProviderも、CountdownをObservable Commandとして実装し、進捗、残り時間、Lifetime、中間応答、Defined Execution Errorを扱っています[5]。今回のコードはこの設計を温度保持へ置き換え、入力エラーと実行時エラーの違いが分かるようにしました。
エラーを4種類に分ける
1. Validation Error
型、単位、範囲などがFeature定義に合わない入力です。今回のHoldDuration=-1が該当します。Commandを装置へ渡す前に拒否できるため、同じ値をそのまま再送しても成功しません。
2. Defined Execution Error
入力形式は正しいものの、装置状態や実験条件により実行できない、または途中で失敗したケースです。DeviceBusy、SafetyInterlockOpen、TargetNotReachedなど、Clientが次の行動を選べる名称にします。
3. Undefined Execution Error
設計時に予測できなかった実装例外です。ログ、装置状態、Execution UUIDを保存し、原因を調査します。何でもDefined Execution Errorに変換すると、本当の不具合が見えなくなります。
4. Connection Error
ClientとServerの通信問題です。SiLA仕様では、接続が失われても、Serverは受理済みObservable Commandの処理を継続し、UUIDを規定期間有効に保つ必要があります。一方、切断したClientへの状態配信は停止するため、Client側が再接続し再購読します[1]。今回のSDK検証では意図的切断後の再購読までは確認していないため、本番導入前の相互接続試験項目です。
再試行と二重実行をどう防ぐか
通信タイムアウトは「実験が失敗した」という意味ではありません。Serverが要求を受理した直後に応答だけが失われた場合、同じCommandを再送すると二重実行になり得ます。
- Execution UUIDを受け取ったら永続化する
- 通信断後は、まず既存UUIDの状態を照会する
- 開始要求にはワークフロー側の一意な依頼IDをMetadata等で渡す設計を検討する
- Server側で同じ依頼IDの重複受付を拒否または既存実行へ関連づける
- 共有装置は資源ロックと排他制御を設計する
この設計はSiLAだけで完結せず、ワークフローエンジン、LIMS、データベース、装置ドライバを含むシステム設計です。実験自動化全体の導入手順は実験自動化とは?で整理しています。
安全と責任範囲
Observable Commandは進捗追跡を改善しますが、安全機能ではありません。ネットワーク、Client、Serverのいずれも停止し得ます。温度、圧力、流量、回転、ロボット動作などの危険を伴う処理では、非常停止、上限監視、インターロック、PID制御を装置・PLC・安全回路側で成立させます。
上位システムは「Command Finished With Error」を受け取った後、装置が安全状態かをProperty等で確認します。エラー通知を受けたことと、物理的に停止したことを同一視してはいけません。閉ループ実験でも、人間の承認が必要な条件範囲と自動実行可能範囲を分けます。関連する全体像は自律実験・Self-driving Labとは?を参照してください。
実装チェックリスト
- 長時間処理をObservable Commandとして定義した
- Waiting、Running、成功、失敗の遷移を試験した
- Execution UUIDをワークフロー記録へ保存した
- Lifetime of Executionが結果取得に十分な長さである
- 進捗率の分母と更新条件を説明できる
- 残り時間が推定値であることをClientが扱える
- 失ってはいけないデータを最終Responseに含めた
- Validation、Defined、Undefined、Connection Errorを分けた
- 通信断後に無条件でCommandを再送しない
- 複数Clientの競合と資源ロックを試験した
- 安全制御を装置・PLC側に残した
FAQ
何秒以上ならObservableにすべきですか?
固定の秒数では決まりません。進捗を知る必要、結果消失の影響、再実行の危険、資源待ちの有無で判断します。
Progress InfoとIntermediate Responseは同じですか?
違います。Progress Infoは概算進捗、Intermediate Responseは途中で生成されたデータです。途中スペクトルや経過秒などを返せますが、確実な保存先にはしません。
通信が切れたらCommandは停止しますか?
受理済みObservable CommandはServer側で継続するのが仕様です[1]。Clientは再接続し、UUIDを使って状態と結果を追跡します。ただし、使用SDKと装置で実際の再接続試験が必要です。
Clientから汎用的に緊急停止できますか?
緊急停止をネットワークCommandだけに依存してはいけません。必要なら装置固有の停止Commandとは別に、ハードウェア安全回路を設計します。
まとめ
SiLA 2のObservable Commandは、長時間実験の開始と追跡を分けます。Execution UUIDを中心に、状態、進捗、残り時間、中間応答、最終Response、エラーを同じ実行へ結び付けます。通信断時には再送より先に既存実行を確認し、二重実行を防ぎます。
実装では、意味のある状態遷移、根拠のある進捗、十分なLifetime、分類されたエラー、実験記録とのID連携が重要です。さらに安全制御は装置・PLC側に残し、SiLAは上位の実験ワークフローと監視を担わせます。
参考文献
- Association Consortium Standardization in Lab Automation, “SiLA 2 Part (A) – Overview, Concepts and Core Specification,” Public Document Release v1.1, 19 March 2022. PDF
- Association Consortium Standardization in Lab Automation, “SiLA 2 Part (A), Intermediate Command Responses,” Release v1.1, 2022. SiLA Standards
- SiLA2, “sila_python,” official GitLab repository, 確認日 2026-10-13. official repository
- SiLA2, “sila_python v0.14.0,” tag/commit b3c611565d6df1d6747eb8cb7c211aed5e3e2055, 2025-12-01. v0.14.0
- SiLA2, “TimerProvider implementation and Feature Definition,” sila_python v0.14.0 example server. official example


