Livebook の Smart Cell からリモートの Phoenix に接続し、リモート上の情報をグラフ化する

## はじめに

Livebook Launch Week 2 を自分でやってみるシリーズ

- Day1: Smart Cell からのリモート接続 <- ここ
- Day2: [Whisper による音声認識の新機能](https://qiita.com/RyoWakabayashi/private/4db05611945f3bba6e30)
- Day3: [ファイルをドラッグ＆ドロップすると、扱うためのコードを自動生成する](https://qiita.com/RyoWakabayashi/private/0a2760c88001076c0c7b)
- Day4:
  - [データクラウド Snowflake に接続する](https://qiita.com/RyoWakabayashi/private/98db4a51c6a275541ec2)
  - [Microsoft SQL Server に接続する](https://qiita.com/RyoWakabayashi/private/ab1ce456eaa14b1da6f8)
- Day5: [Vim と Emacs のキーバインド](https://qiita.com/RyoWakabayashi/items/c95934c690d663918a8a)

Day 1 は Smart Cell からのリモート接続です

https://news.livebook.dev/remote-execution-smart-cell---launch-week-2---day-1-m3dv2

今までもリモートノードに接続できていましたが、 Smart Cell からの実行では「自由に Kino などを使った視覚化ができる」のが特徴です

本記事では Attached node によるリモート接続と、 Smart Cell によるリモート接続を両方実行し、比較します

## Phoenix の準備

以下のコマンドで Phoenix プロジェクトを新規作成します

:::note info
今回は DB を使わないため `--no-ecto` を指定しています
:::

```bash
mix phx.new phoenix_sample --no-ecto
```

`Fetch and install dependencies? [Yn]` と訊かれるので、そのまま Enter を押して依存モジュールをインストールしましょう

作成された Phoenix プロジェクトのディレクトリーに移動します

```bash
code phoenix_sample
```

ノード名とクッキーを指定して Phoenix を起動します

```bash
iex --sname phoenix_sample --cookie mycookie -S mix phx.server
```

ブラウザで http://localhost:4000/ を開くと Phoenix の初期画面が表示されます

![スクリーンショット 2023-11-05 8.38.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/705a2697-6110-56b9-3e7f-6ca7619f6f5d.png)

## Livebook の準備

今回はローカルで Livebook を起動します

Livebook の README にある通り、 Elixir と Erlang のある環境下でコマンドを実行します

https://github.com/livebook-dev/livebook

```bash
git clone https://github.com/livebook-dev/livebook.git

cd livebook

mix deps.get --only prod

MIX_ENV=prod mix phx.server
```

ブラウザで http://localhost:8080/ を開くと Livebook のホーム画面が表示されます

## Attached node によるリモート接続

Livebook のホーム画面から右上の + New notebook をクリックし、新しいノートブックを開きます

![スクリーンショット 2023-11-05 8.40.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/9332cb6f-d8a3-1086-95be-01a26530d7b3.png)

Livebook の左メニュー CPU アイコンをクリックし、 RUNTIME メニューを開きます

RUNTIME メニューの Type が ELixir standalone になっており、ノードに接続されていないことが分かります

RUNTIME メニューの上部 RUNTIME という文字の右側にある歯車アイコンをクリックします 

![スクリーンショット 2023-11-05 8.34.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/718cefa8-0061-ebb0-6b59-8710d718005f.png)

Runtime settings ノードが開くので、 Attached node をクリックします

![スクリーンショット 2023-11-05 8.34.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/b9650d3e-c19f-c40b-ee11-e93ca441a801.png)

Name　と Cookie に Phoenix 起動時に指定したノード名、クッキーを入力し、 Connect をクリックします

これによって、作成した Phoenix プロジェクトに接続されます

モーダルを閉じると RUNTIME メニューの Type が Attached になっています

![スクリーンショット 2023-11-05 8.46.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/015671d4-4378-8f23-ecef-2c41b996d85f.png)

この状態でセットアップセルの右上、モジュール追加のアイコンにマウスカーソルを合わせると、 `The current runtime does not support adding dependencies` とツールチップが表示されます

本来、ノートブックは Kino などのモジュールを追加することでデータを視覚化できるのですが、 Attached node の状態では接続先ノードの中で動いているため、 **モジュールを追加できなくなっています**

セルに `Pho` と入力すると、補完候補に `PhoenixSample` や `PhoenixSampleWeb` が表示され、確かにリモート接続できている（リモートの情報が取得できている）ことが分かります

![スクリーンショット 2023-11-05 8.52.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/a8e37790-66b3-a64f-ecdd-9a08cd6744b4.png)

![スクリーンショット 2023-11-05 8.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/1b752406-69da-7cdd-a645-a317387c0dca.png)

セルに以下のコードを入力し、実行します

```elixir
PhoenixSampleWeb.Endpoint.server_info(:http)
```

実行結果
```elixir
{:ok, {{127, 0, 0, 1}, 4000}}
```

リモートノードが IP アドレス 127.0.01 の 4000 番ポートで起動していることが分かります

次のセルに以下のコードを入力して実行します

```elixir
Range.new(1, 10)
|> Enum.map(fn _ ->
  Process.sleep(1000)
  :erlang.memory(:total)
end)
```

実行結果
```elixir
[64342032, 64412112, 64449024, 64496960, 64387800, 64674576, 64716656, 64669320, 64711400, 64632640]
```

1秒間隔で Phoenix のメモリ使用量が取得できました

しかし、 Kino などをインストールできないため、これをグラフ化することはできません

## Smart Cell によるリモート接続

Livebook のホーム画面から右上の + New notebook をクリックし、新しいノートブックを開きます

セットアップセルに以下のコードを入力し、実行します

```elixir
Mix.install([
  {:kino, "~> 0.11"},
  {:kino_vega_lite, "~> 0.1"}
])
```
:::note info
リモート接続に必要なのは Kino だけです

KinoVegaLite は後でグラフ化するために追加しています
:::

Smart Cell の Remote execution をクリックします

![スクリーンショット 2023-11-05 9.06.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/82e1c902-d736-b01f-7cca-b12e14ac5121.png)

リモート実行用のフォームが表示されました

![スクリーンショット 2023-11-05 9.10.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/512d6692-2e39-a5e3-8f28-01a1e5606504.png)

以下の内容を入力してください

- NODE:
Phoenix 起動時に指定したノード名 + `@<接続先のホスト名>`
今回は接続先がローカルなので、ローカルマシンのホスト名を指定します
macOS の場合、 `scutil --get ComputerName` でローカルマシンのホスト名が取得できます

- COOKIE:
秘密情報なのでモーダルが開きます
Name に COOKIE 、 Value にPhoenix 起動時に指定したクッキーを入力します

- ASSIGN TO:
`server_info`

セルに以下のコードを入力します

```elixir
PhoenixSampleWeb.Endpoint.server_info(:http) |> elem(1)
```

左上の Evaluate をクリックします

実行結果が表示されました

![スクリーンショット 2023-11-05 9.25.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/6fecd743-05a1-a418-2ebd-5f6d1bdaef0c.png)

次のセルに以下のコードを入力し、実行します

```elixir
server_info
```

実行結果
```elixir
{{127, 0, 0, 1}, 4000}
```

ASSIGN TO に指定した変数に実行結果が格納されています

もう一つ Remote execution の Smart Cell を追加し、 ASSIGN TO を `memory_usage` にして、今度は以下のコードを実行しましょう

```elixir
Range.new(1, 10)
|> Enum.map(fn _ ->
  Process.sleep(1000)
  %{
    datetime: Time.utc_now,
    memory_usage: :erlang.memory(:total)
  }
end)
```

実行結果
```elixir
[
  %{memory_usage: 62264192, datetime: ~T[00:40:06.003698]},
  %{memory_usage: 62297544, datetime: ~T[00:40:07.013753]},
  %{memory_usage: 62324520, datetime: ~T[00:40:08.014687]},
  %{memory_usage: 62360928, datetime: ~T[00:40:09.016141]},
  %{memory_usage: 62319392, datetime: ~T[00:40:10.016745]},
  %{memory_usage: 62337720, datetime: ~T[00:40:11.017705]},
  %{memory_usage: 62387992, datetime: ~T[00:40:12.018881]},
  %{memory_usage: 62432032, datetime: ~T[00:40:13.019670]},
  %{memory_usage: 62379944, datetime: ~T[00:40:14.020829]},
  %{memory_usage: 62422032, datetime: ~T[00:40:15.021712]}
]
```

メモリ使用量の推移が取得できました

これをグラフ化しましょう

Chart の Smart Cell を追加します

![スクリーンショット 2023-11-05 9.34.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/93f0881c-90fe-e419-5a86-ee89eb0542cf.png)

以下のように指定し、 Evaluate をクリックします

- WIDTH: 700
- Chart: line
- x-axis の Type(歯車アインコンで表示): nominal

![スクリーンショット 2023-11-05 9.44.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/c4b68f6b-c2a1-1a20-2c16-768f6fe51608.png)

メモリ使用量がグラフ化できました

![スクリーンショット 2023-11-05 9.45.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/884ae801-18c9-e8f4-b32b-a083085ceaea.png)

## Remote execution の仕組み

先ほどの Smart Cell の右上鉛筆アイコンをクリックし、セルをコード化すると以下のようになります

```elixir
node = :"phoenix_sample@oec-mac-book-1903"
Node.set_cookie(node, String.to_atom(System.fetch_env!("LB_COOKIE")))

memory_usage =
  :erpc.call(node, fn ->
    Range.new(1, 10)
    |> Enum.map(fn _ ->
      Process.sleep(1000)
      %{datetime: Time.utc_now(), memory_usage: :erlang.memory(:total)}
    end)
  end)
```

Erlang の　erpc　モジュールによってリモート実行していることが分かります

https://www.erlang.org/doc/man/erpc

## まとめ

Attached node によるリモート接続では Kino などのモジュールを追加できないため、せっかくの Livebook の UI/UX を活かしきれませんでした

Remote execution の Smart Cell によって、リモート実行でも自由にモジュールを追加でき、高度な視覚化が実装できます