View
318
Download
0
Category
Preview:
Citation preview
Mongo à la ResqueNicolas Fouché
http:// .com http://about.me/nfo
Say “rescue”
or “resquioux” in French
Resque
One man:
Resque
One language:
Resque
One dependency:
Redis
Remote Dictionary Server
“memcached on steroids”
Initial release was March 2009
Redis
Redis is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.
http://redis.io
Redis
In RAM
Latency: 10ns VS 1ms = 1,000,000ms
≃ 5000 Gets/s
≃ 5000 Sets/s
Redis
Virtual memory
keys in memory
values as needed in memory
replication
Redis
well written ANSI C
and clients in all languages
Redis
keep in mind the complexity of each operation
Resque
parent / child fork process
Resque
handles Unix signals
=> god / monit / bluepill friendly
Resque
Sinatra web UI, known as resque-web
Queues
Priority:
$ QUEUES=high,low rake resque:work
Queues
Consume all queues:
$ QUEUES=* rake resque:work
Enqueue jobs
Resque.enqueue(Archive, @repo.id, branch)
Workers
class Archive @queue = :file_serve def self.perform(repo_id, branch = nil) repo = Repository.find(repo_id) repo.create_archive(branch || "master") end end
Persistence
Jobs are stored as JSON
{ "class": "Archive", "args": [ 44, "masterbrew" ] }
Failure backends
redis (for resque-web)
hoptoad
and others (like exceptional)
Don’t like Ruby ?
Alternate implementations
https://github.com/defunkt/resque/wiki/alternate-implementations
resque-mongo
Translating queriesatomic operations
$set - set a particular value
$unset - set a particular value
$inc - increment a particular value by a certain amount
$push - append a value to an array
$pushAll - append several values to an array
$pull - remove a value(s) from an existing array
$pullAll - remove several value(s) from an existing array
$bit - bitwis
Translating queriesPush a job
redis.sadd(:queues, queue)redis.rpush("queue:#{queue}", encode(item))
mongo << {:queue => queue, :item => item, :date => Time.now}mongo_queues.update( {:queue => queue }, {'$inc' => {:count => 1}})
Translating queries
Pop a job
redis.lpop("queue:#{queue}")
doc = mongo.find_and_modify( :query => {:queue => queue}, :sort => [[:date, 1]], :remove => true) mongo_queues.update( {:queue => queue }, {'$inc' => {:count => -1}})
Translating queries
queue size
redis.llen("queue:#{queue}").to_i mongo_queues.find_one(:queue => queue)['count']
Translating queriesPeek a job
list_range("queue:#{queue}", start, count)
start, count = [start, count].map { |n| Integer(n) } res = mongo.find(:queue => queue).sort([:date, 1]).skip(start).limit(count).to_a res.collect! { |doc| doc['item'] } count == 1 ? res.first : res
Translating queries
Remove queue
redis.srem(:queues, queue) redis.del("queue:#{queue}")
mongo.remove({:queue => queue}) mongo_queues.remove({:queue => queue})
Mongo to the rescue ?
Sometimes you just know MongoDB better than Redis
Most of query features of Redis can be translated in Mongo queries
But for Redis addicts, MongoDB has some secrets
Used to MongoDB ?
Used to MongoDB ?[lol@cats ~]# bin/mongo MongoDB shell version: 1.6.4 connecting to: test > show dbs admin local monque > use monque switched to db monque > db.getCollectionNames(); [ "delayed_queue", "failures", "job_groups", "monque", "queues", "schedules", "schedules_changed", "stats", "system.indexes", "workers" ] > db.workers.count(); 40 > db.workers.findOne(); { "_id" : ObjectId("4c863c6c89cb535954000001"), "started" : "Tue Sep 07 2010 13:21:48 GMT+0000 (UTC)", "worker" : "myserver:22868:facebook*" }
Used to MongoDB ?require 'rubygems' require 'mongo' include Mongo db = Connection.new.db('sample-db') coll = db.collection('test') coll.remove 3.times do |i| coll.insert({'a' => i+1}) end puts "There are #{coll.count()} records. Here they are:"coll.find().each { |doc| puts doc.inspect }
Really used to MongoDB ?
New features
Go take a look in this JSON !
Search failed jobs
What’s happening right now ?
Use the mongo console !
Listen on queues by prefix
Queues prefix:
$ QUEUES=email*,analytics* rake resque:work
Plugins
resque-mongo-groups
resque-mongo-scheduler
resque-mongo-groups
by Catalin Bordianu, aka @omikronn
resque-mongo-groups
Resque.enqueue( EatBreakfast, :with => ['eggs', 'bacon'], :group_id => 'meals:' + Time.now.utc.strftime('%Y%m%d') )
resque-mongo-groups
class EatBreakfast extend Resque::Plugins::Groups::TrackedJob end
resque-mongo-groups
def self.perform # ... self.class.atomic_op_on_complete = { '$inc' => { 'eggs' => 1, 'bacon' => 1 } } # ... end
resque-mongo-groups
Resque.group_stats("meals:20110316") { '_id' => 'meals:20110316', 'total' => 4, 'delayed' => 2, 'completed' => 3, 'failed' => 1, 'exceptions' => ["#<TooMuchEggs: beware !>"] 'custom' => {:eggs => 12, :bacon => 1, :potatoes => 3} }
resque-mongo-groups
gem "resque-mongo-groups"
resque-mongo-scheduler
Resque.enqueue_at( 1.hour.from_now, Eat, :what => 'leftovers' )
resque-mongo-scheduler
breakfast: cron: "0 8 * * *" class: Eat args: "bacon" description: Breakfast
gem "resque-mongo-scheduler", :require => "resque-scheduler"
resque-mongo-scheduler
resque-mongo ⚡ resque
You cannot use resque and resque-mongo in the same project
resque-mongo ♥ resque
migration to resque-mongo => free
resque-mongo ♥ resqueStill have to migrate from
to
resque-mongo ♥ resque
easy to merge the last changes from resque to resque-mongo
easy to port existing plugins
Get the gem !
gem install nfo-resque-mongo
The maintainer still did not answer to my ownership requests :(
and use it with Bundler
gem "nfo-resque-mongo", :require => "resque"
Help needed !Add exclusive features to resque-web
Migrate existing plugins
Create new plugins
Promote the gem
Or simply use the gem, you ‘ll surely send pull requests
That’s all folks
Credits for Flickr images: acezebragirl4j, kiwitime, fulbert05, josh_exell, benheine, tudacee
Recommended