Alles was länger dauert, z.B. Trackbacks zu verschicken, sollte eine Webanwendung besser im Hintergrund ausführen. Sinatra hat dafür aber keinen Mechanismus parat. Ruby kann zwar Threads starten, aber ein Thread in einem Webserverthread könnte am Ende der Anfrage abgewürgt werden. Beim von mir genutzten Webserver puma würde genau das passieren.
Es gibt natürlich Lösungen, Delayed::Job zum Beispiel. Aber das kommuniziert über die Datenbank, braucht seine eigene Tabelle, und sah sehr Rails-lastig aus. Sucker Punch klang erst perfekt, weil es innerhalb des Sinatra-Prozesses läuft. Aber es braucht angepasste Worker-Objekte, und die Objektstruktur wollte ich nicht anpassen.
Meine einfache Lösung basiert auf der Idee eines Worker-Threads im Sinatra-Prozess. Nur dass statt eines einzelnen Threads ein Threadpool aus dem Gem ruby-thread bereitgehalten wird, dem der Code übergeben werden kann. Das funktioniert so:
require 'sinatra/base'
require 'thread/pool'
class Threadexample < Sinatra::Application
class << self; attr_accessor :pool end # thread pool as class variable
@pool = Thread.pool(2)
get '/'
DoingSomething.new()
end
end
class DoingSomething
def initialize()
Threadexample::pool.process { # send the normal code to the threadpool
puts "send trackback now in the background, while the pageload is already finished"
}
end
end
Der Threadpool läuft dauerhaft im Sinatra-Prozess, beim modularen Stil gespeichert als Klassenvariable. Der Code im von Sinatra aufgerufenen Objekt wird an den Pool gesendet. Das schöne an der Lösung ist, dass der Code und die Objektstruktur nicht verändert werden müssen. Und dass die Threads im Pool nacheinander bearbeitet werden, bestehende Threads werden nicht einfach überschrieben.
onli blogging am : Ruby und mehrere Kerne
Vorschau anzeigen