Elixirの分散型DB MnesiaをGenServerでイベントドリブン


# はじめに
###データーベースでイベントドリブンしたい。

この記事は
物の状態をイベントドリブンで取得するために、DBへの他ノードからの書き込みや削除のイベントをGenServerで取得します。

![qiita用スライド #大崎.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295240/805e2326-f4dd-e593-2282-f4d951f7d7c6.png)

分散型DB(Mnesia)を複数のマシンで実行した記事はこちら
[Nerves＋Phoenix 003　エムネチカ：分散型DB Mnesiaを使ってオリジナルCapeのLEDをエムネチカ](https://qiita.com/32hero/items/b7fb8409f3f6d0a60f66)

#参考
- [Mnesia Reference Manual>6.7  Mnesia Event Handling](https://erlang.org/doc/apps/mnesia/Mnesia_chap5.html)
- @twinbee さんの[MnesiaとFlowで高速スモールアナリティクス](https://speakerdeck.com/enpedasi/mnesiatoflowdegao-su-sumoruanariteikusu)

# 環境
- macOS
- elixir 1.10.3-otp-23
- erlang 23.0.2

# 目次
- GenServer
- Mnesiaの開始
- GenServerの開始
- 実行
- 次回は

# GenServer

###GenServerを作成:initでsubscribe開始、handle_infoで受信
```Elixir:mnesiatrigger.exs
defmodule Mnesiatrigger do
  use GenServer
  require Logger

  def start_link(pname, table_name, ppid \\ []) do
    GenServer.start_link(__MODULE__, {table_name , ppid},name: pname)
  end

  def init({table_name, ppid}) do
    # テーブルに関するイベントをsubscribeの対象とする。
    {:ok,mnesiaref} = :mnesia.subscribe({:table, table_name, :simple})
    {:ok,mnesiaref}
  end

  # テーブルへのイベントが発生した場合にメッセージを受信
  def handle_info({:mnesia_table_event,
      {write, {tbl, key, val}, from} = msg},state) do
      IO.inspect("書き込み: table: #{tbl}, key: #{key}, value: #{val}, from: #{inspect(from)}")
    {:noreply, state}
  end

  def handle_info({:mnesia_table_event,
      {delete, {tbl, key}, from} = msg},state) do
      IO.inspect("削除: table: #{tbl}, key: #{key}, from: #{inspect(from)}")
    {:noreply, state}
  end

  # デバッグ用
  # def handle_info({:mnesia_table_event, value = msg},state) do
  #   IO.inspect("#{inspect(value)}")
  #   {:noreply, state}
  # end
end
```

###Mnesiaの開始

まずNode:aでSchema、Tableの作成まで実行

```Elixir:Node->a
iex --name a@192.168.1.61 --cookie comecomeeverybody ./mnesiatrigger.ex
# 停止
iex> :mnesia.stop()
:stopped

# スキーマ削除
iex> :mnesia.delete_schema([node()])
:ok

# スキーマ作成
iex> :mnesia.create_schema([node()])
:ok

# 開始
iex> :mnesia.start()
:ok

# テーブル作成
iex> :mnesia.create_table(Exi, [attributes: [:key, :value]])
{:atomic, :ok}
```

次にNode:bでMnesiaを開始

```Elixir:　Node->b
iex --name b@192.168.1.61 --cookie comecomeeverybody
# 停止
iex> :mnesia.stop()
:stopped

# 開始
iex> :mnesia.start()
:ok
```

次にNode:aでNode:bをNodeに追加

```Elixir:　Node->a
# ノードの追加
iex> :mnesia.change_config(:extra_db_nodes, [:"b@192.168.1.61"])
{:ok, [:"b@192.168.1.61"]}

```

###GenServerの開始

Node:aでGenServerを起動

```Elixir:Node->a
iex> Mnesiatrigger.start_link(:mnetest, Exi, self())
{:ok, #PID<0.206.0>}
```


#実行
- 実行順
    - Node:bでdirty_write
    - Node:bでdirty_delete
    - Node:bでtransaction、write

###実行結果
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Elixirの分散型DB MnesiaをGenServerでイベントドリブン<a href="https://t.co/GNlFSZu0ZY">https://t.co/GNlFSZu0ZY</a><a href="https://twitter.com/hashtag/qiita?src=hash&amp;ref_src=twsrc%5Etfw">#qiita</a><a href="https://twitter.com/hashtag/Elixir?src=hash&amp;ref_src=twsrc%5Etfw">#Elixir</a> <a href="https://twitter.com/hashtag/Nerves?src=hash&amp;ref_src=twsrc%5Etfw">#Nerves</a> <a href="https://twitter.com/hashtag/Phoenix?src=hash&amp;ref_src=twsrc%5Etfw">#Phoenix</a> <a href="https://twitter.com/hashtag/kochi?src=hash&amp;ref_src=twsrc%5Etfw">#kochi</a>.ex <a href="https://twitter.com/hashtag/Mnesia?src=hash&amp;ref_src=twsrc%5Etfw">#Mnesia</a> <a href="https://twitter.com/hashtag/%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%89%E3%83%AA%E3%83%96%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#イベントドリブン</a> <a href="https://t.co/cYHdiBvv7U">pic.twitter.com/cYHdiBvv7U</a></p>&mdash; みっちぃ (@rigutter) <a href="https://twitter.com/rigutter/status/1410520221232762880?ref_src=twsrc%5Etfw">July 1, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#次回は
kochi.exからは
@nishiuchikazuma さんがMnesiaのrapper「Memento」をご紹介。