+ All Categories
Home > Technology > The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Date post: 05-Dec-2014
Category:
Upload: karel-minarik
View: 4,475 times
Download: 1 times
Share this document with a friend
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)
39
The Code of Forking Paths Karel Minařík
Transcript
Page 1: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking PathsKarel Minařík

Page 2: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 3: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)
Page 4: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

“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.”

Page 5: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

http://en.wikipedia.org/wiki/The_Garden_of_Forking_Paths

Page 6: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

HTTP/1.1  503  Service  UnavailableHTTP/1.1  201  Created

Parallel presenceTHE CODE OF FORKING PATHS

Page 7: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

THE CODE OF FORKING PATHS

Ataxo Social Insider

Page 8: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Asynchronous Task Processing1

Page 9: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Long running requests

Canonical Example: video upload and conversion

Asynchronous Task ProcessingTHE CODE OF FORKING PATHS

Page 10: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Request Response

Request Response

WORKLOAD

WORKLOAD

NOTIFICATION

Page 11: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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?

Page 12: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 13: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)
Page 14: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)
Page 15: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 16: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 17: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 18: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 19: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

https://github.com/karmi/resque-demo

Demo

Page 21: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

„Messaging”2

Page 22: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 23: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Maintainability (changing features)

Extensibility (adding or removing features)

Testability (validating features)

Three Overlooked Features of A Software SystemMESSAGING

Page 24: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 25: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Message Queue

Page 26: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Workers

Page 27: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

AMQPMESSAGING

Alvaro Videla and Jason J.W. Williams, RabbitMQ in Actionp. 16

Page 28: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Alvaro Videla and Jason J.W. Williams, RabbitMQ in Actionp. 30

Exchanges, Queues and BindingsAMQP

Page 29: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

The Code of Forking Paths

Page 30: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 31: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)
Page 32: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Thumbs up!!!

Page 33: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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');

Page 34: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Ry Dahl, Node.js (2009)http://nodejs.org

Page 36: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 37: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 38: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

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

Page 39: The Code Of The Forking Paths (Asynchronous Processing with Resque and AMQP)

Thanks!d


Recommended