我見過Elixir GenServer的幾個例子,但他們主要處理數組值(例如購物車)或計數器增量。因此他們演示瞭如何處理簡單的數據類型。如何在Phoenix/Elixir Genserver中傳遞模型
我想知道如何在更新某些模型記錄時在Phoenix應用程序中傳遞狀態。
示例我可以提供的是:
- 步驟1:我接收AWS SNS通知(包含數據的溶液中加入什麼新S3對象)=>只是存儲消息來建模
Notification
- 步驟2:我解析
Notification
中的消息以讀取s3對象filename
。那麼這個存儲新Document
模型 - 第三步:我取回S3對象(例如ORIGINAL_NAME)的元數據,並存儲
從紅寶石即將on Rails的我會做到這一點,因爲這:
- 控制器創建
Notification
然後第二步驟時間表後臺作業(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調用:
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
現在,這裏是我的問題:
- 我改變Genserver的狀態(最初是
{Notification, id}
,那麼它的{Document, id}
。對我來說,就像Genserver一直期待的那種類型一樣?所以也許我應該總是返回`{Notification,id}並從關聯中拉出Document?或者這是好的,因爲它是? - 如果我用`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是異步的,所以它不是一個問題.'這是我擔心的事情,如果一個異步可以投另一個異步和teoretically投出另一個異步,如果我改變任何那些GenServer的價值主管會確保正確的執行順序,從「{Notification,123}」到「{Document,234}」的步驟? ......聽起來,任何'handle_cast'方法都應該被調用/包含一次,並且在那個執行gen server中只應該使用'handle_info'。 (感覺對我來說'handle_cast - > handle_info - > handle_info'類似於公共方法,調用一堆私有方法) – equivalent8
...並感謝您的建議,真的很有幫助。我可以看到我看錯了:)我將不得不再次訪問GenServer上的章節。 – equivalent8