Upload
karel-minarik
View
4.474
Download
1
Embed Size (px)
DESCRIPTION
Slides for a lecture on task queues, asynchronous processing, messaging and architecture at University of Economics in Prague. Video available online: http://multimedia.vse.cz/media/Viewer/?peid=51c06c512f4645289c4e9c749dc85acc1d (Silverlight, so Windows only)
Citation preview
The Code of Forking PathsKarel Minařík
The Code of Forking Paths
Karel Minařík
→ Independent web designer and developer
→ Ruby, Rails, Git and CouchDB propagandista in .cz
→ Previously: Flash Developer; Art Director; Information Architect;… (see LinkedIn)
→ @karmiq at Twitter
→ karmi.cz
“He believed in an infinite series of times, in a growing, dizzying net of divergent, convergent and parallel times. (...) We do not exist in the majority of these times; in some you exist, and not I; in others I, and not you; in others, both of us. In the present one, which a favorable fate has granted me, you have arrived at my house; in another, while crossing the garden, you found me dead; in still another, I utter these same words, but I am a mistake, a ghost.”
The Code of Forking Paths
http://en.wikipedia.org/wiki/The_Garden_of_Forking_Paths
The Code of Forking Paths
HTTP/1.1 503 Service UnavailableHTTP/1.1 201 Created
Parallel presenceTHE CODE OF FORKING PATHS
The Code of Forking Paths
THE CODE OF FORKING PATHS
Ataxo Social Insider
The Code of Forking Paths
Asynchronous Task Processing1
The Code of Forking Paths
Long running requests
Canonical Example: video upload and conversion
Asynchronous Task ProcessingTHE CODE OF FORKING PATHS
The Code of Forking Paths
Request Response
Request Response
WORKLOAD
WORKLOAD
NOTIFICATION
The Code of Forking Paths
„Engineering“ solutionTHE CODE OF FORKING PATHS
class UploadController < ApplicationController
def create # .... Thread.new do # *** WORK REALLY HARD <HERE> *** end render :text => "KTHXBAI!" end
end
What could possibly go wrong?
The Code of Forking Paths
The Task QueueTHE CODE OF FORKING PATHS
class UploadController < ApplicationController
def create # Store uploaded file, store record put_the_video_on_the_processing_queue(@video.id) render :text => "Thanks! Your video is being processed." end
end
The Code of Forking Paths
How Does It Work?REDIS
RPUSH
LPOPO(1)
https://github.com/defunkt/resque/blob/v1.13.0/lib/resque.rb#L133-138
}Millions of items
http://redis.io/commands#list
The Code of Forking Paths
Poor-man’s QueuesTASK QUEUES
/usr/local/bin/redis-‐cli RPUSH "queue" "task-‐01"
while true; do /usr/local/bin/redis-‐cli BLPOP "queue" 0; done
„Publisher”
„Worker”
1
2
The Code of Forking Paths
/usr/local/bin/redis-‐cli RPUSH "queue" "task-‐01"
while true; do /usr/local/bin/redis-‐cli BLPOP "queue" 0 /usr/local/bin/redis-‐cli PUBLISH "queue:messages" "Processed task."done
„Publisher”
„Worker”
1
2
/usr/local/bin/redis-‐cli SUBSCRIBE "queue:messages"
„Monitor”3
Demo
Poor-man’s QueuesTASK QUEUES
require "redis"require "nest"
module Ost VERSION = "0.0.1" TIMEOUT = ENV["OST_TIMEOUT"] || 2
class Queue attr :ns
def initialize(name) @ns = Nest.new(:ost)[name] end
def push(value) redis.lpush(ns, value) end
def each(&block) loop do _, item = redis.brpop(ns, TIMEOUT) next if item.nil? or item.empty?
begin block.call(item) rescue Exception => e error = "#{Time.now} #{ns[item]} => #{e.inspect}"
redis.rpush ns[:errors], error redis.publish ns[:errors], error end end end
def errors redis.lrange ns[:errors], 0, -1 end
alias << push alias pop each
private
def redis Ost.redis end end
@queues = Hash.new do |hash, key| hash[key] = Queue.new(key) end
def self.[](queue) @queues[queue] end
def self.connect(options = {}) @redis = Redis.connect(options) end
def self.redis @redis ||= Redis.connect end
def self.redis=(redis) @redis = redis endend
https://github.com/soveran/ost
https://github.com/karmi/resque-demo
Demo
http://git.karmi.cz/resque_job_polling_demo.git
Demo
The Code of Forking Paths
„Messaging”2
The Code of Forking Paths
I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea.
e big idea is "messaging" (...).
e key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.
— Alan Kay, prototypes vs classes was: Re: Sun's HotSpot
http://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html
„Object Oriented Programming”MESSAGING
The Code of Forking Paths
Maintainability (changing features)
Extensibility (adding or removing features)
Testability (validating features)
Three Overlooked Features of A Software SystemMESSAGING
The Code of Forking Paths
When you place your order the cashier marks a coffee cup with your order and places it into the queue. e queue is quite literally a queue of coffee cups lined up on top of the espresso machine. is queue decouples cashier and barista and allows the cashier to keep taking orders even if the barista is backed up for a moment.
— Gregor Hohpe, Starbucks Does Not Use Two-Phase Commit
http://www.eaipatterns.com/ramblings/18_starbucks.html
Asynchronous Task Processing in A Real WorldMESSAGING
Message Queue
Workers
The Code of Forking Paths
AMQPMESSAGING
Alvaro Videla and Jason J.W. Williams, RabbitMQ in Actionp. 16
The Code of Forking Paths
Alvaro Videla and Jason J.W. Williams, RabbitMQ in Actionp. 30
Exchanges, Queues and BindingsAMQP
The Code of Forking Paths
The Code of Forking Paths
Publishers and ConsumersAMQP
exchange = MQ.topic('log')exchange.publish( {:level => level, :time => Time.now, :body => message}.to_json,
:key => "log.#{level}" )
MQ.queue("all logs").bind( MQ.topic('log'), :key => "log.*" ).subscribe do |header, message| ...end
MQ.queue("error logs").bind( MQ.topic('log'), :key => "log.error" ).subscribe do |message| ...end
Publisher
Consumer (all logs)
1
2
Consumer (error logs)3
Message
Routing Key
Thumbs up!!!
The Code of Forking Paths
Evented ProgrammingASYNCHRONOUS WORLD
$.get('/data', function(data) {
$('.result').html(data);
alert('Loaded data from the server.');
});
var mydata = $.get('/data');
http://s3.amazonaws.com/four.livejournal/20091117/jsconf.pdf
The Code of Forking Paths
module BalancingProxy # ... module Callbacks
def on_select lambda do |backend| puts "Selected backend: #{backend.url}" backend.increment_counter if Backend.strategy == :balanced end end
def on_connect lambda do |backend| puts "Connected" end end
def on_data lambda do |data| puts "Receiving data" data end end
def on_response lambda do |backend, resp| puts "Handling response" resp end end
def on_finish lambda do |backend| puts "Finished" backend.decrement_counter if Backend.strategy == :balanced end end
end
end
https://github.com/igrigorik/em-proxy/blob/master/examples/balancing.rb
module Server # ... Backend.select do |backend| conn.server backend, :host => backend.host, :port => backend.port
conn.on_connect &Callbacks.on_connect conn.on_data &Callbacks.on_data conn.on_response &Callbacks.on_response conn.on_finish &Callbacks.on_finish end end
The Code of Forking Paths
ResumeTHE CODE OF FORKING PATHS
➡ Long-running Tasks
➡ Task Queues (Redis, Resque)
➡ Maintainability, Extensibility, Testability
➡ “Monadic” Architecture (of loosely coupled parts)
➡ Messaging: AMQP, Publisher/Consumer, Routing
The Code of Forking Paths
Watch OnlineTHE CODE OF FORKING PATHS
Watch this lecture online (in Czech):http://multimedia.vse.cz/media/Viewer/?peid=51c06c512f4645289c4e9c749dc85acc1d
Thanks!d