Was dieses Tutorial abdeckt
- Jobs zu einem Batch gruppieren und einen Success-Callback registrieren.
- Warum der Callback in einer eigenen Klasse steht und nicht in einem Block.
- Kontext an einen Callback übergeben, der auf einer anderen Maschine läuft.
Voraussetzungen
Batches sind eine Funktion von Sidekiq Pro. Das Open-Source-Gem
sidekiq-batch implementiert dieselbe API, was nützlich ist, um das Muster auszuprobieren. Für den Produktiveinsatz ist Sidekiq Pro die besser unterstützte Option.Jobs in reinem Sidekiq schreiben
Batches sind eine Sidekiq-Funktion, keine von Active Job. Jobs, die Teil eines Batches sind, sollten Sidekiq direkt verwenden. Dann schiebt sich die eigene Kapselung von Active Job nicht zwischen den Batch und seine Jobs. Einen Job umzustellen ist eine Änderung in zwei Zeilen. Binden SieSidekiq::Job ein, statt von ApplicationJob zu erben, und reihen Sie mit perform_async statt mit perform_later ein.
Sidekiq::Job ist der aktuelle Name. Älterer Code und ältere Screencasts verwenden Sidekiq::Worker, das weiterhin als Alias funktioniert.Den Batch erstellen
Erstellen Sie den Batch dort, wo die Arbeit ausgelöst wird, und reihen Sie die Jobs dann innerhalb vonbatch.jobs ein:
on(:complete) ist der andere Callback, den Sie registrieren können. Er wird ausgelöst, wenn jeder Job beendet ist, unabhängig davon, ob alle erfolgreich waren. Verwenden Sie :success, wenn der nächste Schritt davon abhängt, dass die Arbeit erfolgreich war.
Den Callback als Klasse schreiben
Der Callback ist eine Klasse, kein Block. Wenn ein Batch abgeschlossen ist, existiert der Prozess, der ihn erstellt hat, längst nicht mehr. Der Callback läuft als eigener Sidekiq-Job, möglicherweise auf einer anderen Maschine, Minuten später. Keine Anfrage, keine lokale Variable und keine Modellinstanz sind noch im Gültigkeitsbereich. Ein Block würde Zustand einschließen, den es nicht mehr gibt. Deshalb instanziiert Sidekiq Ihre Callback-Klasse neu und übergibt ihr den Batch-Status sowie den Options-Hash, den Sie registriert haben:Batches miteinander verketten
Ein Callback kann einen weiteren Batch erstellen. Durch dieses Verketten bauen Sie einen Workflow mit mehr als zwei Stufen auf. Erstellen Sie die Server. Konfigurieren Sie sie im Callback als neuen Batch. Markieren Sie in diesem Callback den Cluster als aktiv.Batches mit AppSignal überwachen
AppSignal instrumentiert Sidekiq über seine Sidekiq-Integration und meldet Jobs im Namespacebackground.
Batches ändern, worauf es zu achten lohnt:
- Der Callback ist der Job, der zählt. Ein Batch ist nur nützlich, wenn der Callback läuft. Lassen Sie sich von der Fehlererfassung informieren, wenn er eine Exception auslöst. Ein Callback, der stillschweigend fehlschlägt, hinterlässt einen halb fertigen Workflow, während die vorherigen Jobs alle Erfolg melden. Er läuft als Sidekiq-Job, daher instrumentiert AppSignal ihn automatisch. Fügen Sie Instrumentierungs-Events hinzu, um zu sehen, wofür seine Zeit verwendet wird.
- Ein einziger Fehler stoppt den Batch. Bei einem
on(:success)-Callback bedeutet ein einziger fehlgeschlagener Job, dass der Callback nie läuft. Der Fehler wird als Issue auftauchen; der fehlende Callback taucht nirgendwo auf, es sei denn, Sie suchen gezielt danach. - Lange Workflows verdienen ein Check-in. Mehrstufige Batches, die nach einem Zeitplan abgeschlossen sein müssen, eignen sich gut für Check-ins. Ein Check-in meldet den Lauf, der nicht stattgefunden hat, statt den, der fehlgeschlagen ist.
- Jobs mit dem Batch taggen. Fügen Sie die Batch- oder Workflow-ID als Tag hinzu. Wenn Sie dann herausfinden, welche Stufe hängen geblieben ist, können Sie alle Jobs eines Laufs zusammen abrufen. AppSignal speichert die Argumente jedes Jobs als Parameter.
Transkript
Aus dem Video transkribiert und leicht bearbeitet. Die automatischen Untertitel haben einige Produkt- und API-Namen falsch verstanden, diese wurden korrigiert.Transkript lesen
Transkript lesen
0:02 Hallo zusammen! In dieser Folge geht es um den Bau von fortgeschrittenen Background-Workern mit Sidekiq-Batches. Das ist richtig cool, weil man damit eine Reihe von laufenden Background-Jobs zusammenfassen kann. Wenn sie fertig sind, ruft man einen Callback auf und geht so von serieller Ausführung zu parallel und wieder zurück zu seriell. Normalerweise geht man bei Background-Jobs von Rails, das seriell läuft, zu parallel über, und dann ist man fertig.0:33 Aber das ist wichtig für komplexe Workflows, denn wenn man zum Beispiel etwas wie Hatchbox baut, muss man bei komplexen Dingen im Hinterkopf behalten, dass manches, was man im Hintergrund erledigt, wie das Erstellen und Konfigurieren von Servern, manchmal warten muss, bis ein Block Arbeit erledigt ist. Bei einem Server-Cluster hat man zum Beispiel vielleicht einen Load Balancer, der an eine Reihe von Webservern verteilt. Und in diesem Fall wollen wir einen Webserver hinzufügen. Wir hätten also einen Load Balancer und zwei Webserver, und dieser eine fungiert außerdem als unser Cron- und Background-Worker sowie als Datenbankserver. Aber man kann sich vorstellen, dass jedes ähnliche Setup ähnliche Probleme hat.1:18 Das Problem dabei ist, wenn man die Arbeit im Backend erledigt. Wenn man das absendet, wissen wir, dass ein Webserver hinzugefügt wurde, also müssen wir diesen neuen Server bei DigitalOcean erstellen. Also können wir diesen Job losschicken, um das zu erledigen. Und wir wissen, dass wir den Load Balancer aktualisieren und mit der IP-Adresse dieses neuen Webservers neu konfigurieren müssen. Wenn wir aber vielleicht mehrere davon hinzufügen wollen, könnten wir das nicht so einfach machen.1:45 Der Grund dafür ist: Wenn wir diese zwei Webserver bei DigitalOcean erstellen, können sie eine zufällige Zeitspanne brauchen, um erstellt zu werden. Und wir können den Load Balancer nicht sofort konfigurieren. Wir könnten nicht einfach sagen: Okay, konfiguriere alle Maschinen, erstelle die neuen Maschinen, denn dieser Load Balancer muss warten, bis die neuen Webserver erstellt sind und wir IP-Adressen für sie haben. Wir können ihre IP-Adressen nicht in den Load Balancer eintragen, wenn wir sie nicht haben. Und das ist unser Problem.2:16 Wir müssen all diese Server in einem Batch erstellen und warten, bis alle fertig sind, und dann können wir alle Maschinen konfigurieren. So haben wir alle nötigen Informationen, um die Konfiguration durchzuführen. Genau dafür kommen Sidekiq-Batches ins Spiel. Jetzt sprechen wir über Sidekiq-Batches. Das ist eine Pro-Funktion von Sidekiq.2:35 Das kostet also Geld, aber es lohnt sich definitiv und bringt einige großartige weitere Funktionen mit, die für so ziemlich jede Produktionsanwendung erforderlich sind, die fortgeschrittene Background-Worker wie diesen einsetzt. Man kann aber auch eine Open-Source-Version von Sidekiq-Batches verwenden, die dieselbe API bietet. Ich zeige Ihnen die, damit Sie dieses Repo klonen und selbst ausprobieren können, aber für die Produktion sollten Sie wahrscheinlich Sidekiq Pro verwenden. Batches sind wirklich cool. Man schreibt im Grunde eine kleine Konfiguration wie diese und erstellt einen neuen Batch, legt bei Bedarf eine Beschreibung fest, aber vor allem kann man einen Callback erstellen.3:16 Callbacks sehen für Sie vielleicht etwas merkwürdig aus, aber der Grund, warum sie in einer anderen Klasse definiert werden, ist, dass das alles in Background-Workern läuft, die auf unterschiedlichen Maschinen laufen könnten, und man keinen Zugriff mehr auf den Ort hat, an dem das ursprünglich ausgeführt wurde. Wenn der Callback also erfolgreich aufgerufen wird, hat man diese ursprüngliche Rails-Anfrage oder Modellinstanz nicht mehr. Das könnte auf einer ganz anderen Maschine laufen. Deshalb müssen Sie eine neue Klasseninstanz dafür erstellen. Und dann verwenden Sie im Grunde nur diesen Jobs-Block, um alle Ihre neuen Worker zu erstellen, und das war’s im Wesentlichen.3:59 Ihre Jobs laufen dann in diesem Batch, und danach wird diese Callback-Klasse instanziiert, wie auch immer Sie sie definiert haben. Dabei werden zusätzliche Optionen übergeben, die Sie hinzufügen möchten. Aber das ist im Grunde alles. Schauen wir uns ein Beispiel an. Wir werden dieses Konzept an einem Beispiel durchgehen, damit Sie es besser verstehen.4:20 Ich habe hier eine brandneue Rails-Anwendung, zu der ich mit dem Jumpstart-Template ein paar Gems hinzugefügt habe. Vor allem fügen wir Sidekiq Batch hinzu. Sie können entweder Sidekiq Pro oder Sidekiq Batch verwenden. Mit diesem können Sie das Repo klonen und es sich ansehen. Das verwenden wir also.4:38 Dann müssen wir nur ein paar Jobs erstellen, oder zumindest eine Stelle, die den Batch erstellt. Ich habe das in einem Job selbst gemacht. Ich habe also einen Job, der einen Batch erstellt und diesen ausführt. Aber Sie könnten das auch in Ihren Models, Ihren Controllern, Ihren einfachen Ruby-Objekten machen, überall dort, wo Sie den Batch erstellen möchten. Der ganze Code läuft natürlich in Sidekiq.4:58 Der ganze Worker-Kram läuft also dort. Erstellen wir also schnell einen Job. Sagen wir, wir bearbeiten app/jobs/create_server_job.rb. Unser CreateServerJob hat also die Methode
perform. Und wir müssen hier Sidekiq Worker einbinden.5:19 Und der Grund, warum wir das statt Active Job verwenden wollen, ist, dass man bei Sidekiq-Batches sicherstellen möchte, dass man bei Sidekiq selbst bleibt. Man möchte nicht, dass irgendein Active-Job-Kram dazwischenfunkt, und es funktioniert viel, viel besser, wenn man nur mit Sidekiq arbeitet. Sie müssen also vielleicht einige Ihrer Jobs in reines Sidekiq umwandeln, aber das ist wirklich einfach. Das Einzige, was Sie wirklich ändern müssen, ist diese Zeile hier: nicht von Active Job erben und perform_async statt perform_later mit Active Job verwenden. Das war’s im Wesentlichen.5:55 Und hier soll etwas Arbeit erledigt werden. Sie soll also parallel laufen. Das war’s im Grunde. Sie müssen hier nichts allzu Ausgefallenes machen. Und dort, wo Sie diese Worker auslösen möchten, erstellen Sie den Job- beziehungsweise Batch-Code.6:13 Erstellen wir also einen weiteren Job namens CreateClusterJob. class CreateClusterJob, perform. Und hier wollen wir unseren Batch erstellen. Wir schreiben also batch = Sidekiq::Batch.new, batch.description = "Creating cluster". Und dann sagen wir auch batch.on :success.6:36 Wir wollen eine Art Callback aufrufen. Sie können hier also einen Klassennamen angeben. Sie können, zumindest bei Sidekiq Batch, hier auch einen String angeben, und er wird ebenfalls konstantiert. Wenn wir also einfach eine Klasse namens Created hier hätten, class Created, könnten wir das tun. Wir müssten sie natürlich mit einem Namespace versehen.6:58 CreateClusterJob::Created. So haben wir ganz einfach Zugriff darauf. Wir können das auch einfach als Klasse machen. Und dann können Sie optional einen Options-Hash übergeben. Wenn Sie also die Cluster-ID übergeben müssten, könnten Sie das ebenfalls tun.7:18 Sie könnten also so etwas machen, wo Sie die Cluster-ID übergeben. Wir haben kein Cluster-Model. Also nehme ich hier einfach 999. So haben Sie ein Beispiel zum Anschauen. Und dann sagen wir batch.jobs do.7:28 Und hier müssen wir unsere anderen Jobs in die Warteschlange einreihen. Machen wir es also einfach: Wir sagen 5.times. Das machen wir hier. Wir nehmen die Zahl dort.7:41 CreateServerJob.perform_async und übergeben i. Das war’s dann auch schon. So wird sichergestellt, dass diese hinzugefügt werden. Und sobald Sie das tun, werden die Jobs eingereiht und beginnen zu laufen.8:02 Und dann müssen Sie in Ihrer Callback-Klasse einfach on_success schreiben. Optional können Sie auch ein def on_complete machen, wenn Sie möchten. Es gibt eine Nuance oder einen Unterschied zwischen beiden. Ich habe immer on_success verwendet. Das nehmen wir also hier.8:20 Beide nehmen einen Status und Optionen entgegen. Sie können also den Status und die Optionen ausgeben. Die Optionen sollten genau der Hash sein, den Sie übergeben haben. Und der Status ist dann der Sidekiq-Status. Setzen wir hier also einen Trenner und schreiben “created cluster”.8:40 Punkt. So sollten wir das sehen, sobald diese Server-Jobs fertig sind. Das ist also die Arbeit, die Sie parallel erledigen möchten. Schlafen wir also einfach eine zufällige Zeit zwischen 1 und 10 Sekunden. Und dann geben wir “creating server …” aus.8:59 Und wir können hier die ID angeben, die wir übergeben haben. Und danach: “created”. Nur damit wir in unseren Logs genau die passenden Server-Zeilen sehen. So können wir sie zählen und sicherstellen, dass alles korrekt ist. Denn das hier sollten wir nur einmal sehen.9:26 Das hier sollten wir so oft sehen, wie wir es aufrufen. In diesem Fall also 5-mal, 10-mal, wenn Sie es auf 10 ändern, was auch immer. Wir haben jetzt also diesen Job, der im Grunde eine Reihe anderer auslöst. Und dieser Code wird ausgeführt, sobald alles fertig ist, nur ein einziges Mal.9:47 Und er läuft ebenfalls innerhalb von Sidekiq. Das ist also noch etwas, das man im Hinterkopf behalten sollte. Deshalb wird diese Klasse instanziiert: weil sie auf welchem Server auch immer innerhalb von Sidekiq läuft. Sie hat also keinen Zugriff auf irgendwelche Instanzvariablen oder anderen lokalen Kram. Denn das wird eine brandneue Instanz dieser Created-Klasse sein, wenn sie läuft.10:07 Deshalb müssen Sie in der Lage sein, diese Optionen zu übergeben, um zum Beispiel Ihre Cluster-ID zu erreichen, wenn das fertig ist, um herauszufinden, welcher Cluster als aktiv markiert werden muss. Damit können wir zur Rails-Konsole gehen und das ausprobieren. Starten wir Sidekiq. Es läuft jetzt, und wir sagen CreateClusterJob.new.perform. Wenn alles richtig gelaufen ist, sollten wir sehen, dass fünf Jobs eingereiht wurden.10:34 Das ist die Idee dieser Jobs. Sidekiq, und hier können wir sehen, wie sie laufen. Wir haben also Server null bis vier, also fünf davon, und Sie sehen, dass sie laufen, in welcher Reihenfolge auch immer Sidekiq sie zuerst verarbeitet. Sie sehen, dass drei vor einigen der anderen fertig war, und das alles ist erfolgreich abgeschlossen.10:56 Wir sehen also, dass fünf Jobs gestartet wurden und fünf Jobs abgeschlossen wurden. Und dann, ganz am Ende, wurde ein neuer Sidekiq-Batch-Callback-Worker gestartet, den das Gem für uns implementiert hat, der das als Job auslöst, und der läuft dann genau dieses eine Mal. Das ist cool, denn jetzt können wir von einer einzelnen laufenden Sache zu mehreren übergehen und dann wieder zurück zu einer einzelnen Sache. Und das ist wirklich großartig, weil es uns ermöglicht, das auch über unseren Sidekiq-Cluster verteilt zu tun. Das macht man häufig mit Threading, wo man eine einzelne Maschine hat, eine Reihe von Threads startet, etwas parallele Arbeit erledigt und sich dann wieder zusammenschließt und wartet, bis diese Threads fertig sind, um dann wieder seriell weiterzumachen.11:43 Aber mit Sidekiq können wir das verteilt über unsere Sidekiq-Worker-Server erledigen. Das ist wirklich cool und erlaubt uns, auf diese Weise viel mehr zu erledigen, weil das jetzt über mehrere Maschinen skaliert werden kann, was fantastisch ist. Sidekiq Pro ist also die Stelle, wo Sie das bekommen, oder verwenden Sie das Gem. Ich würde auf jeden Fall Sidekiq Pro empfehlen. Der Support wird besser sein.12:08 Es wird wahrscheinlich das alles effizienter oder besser implementieren. Und es wird sich mit der Zeit definitiv weiterentwickeln. Diese Funktion ist also definitiv eine Art Voraussetzung, wenn man anfängt, fortgeschrittenere Background-Jobs zu bauen. Sie werden das wahrscheinlich für bestimmte Situationen brauchen, weil Sie einen Workflow haben, den Ihr Code ausführen muss. Und das hilft Ihnen, diese Workflows zu bauen.12:29 Zum Beispiel könnte Ihr Created-Callback tatsächlich einen weiteren Batch starten und einen weiteren auslösen. Das ist also ziemlich interessant. So können Sie diese Batches miteinander verketten lassen. Und das mache ich in Hatchbox. Es ist also ziemlich schön zu sehen, wie das alles funktioniert und welche komplexen Dinge man damit machen kann.12:49 Das ist also wirklich cool. Und das ist natürlich eine komplexe Funktion, die für viele Anwendungen erforderlich ist. Ich hoffe also, dass Ihnen diese Folge gefallen hat. Wenn Sie mehr über fortgeschrittene Background-Worker oder Sidekiq-Sachen sehen möchten, schreiben Sie mir das gerne in die Kommentare unten. Dann sprechen wir uns in der nächsten Folge.13:05 Peace.