2011-01-17 2 views
8

Eine der Verantwortlichkeiten meiner Rails-Anwendung ist das Erstellen und Servieren von signierten Xmls. Jedes signierte XML wird nach der Erstellung niemals geändert. Also speichere ich jedes xml im Ordner public und leite den Client entsprechend um, um unnötige Verarbeitung vom Controller zu vermeiden.Serving dynamische Zip-Dateien durch Apache

Jetzt möchte ich eine neue Funktion: Jede XML ist mit einem Datum verbunden, und ich möchte die Fähigkeit implementieren, eine komprimierte Datei mit jedem XML, dessen Datum in einem vom Client angegebenen Zeitraum liegt, zu liefern. Dennoch kann der Zeitraum nicht auf weniger als einen Monat begrenzt werden, damit das Feature nützlich ist, und das bedeutet, dass einige gezippte ZIP-Dateien bis zu 50 Millionen betragen.

Meine Anwendung wird als Passagiermodul von Apache bereitgestellt. Daher ist es völlig inakzeptabel, die Datei mit send_data zu bedienen, da der Client warten muss, bis die gesamte komprimierte Datei generiert wurde, bevor der eigentliche Download beginnt. Obwohl ich eine Idee habe, wie man das Feature in Rails implementiert, so dass die komprimierte Datei produziert während geliefert wird, fühle ich, mein Server wird knapp auf Ressourcen, wenn einige lange Ruby/Passenger Prozesse zugewiesen sind, große Zip-Dateien dienen.

Ich habe über a better solution gelesen, um statische Dateien über Apache, aber nicht dynamische zu dienen.

Also, was ist die Lösung für das Problem? Benötige ich etwas wie einen benutzerdefinierten Apache-Handler? Wie informiere ich Apache über meine Anwendung, wie man mit der Anfrage umgeht, die Dateien komprimiert und das Ergebnis gleichzeitig streamt?

+0

Der ZIP-Dateiformat Index am Ende der Datei ist. Ich habe auch schnell durch RFC 2616 (HTTP 1.1) geschaut und die Antwort mit variabler Länge funktioniert wahrscheinlich, obwohl normalerweise die Inhaltslänge angekündigt werden sollte. Technisch sollte das soweit möglich sein. – erloewe

+0

Es gibt kein HTTP-Problem, wenn die Länge nicht im Voraus bekannt ist. Dafür ist die chunked Transfer-Codierung zuständig. Sie können Bytes schreiben, die wie eine Zip-Datei in einer beliebigen Sprache aussehen. Achten Sie darauf, die Ausgabe regelmäßig zu leeren. – covener

Antwort

3

Check out my mod_zip Modul für Nginx:

http://wiki.nginx.org/NgxZip

Sie können ein Backend-Skript Nginx sagen, im Archiv, das URL-Adressen enthalten, und Nginx wird dynamisch eine ZIP-Datei auf dem Client-Stream enthält diese Dateien. Das Modul nutzt Nginx's Single-Thread-Proxy-Code und ist extrem leicht.

Das Modul wurde erstmals 2008 veröffentlicht und ist an diesem Punkt ziemlich ausgereift. Von Ihrer Beschreibung denke ich, dass es Ihren Bedürfnissen entspricht.

0

Sie müssen einfach die API verwenden, die Ihnen zur Verfügung steht, um eine ZIP-Datei zu erstellen und sie in die Antwort zu schreiben, wobei die Ausgabe periodisch gelöscht wird. Wenn dies große ZIP-Dateien bereitstellt oder häufig angefordert wird, sollten Sie erwägen, es in einem separaten Prozess mit einem hohen Nice/ionice-Wert/niedriger Priorität auszuführen.

Im schlimmsten Fall können Sie eine Befehlszeilen-Zip in einem Prozess mit niedriger Priorität ausführen und die Ausgabe in regelmäßigen Abständen weitergeben.

0

es ist schwierig zu tun, aber ich habe ein Juwel namens Zipline (http://github.com/fringd/zipline) gemacht, die Dinge für mich funktioniert. Ich möchte es aktualisieren, so dass es einfache Dateigriffe oder -pfade unterstützen kann, im Moment geht es davon aus, dass Sie carrierwave verwenden ...

auch, können Sie wahrscheinlich nicht die Antwort mit Beifahrer streamen ... musste ich Verwenden Sie Unicorn, um das Streamen richtig zu machen ... und eine bestimmte Rack-Middleware kann das sogar vermasseln (Calling Response).to_s bricht es)

wenn jemand noch das mich auf der GitHub Seite muss die Mühe