[Elixir]What’s new in Ecto2.0

Elixirの開発元であるPlatformatecからEcto2.0に関するフリーペーパーが正式に公開された。

http://blog.plataformatec.com.br/wp-content/uploads/2016/12/whats-new-in-ecto-2-0-1.pdf

いくつかEctoの特性(Ecto is not your ORMといったこととか)が書かれていて、解決したい問題とその対策として2.0や2.1で入ったことを書いている。

1つ、気になったところをメモとして残しておく。
Ecto2.1からdynamicを使って簡易に動的にwhere句を制御することができるようになった。コードは以下。

https://github.com/elixir-ecto/ecto/blob/v2.1.1/lib/ecto/query.ex#L381

例えば、以下の場合は dynamic で指定した箇所をその引数の状態によって動的に切り替えることができる。
(http://blog.plataformatec.com.br/wp-content/uploads/2016/12/whats-new-in-ecto-2-0-1.pdf より)

これにより、SQLの発行を静的に数多くのパターン実装する必要のある箇所を、限られた少数の実装で表現することができるようになる。個人的に、特にfilter系の関数用意しようとしたら必要以上に行数が増える状態になっていたのでとてもありがたい。時間見つけて適用してみよう。

[Elixir]timestamp in Ecto2.1

Ecto2.1が着々とrcとして改修されていますね。
この中で、Calendar typeの導入が書かれています。

defaultでは、従来は timestamp() などの Ecto.Scheme に設定する値には Ecto.DateTime が格納されていたのですが、ここがデフォルトで NaiveDateTime になるよう。これにより、このSchemeを使っているところは基本的に NativeDateTime でEctoから今まで Ecto.DateTime で受け取っていた時間を扱う必要がありますね。 Ecto.DateTime とかはEcto2.2で完全に削除されるそうな。

https://github.com/elixir-ecto/ecto/blob/e3077b99c24086d5b93580228b1daa6bb0ee0b5a/CHANGELOG.md#integration-with-elixir-13-calendar-types

Schemeの設定としては以下になるそうですね。(ここ@timestamps_opts より。)

[type: :naive_datetime, usec: true]

ちなみに、これが導入PR
https://github.com/elixir-ecto/ecto/commit/12d67912ddddb39ff79cb53d3098569cb427b521

~N[] のsigilとか使われてて、個人的には Map だけで表現されるより読みやすくなった。

[Elixir]handle_infoとreply

GenServerなんかにある handle_info/2 の使い方をど忘れしてしまったので、メモ。

自身のブログを検索すると、 [Elixir in Action]OTP/GenServerを学んで非同期/並行処理を学ぶ にすでにメモってたのですが。

以下のような簡単なコールバックを実装し、スクリプトを実行してみます。

まずはGrnServerを持つプロセスを生成します。そのあと、 callcast で定義されていないメッセージを send してあげると、ここでは handle_info/2 に拾われて処理を行います。

defmodule MyInfo do
  use GenServer

  # Callbacks

  def handle_info({:reply, msg}, state) do
    IO.inspect msg
    IO.inspect state
    {:noreply, state}
  end
  def handle_info(_msg, state) do
    {:noreply, state}
  end
end
# Start the server
{:ok, pid} = GenServer.start_link(MyInfo, ["hello"])

# send message to the process
Process.send_after pid, {:reply, "message"}, 1_000

# "message"
# ["hello"]

少し話がそれて、非同期通信の時に何らかの処理を終えた時に通知を受け取りたい場合、そういえば以下のように reply/2 を使って処理を非同期にプロセスに投げることできるのでしたね。上に貼ったリンク先を読み直してて思い出した…

def hanldle_call(....) do
  spawn(fn ->
    data = # 処理
    GenServer.reply(caller, data) # 処理が終われば、GenServerの機構でメッセージを送る
  end)

  {:noreply, do_folder} # まずは非同期的に応答する
end

handle_infoも使うと、以下の通りにも書くことができる、と。
ここの、GenServerのドキュメントにも載っているやり方です。

def handle_cast(:reply_in_one_second, from, state) do
  Process.send_after(self(), {:reply, from}, 1_000)
  {:noreply, state}
end

def handle_info({:reply, from}, state) do
  GenServer.reply(from, :one_second_has_passed)
end

[Elixir]Registerを覗く

key-value processとしてElixir1.4に入れる予定の Register というものが公開されました。

付属のベンチマークによると、以下のように高い性能が出ていることがわかります。

このベンチマークの内容は以下

https://github.com/elixir-lang/registry/blob/master/bench/shared.exs

プロセスを起動して、登録して。それを10000回登録する間の時間を計測しているみたいですね。
各ベンチマークの最後で登録した名前をチェックして、その欠損がないことを確認して終わり、と。

register/3 周りは以下

https://github.com/elixir-lang/registry/blob/master/lib/registry.ex#L535

ここら辺を見て回ると、 :ets テーブルを複数に分割(sharding)しているぽい。
同じようなことをしているものがあるのかなと調べてみると、以下のライブラリがすでに。

https://github.com/cabol/shards
https://github.com/cabol/exshards

プロセスを気軽に使えるように便利機能を拡充していく、という感じですかね。


おまけ

テストコード、繰り返しには以下のように fordescribetest を囲むことができるのですね。こう言う書き方もあるのねーという学びでした。

https://github.com/elixir-lang/registry/blob/master/test/registry_test.exs

Download precompiled package and execute library with its binary

I’d like to run http_proxy without install package management for Elixir as portable aspect.
So, I prepare simple shell script to help the problem.

It is that downloading precompiled package and unzip it, run http_proxy with the precompiled mix.

Example

https://github.com/KazuCocoa/run_http_proxy

[Elixir]read GenStage and try a bit

GenStageの0.3.0がリリースされたと合わせて、GenStageに関してのアナウンスがされたので触ってみました。合わせて、GenEventの問題点や解決したい問題がかかれているので参考になると思います。

http://elixir-lang.org/blog/2016/07/14/announcing-genstage/

GenStageとは

https://github.com/elixir-lang/gen_stage#genstage

に書いている通り、producerとconsumerの別れた役割を持つプロセスの間のイベントをやりとりするためのライブラリです。

GenEventだとイベントを1つの1つのプロセスで処理していたので、何かエラーが発生した時にsupervisorを再起動するというような戦略が取れないことだったりなど、データの流れを考える上で平行処理やその周辺に開発者が気を配らないといけない、と手間がかかっていました。そのため、開発者がデータの処理に集中できるように、そこら辺をいい感じにしてくれるものを用意するために作られたものがこれのようです。

3つの役割

GenStageは、0.3.0現在は3つの役割を持つことができます。

  1. producer
  2. consumer
  3. producer_consumer

1は、callbackの実装時に handle_demand/2 を実装する必要があります。これは、2や3から要求が来た時に行う処理を書きます。2と3は handle_events/3 を実装する必要があります。これは、イベントを得た時に行う処理を書きます。

関係性の定義

GenStage.sync_subscribe c, to: b のように書くことで、このcとbの間にはconsumer(c)とproducer(b)の関係ができます。つまり、cからbに要求が送られ、それに対して行われた要求が処理されcに対して応答として帰ってきます。ここでは sync_subscribe/3 なので、同期的な挙動を行います。一定時間応答がなかったらtimeoutに成るし、そうなるまでcはbから返答を待ちます。

他にも async_subscribe/2 も存在して、これはこの関係が非同期的に行われる、ということですね。

https://hexdocs.pm/gen_stage/Experimental.GenStage.html#async_subscribe/2
https://hexdocs.pm/gen_stage/Experimental.GenStage.html#sync_subscribe/3

これらの関係性がわかるサンプル実装が以下にあります。
https://github.com/elixir-lang/gen_stage/blob/master/examples/producer_consumer.exs

最後に

GenStageはまだ開発中で、 Experimental.GenStage.Flow の実装を控えているそうです。今はまだプロトタイプとしてのドキュメントが以下にあるだけですが、外部データの流れをうまく扱う Flow を練っているようですね。

https://hexdocs.pm/gen_stage/Experimental.GenStage.Flow.html

ここら辺は以下のような使い方に寄与するみたいです。

Developers who maintain libraries that integrate with external data sources, be it a RabbitMQ, Redis or Apacha Kafka, can explore GenStage as an abstraction for consuming data from those sources. Library developers must implement producers and leave it up for their users to plug the consumer stages.

私のお試し。
https://github.com/KazuCocoa/my_gen_stage

[Swift][Elixir]implement chat server and client

Implement Chat Server with Phoenix and chat client with iOS application.

Server

After running the server, you can open chat page, http://localhost:4000/, via browser.
The server has no DB. So, history will be deleted if someone reload browser.

Client

Only join the room and send pre-set message to the server.
Don’t support display all chat message, store message and so on.

images

sample