1.はじめに
最近興味を持っているgRPCをElixirでも試してみました。
所々ハマリどころがあったので、備忘録としてまとめます。
試行環境
ハード | Raspberry Pi 3 B+ |
OS | Ubuntu Server 20.04 LTS |
2.下準備
(1)protocol buffer
のインストール
gRPCの*.proto
ファイルを解釈するのに必要なツールをインストールします。
$ sudo apt-get install libprotobuf-dev libprotoc-dev protobuf-compiler -y $ protoc --version libprotoc 3.6.1 $
(2)protobuf-elixir
のインストール
こちらの内容に従ってインストールします。
GitHub - tony612/protobuf-elixir: A pure Elixir implementation of Google Protobuf
$ git clone https://github.com/tony612/protobuf-elixir.git
$ cd protobuf-elixir
$ mix escript.install hex protobuf
elixirで生成した実行ファイルは~/.mix/escripts
にインストールされます。このディレクトリにパスを通します。
$ nano ~/.bashrc
bashrc
(・・・省略・・・) # for escript export PATH="$PATH:$HOME/.mix/escripts"
$ . ~/.bashrc $ echo $PATH /home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/ubuntu/.mix/escripts $ protoc-gen-elixir --version 0.7.1
使い方
カレントディレクトリのprotoファイルを解釈して、./libディレクトリに出力します。
$ protoc --elixir_out=./lib helloworld.proto
3.gRPC Elixirのサンプルを実行
こちらの内容に従ってチュートリアルを進めます。
GitHub - elixir-grpc/grpc: An Elixir implementation of gRPC
ライブラリの依存関係の処理の途中で聴かれるShall I install rebar3? (if running non-interactively, use "mix local.rebar --force") [Yn]
は、"y"を回答します。
$ git clone https://github.com/elixir-grpc/grpc.git $ cd ./grpc/examples/helloworld/ $ mix do deps.get, compile * Getting protobuf (https://github.com/tony612/protobuf-elixir.git) remote: Enumerating objects: 2002, done. remote: Total 2002 (delta 0), reused 0 (delta 0), pack-reused 2002 Receiving objects: 100% (2002/2002), 428.11 KiB | 598.00 KiB/s, done. Resolving deltas: 100% (1240/1240), done. Resolving Hex dependencies... Dependency resolution completed: Unchanged: cowboy 2.7.0 dialyxir 0.5.1 grpc_cowlib 2.8.1 grpc_gun 2.0.0 ranch 1.7.1 * Getting cowlib (Hex package) * Getting dialyxir (Hex package) * Getting cowboy (Hex package) * Getting gun (Hex package) * Getting ranch (Hex package) ==> protobuf Compiling 21 files (.ex) Generated protobuf app ==> helloworld Could not find "rebar3", which is needed to build dependency :ranch I can install a local copy which is just used by Mix Shall I install rebar3? (if running non-interactively, use "mix local.rebar --force") [Yn] * creating /home/pi/.mix/rebar (・・・省略・・・) ==> helloworld Compiling 4 files (.ex) Generated helloworld app
コンソールをもう一つ開いて、サーバ・クライアントのやりとりを試します。
コンソール1:サーバ
実行したあと、クライアントから要求があると、それに合わせてメッセージを出力します。
$ pwd ...../grpc/examples/helloworld $ mix grpc.server 09:58:22.257 [warn] cowlib should be >= 2.9.0, it's 2.8.1 now. See grpc's README for details 09:58:22.360 [info] Running Helloworld.Endpoint with Cowboy using http://0.0.0.0:50051 09:58:48.344 [info] Handled by Helloworld.Greeter.Server.say_hello 09:58:48.350 [info] Response :ok in 5ms 10:05:26.091 [info] Handled by Helloworld.Greeter.Server.say_hello 10:05:26.091 [info] Response :ok in 11µs
コンソール2:クライアント
その1・iexから操作する例です。
$ pwd ...../grpc/examples/helloworld $ iex -S mix Erlang/OTP 22 [erts-10.6.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] 09:58:29.651 [warn] cowlib should be >= 2.9.0, it's 2.8.1 now. See grpc's README for details Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help) iex(1)> {:ok, channel} = GRPC.Stub.connect("localhost:50051") {:ok, %GRPC.Channel{ accepted_compressors: [], adapter: GRPC.Adapter.Gun, adapter_payload: %{conn_pid: #PID<0.228.0>}, codec: GRPC.Codec.Proto, compressor: nil, cred: nil, headers: [], host: "localhost", interceptors: [], port: 50051, scheme: "http" }} iex(2)> request = Helloworld.HelloRequest.new(name: "grpc-elixir") %Helloworld.HelloRequest{name: "grpc-elixir"} iex(3)> {:ok, reply} = channel |> Helloworld.Greeter.Stub.say_hello(request) {:ok, %Helloworld.HelloReply{message: "Hello grpc-elixir"}} iex(4)> {:ok, channel} = GRPC.Stub.connect("localhost:50051", interceptors: [GRPC.Logger.Client]) {:ok, %GRPC.Channel{ accepted_compressors: [], adapter: GRPC.Adapter.Gun, adapter_payload: %{conn_pid: #PID<0.234.0>}, codec: GRPC.Codec.Proto, compressor: nil, cred: nil, headers: [], host: "localhost", interceptors: [{GRPC.Logger.Client, :info}], port: 50051, scheme: "http" }}
iexのプロンプトを抜けるときは、[Ctrl-\]
を押すか、コマンドラインからiex> System.halt
を入力します。
その2・コマンドラインからクライアントスクリプトを実行する例です。
$ pwd ...../grpc/examples/helloworld $ mix run priv/client.exs 10:05:25.904 [warn] cowlib should be >= 2.9.0, it's 2.8.1 now. See grpc's README for details 10:05:26.046 [info] Call say_hello of helloworld.Greeter 10:05:26.157 [info] Got :ok in 77ms %Helloworld.HelloReply{message: "Hello grpc-elixir"}
補足:実行時にcould not find application file: xmerl.app
が発生
Elixirをaptパッケージで入れると、一部不足するパッケージが出てくるので、必要に応じてパッケージを追加する必要があります。
could not find application file: xmerl.app
の場合は、下記のパッケージを追加します。
$ sudo apt-get install erlang-xmerl