Elixir GenServerの例をいくつか見てきましたが、主に値の配列(ショッピングカートなど)やカウンタの増分を扱っています。したがって、単純なデータ型の処理方法を示します。Phoenix/Elixir Genserverでモデルを渡す方法
特定のModelレコードを更新しているとき、どのようにPhoenixアプリケーションで状態を渡すことができますか?
Iを提供することができる例はこれです:
- STEP1:私は(新しいS3オブジェクトが追加されたどのようなデータを含む)AWS SNS通知を受信=>だけ
Notification
- STEP2をモデル化するためのメッセージを格納しますI
Notification
内のメッセージを解析して、s3オブジェクトfilename
を読み取ります。 :私はこのようにそれを行うだろうS3オブジェクト(例えばoriginal_name)のメタデータを取得し、Railsのにルビーから来る
それを格納します。そして、新しいDocument
モデル
- コントローラ
Notification
次いで - 第2工程のためのバックグラウンドジョブ(Sidekiq)をスケジュールするバックグラウンドジョブは、メタデータPullDocumentMetadata.perform_later(「文書」、document.idを引っ張ってドキュメントとスケジュール別のジョブを作成し、作成し)
例:
class NotificationController
def create
# ...
notification = Notification.create(body: message_body)
ProcessNotification.perform_later("Notification", notification.id)
# ...
end
end
class ProcessNotification
# ...
def process(resource_class, resource_id)
notification = resource_class.constantize.find(resource_id)
document = Document.new(filename: parse_filename(notification.body))
document.save
PullMetadata.perform_later("Document", document.id)
end
# ...
end
class PullMetadata
# ...
def process(resource_class, resource_id)
document = resource_class.constantize.find(resource_id)
document.original_name = fetch_original_name(document.filename)
document.save
end
# ...
end
は今、私はにしようとしていた段階コールによってGenserver(ステップを使用してフェニックスと同様のものを複製する)
(作成Notification
はフェニックスで行われる最初のステップコントローラと私は2つのgenserver呼び出しに他の2つの手順を分離したい:
defmodule NotificationController do
# ...
def create(conn, params) do
notification = # ... store body to %{}Notification
# ...
pid = GenServer.start_link(ProcessNotification, {Notification, notification.id})
GenServer.cast(pid, :process_to_document)
end
end
defmodule ProcessNotification do
def handle_cast(:process_to_document, {Notification, notification_id}) do
notification = Repo.get(Notification, notification_id)
filename = not_important_how_i_parse_body(notification)
doc = %{}Document |> Document.changeset(%{filename: filename}) |> Repo.insert!
{:noreply, {Document, document.id}}
end
def handle_cast(:pull_metadata, {Document, document_id}) do
document = Repo.get(Document, document_id)
original_name = not_important_how_i_pull_the_metadata(document)
doc = %{}Document |> Document.changeset(%{original_name: original_name}) |> Repo.update!
{:noreply, {Document, document.id}}
end
end
今ここには私の質問です:
- 私はそれが
{Document, id}
だ、最初はそれが{Notification, id}
た(Genserverの状態を変更しています。 Genserverがいつも同じタイプを期待しているような気がしますか?だから、いつも `{Notification、id}を返さなければならないし、関連からドキュメントを引っ張るべきでしょうか?それともこれは大丈夫ですか? - `pid = GenServer.start_link(ProcessNotification、notification)でGenServerを初期化すると、GenserverはStructの状態を保持できます。オブジェクトをマーシャリングするか、この反物質ですか?
- 実際にキャストからキャストするにはどうすればいいですか。
process_to_document
からキャストするとpull_metadata
となります。それとも私はこのようなコントローラでは、これらのスケジュールを設定する必要があります
例:
defmodule NotificationController do
# ...
def create(conn, params) do
notification = # ... store body to %{}Notification
# ...
pid = GenServer.start_link(ProcessNotification, {Notification, notification.id})
GenServer.cast(pid, :process_to_document)
GenServer.cast(pid, :pull_metadata)
end
end
私が間違っている私がやっているかなり確信しているが、私はこれは良いはずどのように任意のアイデアを感謝しています。
Re: 'しかし、GenServer.castは非同期なので問題ありません。これは、非同期で別の非同期をキャストして、別の非同期をキャストできるかどうか心配していることです。 '{Notification、123}'から '{Document、234} 'までのステップは、監督者が正しい実行順序を保証するか?どのような 'handle_cast'メソッドも一度だけ呼び出されるべきであると私に聞きます。そしてその実行の中でgenサーバは' handle_info'を使うべきです。 (それは私に 'handle_cast - > handle_info - > handle_info'と同じように感じます。公開メソッドと同様に、プライベートメソッドの束を呼び出す) – equivalent8
...アドバイスありがとう、本当に役立ちます。私はそれが間違っているのを見ていることがわかります:)私はGenServerの章をもう一度見直さなければなりません。 – equivalent8