LoginSignup
17
16

More than 5 years have passed since last update.

Elixirでcronライクなライブラリ「quantum-elixir」を使ってみた!

Last updated at Posted at 2016-03-06

1. やりたいこと

作成したElixirのライブラリを呼び出すジョブを定期的に叩きたいな、と思いました。

  • cronを使う。 -> でもsystemdとかになったらTime Unit使わなきゃいけないしなんとなくわかりづらい。。
  • Jenkinsなどのジョブスケジューラコンテナを立てたりする。 -> 一個だけしか動かしたくないし、牛刀か。。

ということで、Javaのquartzみたいなライブラリないのかな、とあさっていたら見つけました。

2. 作者の人の資料と内部実装について

以下でご紹介されているようです。

pointは2つあるようで、

  1. timeスケジューラのエイリアスを定義しているが、List.foldr等で変換処理を行っているよ
  2. timer処理をProcessライブラリを利用して管理しているよ

と言ったとこでしょうか。2. についてはMacroという表記がスライド中にあるのですが、まだ私はキャッチアップが終わってないのでこれから追いかけてみようと思います。楽しそうですね^^

1. についてのコード

defmodule Quantum.Translator do

  @moduledoc false

  @days   ~w{sun mon tue wed thu fri sat}
  @months ~w{jan feb mar apr may jun jul aug sep oct nov dec}

  # Replaces all occurrences of abbreviated day and month names by their index
  def translate(s) do
    {s, _} = List.foldl @days,   {s, 0}, fn n, acc -> do_translate acc, n end
    {s, _} = List.foldl @months, {s, 1}, fn n, acc -> do_translate acc, n end
    s
  end

  defp do_translate({s, i}, n) do
    {String.replace(s, n, "#{i}"), i + 1}
  end

end

accumulatorのnの値を1個ずつincrementすることで、@days@monthsを数字に変換してますね。

2. についてのコード

defmodule Quantum.Timer do

  @moduledoc false

  def timezone_function do
    case Application.get_env(:quantum, :timezone, :utc) do
      :utc ->
        &:calendar.now_to_universal_time/1
      :local ->
        &:calendar.now_to_local_time/1
      timezone ->
        raise "Unsupported timezone: #{timezone}"
    end
  end

  def tick do
    {d, {h, m, s}} = timezone_function.(:os.timestamp)
    Process.send_after(self, :tick, (60 - s) * 1000)
    {d, h, m}
  end
end

ここがちょっとまだ?な状態です。&演算子ってなんだっけ。。

send_afterについてはelixir Process apiを見てみます^^

3. 使ってみました

以下のリポジトリで使ってみました。

3-1. mix.exsを編集

quantumを追加しました。

  defp deps do
    [{:mix_test_watch, "~> 0.2", only: :dev},
     {:tentacat, "~> 0.2"},
     {:riak, "~> 1.0"},
     {:poison, "~> 2.0"},
     {:quantum, ">= 1.6.1"},
     {:factory_girl_elixir, "~> 0.1.1"},
     {:credo, "~> 0.3", only: [:dev, :test]}]
  end

applicationにも追加が必要なようです。

defp applications(_all), do: [:logger, :tentacat, :riak, :quantum]

3-2. quantum用のconigを作成

Mixconfigファイル設定で、スケジュールと実行させるメソッドを定義づけることができるようです。

READMEを参考にしつつ、毎分起動するジョブを定義しました。

config :quantum, cron: [
    # Every minute
    "* * * * *": {GithubStalking, :say_hello}
]

呼ばれている関数の実態は以下のとおりです。

  def say_hello() do
    Logger.info("Hello! World!")
  end

3-3. 常駐プロセス型のメソッドを用意する

ちょっとカッコよく書きましたが、お試しなので、無限ループするメソッドをちょろっと用意して試すことにしました。

毎秒インクリメントされた数字を表示するようにします。

  def my_loop(i) do
    :timer.sleep(1000)
    Logger.info(i)
    my_loop(x+1)
  end

3-4. mix runで実行する

mix run -e 'GithubStalking.my_loop(0)'

もちろん、この時点でdetatchしても良さそうですね。

3-5. 出力の様子

06:17:55.557 [info]  1893

06:17:56.562 [info]  1894

06:17:57.564 [info]  1895

06:17:58.566 [info]  1896

06:17:59.569 [info]  1897

06:18:00.236 [info]  Hello! World!

06:18:00.573 [info]  1898

と、上記のような感じで毎分出力され続けます。

常時実行しているプロセスに対して割り込みのような形で起動しているのか、などなどはきちんとソースを読んで確認してみようと思います^^

4. 所感

  • 設定自体は簡単なので気軽にお試しができそう。
  • ソースも小さいし、勉強がてら読むのには良さそう。
  • エラーハンドリングがしづらい。。ジョブが動いた時に、ジョブの内部でエラーが起きた時に出力されるエラー内容がきちんと表示されないような。。(ソース読もう!)

5. 参考


本日は以上となります。

17
16
2

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
17
16