6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElixirAdvent Calendar 2024

Day 14

Nerves: PropertyTable で効率的な状態管理を実現

Last updated at Posted at 2024-12-13

Nerves を使った開発を進めると、状態管理やイベント通知を効率的に行いたいと感じる場面が多々あります。そこで便利なのが PropertyTable です。

このライブラリは、Nerves プロジェクトのエコシステムに属し、柔軟なキーバリュー形式のデータ管理と変更イベント通知をサポートします。

この記事では、PropertyTable の基本的な使い方をご紹介させていただきます。

PropertyTable  の特徴

PropertyTable は、Nerves エコシステムの一部として設計されたメモリ内キー–バリューストアで、以下の特徴を持っています。

  • 階層的なキー管理: デフォルトでは文字列リスト形式のキーを使用し、階層的で直感的なデータ管理が可能です。
  • サブスクリプション機能: 特定のパターンに基づいた変更イベントを通知し、リアルタイムの変更追跡を実現します。
  • ETS による高速なデータ操作: データは ETS に保存され、高速かつ効率的な読み取りと書き込みが可能です。
  • 柔軟な拡張性: カスタムマッチャーを実装することで、ユニークなユースケースにも対応できます。

具体的には、VintageNetNervesUEvent などの Nerves ライブラリで使用されており、ネットワーク状態の変化や IP アドレスの更新を監視する際に活用されています。また、柔軟なアラーム管理を実現する Alarmist にも採用されています。

PropertyTable の使い方

基本的にPropertyTable GitHub README の内容そのままです。

PropertyTable のデフォルトのプロパティ形式は String リストですが、これは設定可能です。
この形式を使うことで、階層的なキーと値のストアが実現可能です。

例えば、以下のような AwesomeNetworkTable を設定してネットワークインターフェイスのステータスを管理する場合を考えてみます。

AwesomeNetworkTable
├── available_interfaces
│   └── [eth0, eth1]
└── interface
    ├── eth0
    │   ├── config
    │   │   └── %{ipv4: %{method: :dhcp}}
    │   └── connection
    │       └── :internet
    └── eth1
        ├── config
        │   └── %{ipv4: %{method: :static}}
        └── connection
            └── :disconnected
└── connection
    └── :internet

この例では、AwesomeNetworkTable が PropertyTable の名前に相当します。例えば、"eth1" の接続ステータスは ["interface", "eth1", "connection"] というプロパティで表され、その値は :disconnected となります。

このテーブルを管理するライブラリ(プロデューサー)は、以下のように child_spec を監視ツリーに追加することで PropertyTable を作成します。

defmodule AwesomeSupervisor do
  use Supervisor

  def start_link(_args) do
    Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    children = [
      {PropertyTable, name: AwesomeNetworkTable} #<-- これ
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end

IEx プロンプトからこの例を実行する場合は、PropertyTable.start_link/1 を呼び出して手動で PropertyTable を開始します。

# PropertyTable をインストール
Mix.install([{:property_table, "0.2.6"}])

# PropertyTable サーバーを起動
{:ok, _table} = PropertyTable.start_link(name: AwesomeNetworkTable)

データの操作

プロパティを挿入するには以下のようにします:

PropertyTable.put(AwesomeNetworkTable, ["available_interfaces"], ["eth0", "eth1"])
PropertyTable.put(AwesomeNetworkTable, ["connection"], :internet)
PropertyTable.put(AwesomeNetworkTable, ["interface", "eth0", "config"], %{ipv4: %{method: :dhcp}})
PropertyTable.put(AwesomeNetworkTable, ["interface", "eth0", "connection"], :internet)

1 つのプロパティを取得する場合:

PropertyTable.get(AwesomeNetworkTable, ["interface", "eth0", "config"])

プロパティが階層的な形式を持つため、特定のパターンに一致する複数のプロパティを取得することもできます:

PropertyTable.match(AwesomeNetworkTable, ["interface"])

サブスクリプションとイベント

プロパティの変更をサブスクライブすることで、変更が発生するたびに通知メッセージを受け取ることができます。例えば、"interface" で始まるプロパティの変更を監視するには次のようにします:

PropertyTable.subscribe(AwesomeNetworkTable, ["interface"])

その後、次のような変更を加えると:

PropertyTable.put(AwesomeNetworkTable, ["interface", "eth0", "connection"], :disconnected)
flush

サブスクリプションを設定したプロセスに以下のような %PropertyTable.Event{} メッセージが送信されます:

%PropertyTable.Event{
  table: AwesomeNetworkTable,
  property: ["interface", "eth0", "connection"],
  value: :disconnected,
  timestamp: 200,
  previous_value: :internet,
  previous_timestamp: 100
}

このイベントのタイムスタンプは System.monotonic_time/0 から取得されます。この例では、タイムスタンプの差分を計算することで、"eth0" がインターネットに接続されていた時間を測定することができます。

最近のアップデート (v0.2.6)

最新のリリース v0.2.6 では、以下のような改善が行われました。

新機能

  • :event_transformer** オプション**: PropertyTable.Event.t() をカスタムデータ構造に変換する機能が追加されました。これにより、PropertyTable の内部を抽象化して利用できます。

修正点

  • イベントの :previous_timestamp フィールドが nil になる問題を修正。アプリ再起動後の状態が区別しやすくなりました。
  • 初期化時のプロパティタイムスタンプが統一されました。

これらの改善は、ライブラリ利用者が直面する問題を解決するために導入されました。具体的には、アラーム ID とその説明間の競合状態を修正し、同一タイプの異なるデバイス (例: eth1wlan0) を区別するためのタプルベースのアラーム ID サポートを追加しています。

詳しくは、公式 Changelogをご覧ください。

おわりに

PropertyTable は、Nerves ベースのプロジェクトで状態管理やイベント通知を効率化する強力なツールです。その柔軟性とパフォーマンスにより、ネットワーク状態の追跡や設定の永続化など、多岐にわたるユースケースに対応します。

興味がある方は、PropertyTable を活用して効率的な Nerves プロジェクト開発を体験してみてください。

何か氣づいた点があれば、コメントで共有していただけると嬉しいです。

toukon-qiita-macbook_20230912_091808.jpg

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?