Ich habe mehrere Beispiele von Elixir GenServer gesehen, aber sie beschäftigen sich hauptsächlich mit Array von Werten (z. B. Einkaufswagen) oder Zählerinkremente. Daher zeigen sie, wie man mit einfachen Datentypen umgeht.Wie man das Modell in Phoenix/Elixir Genserver übergibt
Ich frage mich, wie ich in einer Phoenix-Anwendung Status übergeben kann, wenn ich bestimmte Model-Datensätze aktualisiere.
Das Beispiel, das ich zur Verfügung stellen kann, ist dies:
- Schritt 1: Ich erhalte AWS SNS-Benachrichtigung (Daten enthält, welche neues s3 Objekt wurde hinzugefügt) => speichert nur die Nachricht
Notification
- step2 zu modellieren: I parse die Nachricht innerhalb
Notification
, um s3 Objektfilename
zu lesen. Dann speichern Sie diese neueDocument
Modell - step3: Ich habe die Metadaten des s3 Objekt holen (zB original_name) und speichern Sie es
Von Ruby on Rails Ich würde es als dies tun:
- -Controller erzeugt
Notification
dann Zeitplan Hintergrundjob (Sidekiq) für den 2. Schritt - Hintergrund Job schafft Dokument und plant einen anderen Job Metadaten PullDocumentMetadata.perform_later zu ziehen ("Dokument", document.id )
Beispiel:
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
Nun war ich zu versuchen, etwas Ähnliches replizieren mit Phoenix mit Genserver (Schritt für Schritt Anruf)
Der erste Schritt (Erstellen Notification
wird von Phoenix getan Controller und ich möchte andere zwei Schritte zu 2 Genserver Anrufe isolieren:
hier sind nun meine Fragen:
- ich den Zustand der Genserver bin zu ändern (zunächst war es
{Notification, id}
, dann ist es{Document, id}
. Es fühlt sich für mich so an, als würde der Genserver die ganze Zeit vielleicht den gleichen Typ erwarten? Also sollte ich immer die `{Notification, id} zurückgeben und das Dokument aus einer Assoziation ziehen? Oder ist das ok, wie es ist? - Wie gut würde Genserver den Zustand eines Struct halten, wenn ich GenServer mit 'pid = GenServer.start_link (ProcessNotification, notification) init ... würde also Marshal das Objekt, oder ist das Antimaterie?
- Wie kann ich tatsächlich aus einem Guss, so aus
process_to_document
würde ichpull_metadata
werfen. Oder soll ich diese in der Steuerung wie folgt planen:
Beispiel:
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
Ich bin mir ziemlich sicher, was ich falsch mache, also schätze ich eine Ahnung, wie dies sollte besser sein.
Re: 'Aber GenServer.cast ist async, so ist es kein Problem.' das ist die Sache, die ich besorgt bin, wenn ein Async kann ein anderes async und teoretical werfen, die ein anderes async, Wenn ich den Wert von GenServer in einer von denen ändern Schritte von '{Notification, 123}' nach '{Document, 234}' stellt der Supervisor die korrekte Ausführungsreihenfolge sicher? ... Es klingt für mich, dass jede 'handle_cast'-Methode nur einmal aufgerufen werden sollte, und innerhalb dieser Ausführung sollte gen server nur' handle_info' verwenden. (Es fühlt sich für mich 'handle_cast -> handle_info -> handle_info' Ähnlich wie öffentliche Methode, Aufruf von privaten Methoden) – equivalent8
... und vielen Dank für den Rat, wirklich hilfreich. Ich kann sehen, dass ich es falsch sehe :) Ich werde die Kapitel über GenServer noch einmal besuchen müssen. – equivalent8