Screencast: Sidekiq

Sidekiq erlaubt es Prozesse im Hintergrund asynchron weiter zu verarbeiten während die Applikation bereits neue Anfragen entgegen nehmen kann. Es verwendet dabei Threads anstatt Forks und geht dadurch effizienter mit Resourcen um als vergleichsweise Resque.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

terminal

[bash]

brew install redis
redis-server /usr/local/etc/redis.conf
bundle exec sidekiq
bundle exec sidekiq -q high,5 default
[/bash]

Gemfile

[ruby]
gem ’sidekiq‘
gem ’sinatra‘, require: false
gem ’slim‘
[/ruby]

snippets_controller.rb

[ruby]
PygmentsWorker.perform_async(@snippet.id)
# PygmentsWorker.perform_in(1.hour, @snippet.id)
[/ruby]

app/workers/pygments_worker.rb

[ruby]

class PygmentsWorker
include Sidekiq::Worker
sidekiq_options queue: "high"
# sidekiq_options retry: false

def perform(snippet_id)
snippet = Snippet.find(snippet_id)
uri = URI.parse("http://pygments.appspot.com/")
request = Net::HTTP.post_form(uri, lang: snippet.language, code: snippet.plain_code)
snippet.update_attribute(:highlighted_code, request.body)
end
end
[/ruby]

routes.rb

[ruby]

require ’sidekiq/web‘
# …
mount Sidekiq::Web, at: ‚/sidekiq‘
[/ruby]

Screencast: Queue Classic

Nachdem letzte Woche PostgreSQL allgemein vorgestellt wurde, geht es diese Woche weiter mit weiteren Features für die PostgreSQL benutzt werden kann. Neben der normal Datenbank-Funktionalität kann PostgreSQL auch als Queue für die Prozess-Verarbeitung eingesetzt werden. Somit wäre es nicht nötig noch eine zusätzliche Komponente für Hintergrundprozesse zu installieren und zu verwalten. Ryan zeigt diese Woche wie dies alles mit queue_classic gelöst werden kann.

 

Downloads in verschiedenen Formaten:

mp4
m4v
webm
ogg

 

Resourcen:

config/application.rb

[ruby]
# Although not shown in the episode, it is a good idea to uncomment this line in config/application.rb
# This is because the schema we are generating here cannot be represented in Ruby.
config.active_record.schema_format = :sql
[/ruby]

terminal

[bash]
rails g migration add_queue_classic
rails g migration setup_queue_classic
rake db:migrate
rake qc:work
rails c
[/bash]

rails console

[ruby]
QC.enqueue "puts", "hello world"
QC.enqueue "puts", msg: "hello world"
QC.enqueue "puts", "msg" => "hello world"
[/ruby]

Gemfile

[ruby]
gem ‚queue_classic‘, ‚2.0.0rc12‘
[/ruby]

lib/tasks/queue_classic.rake

[ruby]
require "queue_classic"
require "queue_classic/tasks"
[/ruby]

config/initializers/queue_classic.rb

[ruby]
ENV["DATABASE_URL"] = "postgres://localhost/mailer_development"
[/ruby]

