Frage Rails-Hintergrundbild-Upload verursacht Anwendungs-Timeout


Leider wurde das Kopfgeld für eine Antwort, die dieses Problem nicht löst, für diejenigen mit ähnlichen Problemen vergeben.

Ich habe ein Formular mit einem Bild hochladen (Heroku zu s3). Wenn ich das Formular absende, wartet mein Rails-Server auf den Hintergrundjob, der das Bild hochlädt, um das Bild fertigzustellen, bevor eine Antwort an den Benutzer zurückgegeben wird. Dies führt bei jedem Hochladen eines Bildes zu einem Anwendungs-Timeout.

Aktuelle Reihenfolge der Ereignisse:

  1. Der Benutzer reicht das Formular ein
  2. Server empfängt Formular
  3. Wenn ein Bild vorhanden ist, startet der Server einen Hintergrundjob
  4. Wenn ein Hintergrundjob gestartet wurde, wartet der Server darauf, dass er beendet wird (Schienen mal hier raus)
  5. Wenn es gestartet wird, wird der Hintergrundjob abgeschlossen
  6. Der Server verarbeitet die Anfrage
  7. Der Server antwortet dem Benutzer

Gewünschte Reihenfolge der Ereignisse:

  1. Der Benutzer reicht das Formular ein
  2. Server empfängt Formular
  3. Server verarbeitet Nichtbildfelder
  4. Wenn ein Bild vorhanden ist, startet der Server einen Hintergrundjob
  5. Der Server antwortet dem Benutzer
  6. Der Hintergrundjob ist abgeschlossen und der Server verarbeitet das hochgeladene Bild (URL wird gespeichert)

Uploader-Code

class PhotoUploader < CarrierWave::Uploader::Base
  include ::CarrierWave::Backgrounder::Delay
  include CarrierWave::MimeTypes
  process :set_content_type
  storage :fog
end

Carrierwave :: Backgrounder-Initialisierer

CarrierWave::Backgrounder.configure do |c|
  c.backend :sidekiq, queue: :carrierwave
end

Benutzermodell

class User < ActiveRecord::Base
  mount_uploader :photo, PhotoUploader, delayed: true
  process_in_background :photo
end

Es gibt keinen Controller-Code, da das Formular von ActiveAdmin bearbeitet wird. Ich kann überschreiben, wo immer es nötig ist, aber ich habe nicht herausgefunden, was geändert werden muss.

Was muss ich ändern, um die richtige Reihenfolge der Ereignisse zu erhalten?


5
2017-11-07 02:05


Ursprung


Antworten:


Das grundlegende Problem hierbei ist, dass Heroku strenge Beschränkungen dafür hat, wie lange eine Anfrage blockieren darf, ohne Daten an den Client zu senden. Wenn Sie dieses Limit (30 Sekunden für das erste Byte) erreicht haben, wird Ihre Anfrage von Heroku ausgesetzt. Bei Datei-Uploads ist es sehr wahrscheinlich, dass Sie dieses Limit erreichen.

Der beste Ansatz besteht darin, dass der Browser des Benutzers die Datei zuerst direkt auf S3 hochlädt. Hier gibt es einige Diskussionen, die relevant sind: Direkte Uploads zu S3 mit Carrierwave

Wenn Sie etwas wie das jQuery File Upload plugin verwenden (https://github.com/blueimp/jQuery-File-Upload), würde der Fluss etwas wie sein:

  • Der Benutzer fügt dem Formular eine oder mehrere Dateien hinzu, bevor er auf "Senden" klickt.
  • Die Dateien werden direkt in S3 hochgeladen und ein Datei-Upload-Token wird für jede Datei zu Ihrem Formular hinzugefügt.
  • Der Benutzer übermittelt das Formular mit den Token der hochgeladenen Dateien und nicht mit dem Inhalt der Dateien.
  • Der Server kann die Dateien basierend auf dem übergebenen Token in S3 nach Hause verschieben.

Auf diese Weise kann sich Ihr Webserver darauf konzentrieren, nur die Anfrage zu bedienen und nicht das Hochladen von Dateien zu blockieren, was sehr lange dauern kann.

Dies erfordert ein wenig mehr Arbeit aufgrund von Herokus Limits - aber letztendlich denke ich, ist dies die einzige Möglichkeit, die Timeout-Grenzen zu umgehen.

Außerdem empfehle ich Ihnen, einen Upload-S3-Bucket zu erstellen und dann eine S3-Lebenszyklusrichtlinie festzulegen, um Dateien zu löschen, die älter als ein Intervall sind. Wenn Sie direkte Datei-Uploads durchführen, werden einige Uploads normalerweise nicht verarbeitet, weil der Benutzer aufgibt usw., so dass der Lebenszyklus diese Dateien bereinigt.


6
2017-11-18 18:55