LoginSignup
23
24

More than 5 years have passed since last update.

José Valimさんのstackoverflowに学ぶ「Elixirによる簡易無限ループ」を実装して常駐プロセスとして動かしみよう!

Posted at

1. やりたいこと

Elixirで無限ループってどうやって書くのかなー、と、GenServerを利用しているライブラリをGitHubで漁りながら眺めていたのですが、なかなかないなー、と。

そんな時に、José Valimさんがstackoverflowで、同じような質問をしている人に快く回答しているのを見かけました。

2. 実装して動かしてみた

2-1. 自分でも写経ベースで試してみた

S3に保存したテストデータをランダムに加工しながら、kinesisに等間隔秒に流し込むモジュールを作りたかったので、下記のように実装してみました。

defmodule GenerateTestData4kinesis.Runner do
  @moduledoc"""
  S3からデータを取得してkinesisにテストデータを流し込みます
  """
  use GenServer
  require Logger

  @doc"""
  """
  def start_link do
    GenServer.start_link(__MODULE__, [], name: :generate_test_data4kinesis)
  end

  @doc"""
  """
  def init([]) do
    my_loop()
    {:ok, []}
  end

  @doc"""
  """
  def my_loop do
    Process.send_after(self(), :my_work, 1_000)
  end

  @doc"""
  """
  def handle_info(:my_work, state) do
    state = put_data(state)
    my_loop()
    {:noreply, state}
  end

  @doc"""
  kinesisにデータを流し込む処理です
  """
  def put_data(state) do
    GenerateTestData4kinesis.main([])
  end

end
  1. Genserver.start_linkが呼ばれる
  2. init([])が呼ばれる
  3. my_loopが呼ばれる
  4. my_workが呼ばれる
  5. handle_infoで、put_dataが呼ばれる
  6. handle_infoの中で、再度、my_workが呼ばれる

以下、4,5,6の繰り返し、となります。

2-2. メイン処理

上記をコールするメインは以下のようにしました。
実態の処理は割愛します。

defmodule GenerateTestData4kinesis do
  @moduledoc"""
  """

  require Logger
  use Application

  @doc"""
  """
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      worker(GenerateTestData4kinesis.Runner, [])
    ]

    opts = [strategy: :one_for_one, name: GenerateTestData4kinesis.Runner]
    Supervisor.start_link(children, opts)
  end

  @doc"""
  """
  def main(args) do
    #write your code
  end

end

2-3. 常駐プロセスとして動かしちゃう

MIX_ENVはお好みで、ということで、下記のようにキックすることで永遠と動き続けるプロセスを立ち上げることができました。

MIX_ENV=***** elixir --detached  -S mix run -e "GenerateTestData4kinesis.start(:fuga,:hoge)" --no-halt

ps -ef | grep elixirとかすると、動いているのが確認できます。
でもバックグラウンドでログを出すとかしてあげないと何やってるのかはわからなくなりますね。。

なお、startの引数は特に、今回評価していないので、意味なしなものを渡しています。

3. もうちょっとstackoverflowを見てみた

下記のような質問も上がってました。
Streamでも行けんじゃね?的な感じでしょうか。

Why not a Task that does its stuff periodically in an infinite loop (possibly powered by Stream.interval or Stream.repeatedly)?
If this is just a periodical pull that forwards the pulled data further to the system, it doesn't really need to be a GenServer, right.
Task is still OTP compliant, and to me it seems more straightforward for the job. 

v1.3からだとできるようになるよー、とのことです。とはいえ、この質問が2015のものだから、2016現在はどんな状況なのかも、また別の機会に見てみようと思います。

The reason is that Task cannot receive system messages.
We want to make Stream and friends aware of those but it isn't in 1.0 and possibly will only be in 1.3. 

4. 所感

結構、簡単に書けちゃうんだなー、と思いました。
ウェブアプリケーションとかじゃなくて、日々の運用系スクリプトとか調査系のスクリプトもElixirの方が書きやすいのかな、といった印象です。

ただ、最新のやり方なのかどうかの確信はないので、もうちょっと公式doc等々見ながらキャッチアップしていこうと思います。Streamも面白そうですしね!^^

5. 参考


本日は以上となります。

23
24
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
23
24