migrations/*add_queue_classic.rb

[ruby]
def up
create_table :queue_classic_jobs do |t|
t.string :q_name
t.string :method
t.text :args
t.timestamp :locked_at
end
add_index :queue_classic_jobs, :id
end

def down
drop_table :queue_classic_jobs
end
[/ruby]

migrations/*setup_queue_classic.rb

[ruby]
def up
QC::Queries.load_functions
end

def down
QC::Queries.drop_functions
end
[/ruby]

newsletters_controller.rb

[ruby]
QC.enqueue "Newsletter.deliver", params[:id]
[/ruby]

models/newsletter.rb

[ruby]
def self.deliver(id)
newsletter = find(id)
# raise "Oops"
sleep 10 # simulate long newsletter delivery
newsletter.update_attribute(:delivered_at, Time.zone.now)
end
[/ruby]

Screencast: Resque

Resque ist ein Redis-Backend Bibliothek in Ruby um Hintergrundprozesse zu erstellen, diese Prozesse in mehrere Queues zu stellen und später zu verarbeiten. Ryan zeigt in seinem dieswöchigen Screencast wie es in Rails genutzt werden kann

 

Downloads in verschiedenen Formaten:

source code
mp4
m4v
webm
ogv

 

Resourcen:

bash

[bash]
brew install redis
redis-server /usr/local/etc/redis.conf
resque-web
rake resque:work QUEUE=’*‘
[/bash]

Gemfile

[ruby]
gem ‚resque‘, :require => "resque/server"
[/ruby]

lib/tasks/resque.rake

[ruby]
Resque::Server.use(Rack::Auth::Basic) do |user, password|
password == "secret"
end
[/ruby]

snippets_controller.rb

[ruby]
Resque.enqueue(SnippetHighlighter, @snippet.id)
[/ruby]

app/workers/snippet_highlighter.rb

[ruby]
class SnippetHighlighter
@queue = :snippets_queue
def self.perform(snippet_id)
snippet = Snippet.find(snippet_id)
uri = URI.parse(‚http://pygments.appspot.com/‘)
request = Net::HTTP.post_form(uri, {‚lang‘ => snippet.language, ‚code‘ => snippet.plain_code})
snippet.update_attribute(:highlighted_code, request.body)
end
end
[/ruby]

config/routes.rb

[ruby]
mount Resque::Server, :at => "/resque"
[/ruby]

config/initializers/resque_auth.rb

[ruby]
Resque::Server.use(Rack::Auth::Basic) do |user, password|
password == "secret"
end
[/ruby]

Screencast: Beanstalkd und Stalker

Beanstalkd ist ein einfacher, schneller und verteilt arbeitender Dienst zum Aufbau von Message Queues. Stalker ist ein Wrapper Interface um entsprechende Jobs in die Message Queue zu senden.

 

Download:

Download(13.6 MB, 9:16)
Alternativer Download für iPod & Apple TV(13.6 MB, 9:16)

 

Resourcen:

 

Quellcode:

[bash]
beanstalkd -d
killall beanstalkd
beanstalkd -d -b …
stalk ./config/jobs.rb
[/bash]

[ruby]
# Gemfile
gem ’stalker‘

# config/jobs.rb with Rails
require File.expand_path("../environment", __FILE__)

job "city.fetch_name" do |args|
City.find(args["id"]).fetch_name
end

# cities_controller.rb
Stalker.enqueue("city.fetch_name", :id => @city.id)

# config/jobs.rb without Rails
require "sqlite3"
require "json"
require "net/http"

RAILS_ENV = ENV["RAILS_ENV"] || "development"

db = SQLite3::Database.new(File.expand_path("../../db/#{RAILS_ENV}.sqlite3", __FILE__))

job "city.fetch_name" do |args|
zip = db.get_first_value("select zip_code from cities where id=?", args["id"])
url = "http://ws.geonames.org/postalCodeLookupJSON?postalcode=#{zip}&country=US"
json = Net::HTTP.get_response(URI.parse(url)).body
name = JSON.parse(json)["postalcodes"].first["placeName"]
db.execute("update cities set name=? where id=?", name, args["id"])
end

error do |exception|
# …
end

# config/god.rb
# run with: god -c config/god.rb
RAILS_ROOT = File.expand_path("../..", __FILE__)

God.watch do |w|
w.name = "anycity-worker"
w.interval = 30.seconds
w.env = {"RAILS_ENV" => "production"}
w.start = "/usr/bin/stalk #{RAILS_ROOT}/config/jobs.rb"
w.log = "#{RAILS_ROOT}/log/stalker.log"

w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
end
end

w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.above = 50.megabytes
c.times = [3, 5] # 3 out of 5 intervals
end

restart.condition(:cpu_usage) do |c|
c.above = 50.percent
c.times = 5
end
end

w.lifecycle do |on|
on.condition(:flapping) do |c|
c.to_state = [:start, :restart]
c.times = 5
c.within = 5.minute
c.transition = :unmonitored
c.retry_in = 10.minutes
c.retry_times = 5
c.retry_within = 2.hours
end
end
end
[/ruby]