15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ElixirAdvent Calendar 2023

Day 3

GenServerとは

Posted at

GenServerとは

GenServerとは状態を保持し、クライアントからのリクエストに応答するプロセスのこと。

具体的にはクライアントから呼び出す関数と、サーバー側のコールバックを実装することで、
クライアントとサーバー間でやり取りを行うことができるようになる。

GenServerモジュールの定義

GenServerのBehaivor(振る舞い)を実装したモジュールのことを、
GenServerモジュールと呼ぶ。

基本的なGenServerモジュールは、次の手順で定義することができる。

  • start_link(初期値)の実装 - GenServerプロセスを開始するためのコールバック
  • init(初期値)の実装 - 上記の関数から引数を受け取り、GenServerプロセスの初期状態を設定するためのコールバック
  • クライアント側の関数を実装する
  • サーバー側のコールバックを実装する

start_link(初期値)の実装

GenServerプロセスは次の2つの関数を使用して生成することができる。

  • GenServer.start(GenServerモジュール, 初期値, オプション)
  • GenServer.start_link(GenServerモジュール, 初期値, オプション)

GenServerモジュールを定義するにはGenServer.start_link(GenServerモジュール, 初期値, オプション)を使用する。

またこれらの関数は、呼び出し元のプロセスとリンクしているかが異なる。

GenServerモジュールのstart_link(初期値)は、このGenServer.start_link(GenServerモジュール, 初期値, オプション)を呼び出す関数となる。

GenServerモジュールのstart_link(初期値)は、次の記述で実装できる。

def start_link(init_status) do
  GenServer.start_link(__MODULE__, init_status, name: __MODULE__)
end

init(初期値)の実装

GenServerモジュールのinit(初期値)は以下のように実装することができる。

def init(init_status) do
{:ok, init_status}

クライアント側の関数を実装する

GenServerプロセスはクライアント-サーバ間でメッセージでやり取りを行う。

実際にはクライアントが実行する関数内で、GenServerプロセスへメッセージの送信を行う。

メッセージを送信する関数は次の2つが存在する。

  • GenServer.call(__MODULE__, メッセージ, ミリ秒(オプション) - クライアントがサーバにメッセージを送信し、応答を待つための関数。またタイムアウトまでのミリ秒を設定することができる。
  • GenServer.cast(__MODULE__, メッセージ) - サーバーがメッセージを受信して、処理を行う関数。応答は返さない。

記述例は以下のようになる。

der initialize_status() do
  GenServer.cast(__MODULE__, {:update, :init})
end

def get_by_key(key) do
  GenServer.call(__MODULE__, {:get, key})
end

サーバー側のコールバックを実装する。

クライアント側の処理を行うには、次の関数を実装する。

  • handle_call(メッセージ, from, status) - GenServer.callからメッセージを受信し、応答を返す。fromは呼び出し元プロセスの情報。
  • handle_cast(メッセージ, status) - GenServer.castからメッセージを受信し、処理を行う。

handle_call(メッセージ, form, status)は次のように実装することができる。

def handle_call(メッセージ, _from, status) do
  {:reply, 応答, 状態}
end

この関数は同期的な操作を行い、戻り値は:replyから始まる。

また同期的な操作を行うため、応答が返るまでクライアントは操作ができない

handle_cast(メッセージ, status)は次のように実装することができる。

def handle_cast(メッセージ, status) do
  {:noreply, 更新後状態)
end

この関数は非同期的な操作を行い、戻り値は:noreplyから始まる。

また非同期的な操作を行うため、クライアントはメッセージを送信直後に操作を行うことができる。

結論

GenServerモジュールを定義するには以下を行う。

  1. start_link(初期値)を定義する。
  2. init(初期値)を定義する。
  3. GenServer.call(__MODULE__, メッセージ)GenServer.cast(__MODULE__, メッセージ)を呼び出すクライアント側の関数を実装する。
  4. メッセージを処理するhandle_call(メッセージ, from, status)handle_cast(メッセージ, status)を実装する。

定義したGenServerモジュールを起動することで、GenServerプロセスを生成し、メッセージを処理することができるようになる。

15
4
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
15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?