resque-pubsub 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ## 0.1.0 (2011-03-14)
2
+
3
+ * Initial version.
4
+
5
+ ## 0.1.1 (2011-03-14)
6
+
7
+ * Bump because of a publishing error.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,82 @@
1
+ ResquePubsub
2
+ ============
3
+
4
+ A [Resque][rq] plugin. Requires Resque 1.9.10.
5
+
6
+ A lightweight publish/subscribe messaging system, with message persistence when clients are down, written on top of Redis and Resque.
7
+
8
+
9
+ Usage / Examples
10
+ ================
11
+
12
+ A simple class that can publish a message:
13
+
14
+ class TestPublisher
15
+ require 'resque-pubsub'
16
+
17
+ def some_method
18
+ self.publish(topic, message)
19
+ end
20
+ end
21
+
22
+
23
+ A simple class that subscribes to messages on a particular topic:
24
+
25
+ class TestSubscriber
26
+ require 'resque-pubsub'
27
+
28
+ subscribe 'test_topic'
29
+
30
+ def self.read_test_topic_message(message)
31
+ # Do something with the message
32
+ end
33
+ end
34
+
35
+
36
+ Customize & Extend
37
+ ==================
38
+
39
+ The method that the is called when the subscriber is sent a message defaults to read_<topic_name>_message,
40
+ but can be customized with the option :reader_method, e.g.,
41
+
42
+ subscribe 'test_topic', :reader_message => :custom_message_method
43
+
44
+ The namespace that pubsub uses in Resque defaults to 'resque:pubsub' but can be configured by setting the constant
45
+ Resque::Plugins::Pubsub::Exchange::PUBSUB_NAMESPACE.
46
+
47
+
48
+ Install
49
+ =======
50
+
51
+ ### As a gem
52
+
53
+ $ gem install resque-pubsub
54
+
55
+ ### In a Rails app, as a plugin
56
+
57
+ $ rails plugin install git://github.com/Mechaferret/resque-pubsub.git
58
+
59
+
60
+ Running Resque
61
+ ==============
62
+
63
+ A sample config file is provided in examples/resque-pubsub.rb. If you put this in config/initializers for a Rails app,
64
+ then Resque will default to the app namespace but will take an override on namespace from the environment variable RESQUE_NAMESPACE. Thus
65
+
66
+ QUEUE=* RESQUE_NAMESPACE="resque:pubsub" rake environment resque:work
67
+
68
+ will run resque jobs against the default pubsub namespace (i.e., will be the pubsub server)
69
+
70
+ while
71
+
72
+ QUEUE=* rake environment resque:work
73
+
74
+ will run resque in an app as normal.
75
+
76
+
77
+ Acknowledgements
78
+ ================
79
+
80
+ Copyright (c) 2011 Monica McArthur, released under the MIT license.
81
+
82
+ [rq]: http://github.com/defunkt/resque
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the resque_pubsub plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the resque_pubsub plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'ResquePubsub'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,6 @@
1
+ require 'resque/plugins/pubsub/subscriber'
2
+ require 'resque/plugins/pubsub/publisher'
3
+ require 'resque/plugins/pubsub/broker'
4
+ self.send(:include, Resque::Plugins::Pubsub::Subscriber)
5
+ self.send(:include, Resque::Plugins::Pubsub::Publisher)
6
+
@@ -0,0 +1,31 @@
1
+ module Resque
2
+ module Plugins
3
+ #
4
+ # pubsub broker
5
+ #
6
+ module Pubsub
7
+ class Broker
8
+ @queue = :messages
9
+ # Returns a top-level Redis connection so that the broker can distribute messages
10
+ # across namespaces. If none has been created, will
11
+ # create a new one using information from the Resque connection.
12
+ def self.redis
13
+ return @redis if @redis
14
+ client_to_copy = Resque.redis.client
15
+ @redis = Redis.new(:host => client_to_copy.host, :port => client_to_copy.port,
16
+ :thread_safe => true, :db => client_to_copy.db)
17
+ end
18
+
19
+ def self.perform(topic, message)
20
+ subscribers = Exchange.redis.smembers("#{topic}_subscribers")
21
+ subscribers.each {|s|
22
+ sinfo = JSON.parse(s)
23
+ puts "distributing to #{sinfo.inspect}"
24
+ Broker.redis.sadd("#{sinfo['namespace']}:queues", "fanout:#{topic}")
25
+ Broker.redis.rpush("#{sinfo['namespace']}:queue:fanout:#{topic}", {:class=> sinfo["class"], :args=>[message]}.to_json)
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ require 'resque'
2
+ module Resque
3
+ module Plugins
4
+ #
5
+ # pubsub exchange manager
6
+ #
7
+ module Pubsub
8
+ class Exchange
9
+ @@pubsub_namespace = nil
10
+ # Returns the current Redis connection. If none has been created, will
11
+ # create a new one using information from the Resque connection and our config.
12
+ def self.redis
13
+ return @redis if @redis
14
+ client_to_copy = Resque.redis.client
15
+ redis_new = Redis.new(:host => client_to_copy.host, :port => client_to_copy.port,
16
+ :thread_safe => true, :db => client_to_copy.db)
17
+ puts "making a redis in exchange, namespace will be #{@@pubsub_namespace}"
18
+ @redis = Redis::Namespace.new(@@pubsub_namespace || "resque:pubsub", :redis => redis_new)
19
+ end
20
+
21
+ @queue = :subscription_requests
22
+
23
+ def self.perform(subscription_info)
24
+ puts "handling a subscription on the exchange"
25
+ puts "requested subscription is #{subscription_info.inspect}"
26
+ puts "namespace is #{Exchange.redis.namespace}"
27
+ redis = Exchange.redis
28
+ redis.sadd("#{subscription_info["topic"]}_subscribers", {:class=>subscription_info["class"], :namespace=>subscription_info["namespace"]}.to_json)
29
+ end
30
+
31
+ def self.pubsub_namespace
32
+ @@pubsub_namespace
33
+ end
34
+
35
+ def self.pubsub_namespace=(n)
36
+ @@pubsub_namespace = n
37
+ @redis.client.disconnect
38
+ @redis = nil
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ require 'resque/plugins/pubsub/exchange'
2
+ module Resque
3
+ module Plugins
4
+ #
5
+ # pubsub publisher
6
+ #
7
+ module Pubsub
8
+ module Publisher
9
+ def self.included(base)
10
+ puts 'including publisher'
11
+ base.send(:include, InstanceMethods)
12
+ end
13
+
14
+ module InstanceMethods
15
+ def publish(topic, message)
16
+ puts "Publisher publishing #{message} in #{topic}"
17
+ Exchange.redis.sadd(:queues, "messages")
18
+ Exchange.redis.rpush("queue:messages", {:class=>'Resque::Plugins::Pubsub::Broker', :args=>[topic, message]}.to_json)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ require 'resque/plugins/pubsub/exchange'
2
+ module Resque
3
+ module Plugins
4
+ #
5
+ # pubsub subscriber
6
+ #
7
+ module Pubsub
8
+ module Subscriber
9
+ def self.included(base)
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ module ClassMethods
14
+ def subscribe(topic, options={})
15
+ @queue = "fanout:#{topic}"
16
+ reader_method = options[:reader_method] || "read_#{topic}_message"
17
+ module_eval <<-"end_eval"
18
+ def self.perform(message)
19
+ self.send("#{reader_method}", message)
20
+ end
21
+ end_eval
22
+ options[:namespace] = Resque.redis.namespace
23
+ options[:topic] = topic
24
+ options[:class] = self.to_s
25
+ puts "Subscriber subscribing with #{options.inspect}"
26
+ Exchange.redis.sadd(:queues, :subscription_requests)
27
+ Exchange.redis.rpush("queue:subscription_requests", {:class=>'Resque::Plugins::Pubsub::Exchange', :args=>[options]}.to_json)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # Logfile created on Thu Jan 20 18:20:02 -0800 2011 by logger.rb/22285
2
+ SQL (0.2ms) SET SQL_AUTO_IS_NULL=0
3
+ SQL (0.3ms) SHOW TABLES
4
+ SQL (430.6ms) CREATE TABLE `transactionals` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `name` varchar(255), `description` varchar(255), `other_id` int(11)) ENGINE=InnoDB
5
+ SQL (0.4ms) SHOW TABLES
6
+ SQL (114.4ms) CREATE TABLE `transactional_facts` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `name` varchar(255), `description` varchar(255), `other_id` int(11)) ENGINE=InnoDB
7
+ SQL (0.4ms) SHOW TABLES
8
+ SQL (102.1ms) CREATE TABLE `schema_migrations` (`version` varchar(255) NOT NULL) ENGINE=InnoDB
9
+ SQL (172.5ms) CREATE UNIQUE INDEX `unique_schema_migrations` ON `schema_migrations` (`version`)
10
+ SQL (0.4ms) SHOW TABLES
11
+ SQL (0.1ms) SELECT version FROM `schema_migrations`
12
+ SQL (0.4ms) INSERT INTO `schema_migrations` (version) VALUES ('3')
13
+ Transactional Columns (38.0ms) SHOW FIELDS FROM `transactionals`
14
+ SQL (0.3ms) BEGIN
15
+ Transactional Create (0.3ms) INSERT INTO `transactionals` (`name`, `other_id`, `description`) VALUES(NULL, NULL, NULL)
16
+ SQL (0.7ms) COMMIT
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class PubsubTest < Test::Unit::TestCase
4
+ def setup
5
+ $success = $lock_failed = $lock_expired = 0
6
+ Resque.redis.flushall
7
+ Resque.redis.namespace = 'test_pubsub'
8
+ end
9
+
10
+ def test_lint
11
+ assert_nothing_raised do
12
+ Resque::Plugin.lint(Resque::Plugins::Pubsub)
13
+ end
14
+ end
15
+
16
+ def test_all
17
+ # Just loading the "TestSubscriber" class is enough to subscribe
18
+ require 'test_publisher'
19
+ require 'test_subscriber'
20
+ # Now process the subscription
21
+ Resque.redis.namespace = 'resque:pubsub'
22
+ @worker = Resque::Worker.new(:subscription_requests)
23
+ @worker.process
24
+ # Check that the subscription is in the subscribers list
25
+ assert check_subscription(Resque.redis.smembers("test_topic_subscribers"), "TestSubscriber", "test_pubsub")
26
+ p = TestPublisher.new
27
+ p.publish("test_topic", "Test message")
28
+ # Run Resque for the broker
29
+ Resque.redis.namespace = 'resque:pubsub'
30
+ @worker = Resque::Worker.new(:messages)
31
+ @worker.process
32
+ # Check that the message queue has been populated
33
+ Resque.redis.namespace = 'test_pubsub'
34
+ assert Resque.redis.keys.include?('queue:fanout:test_topic')
35
+ assert Resque.redis.llen('queue:fanout:test_topic')==1
36
+ # Now run the subscriber Resque
37
+ @worker = Resque::Worker.new('fanout:test_topic')
38
+ @worker.process
39
+ assert Resque.redis.llen('fanout:test_topic')==0
40
+ assert TestSubscriber.last_message=='Test message'
41
+ end
42
+
43
+ def test_configuration_options
44
+ # Configure the pubsub namespace
45
+ require 'resque-pubsub'
46
+ Resque::Plugins::Pubsub::Exchange.pubsub_namespace = 'resque:custom_space'
47
+ puts "namespace is set to #{Resque::Plugins::Pubsub::Exchange.pubsub_namespace}"
48
+ require 'test_publisher'
49
+ require 'test_subscriber'
50
+ require 'test_subscriber_custom'
51
+ # Now process the subscription
52
+ Resque.redis.namespace = 'resque:custom_space'
53
+ @worker = Resque::Worker.new(:subscription_requests)
54
+ @worker.process
55
+ # Check that the subscription is in the subscribers list
56
+ assert check_subscription(Resque.redis.smembers("test_custom_topic_subscribers"), "TestSubscriberCustom", "test_pubsub")
57
+ p = TestPublisher.new
58
+ p.publish("test_custom_topic", "Test custom message")
59
+ # Run Resque for the broker
60
+ Resque.redis.namespace = 'resque:custom_space'
61
+ @worker = Resque::Worker.new(:messages)
62
+ @worker.process
63
+ # Check that the message queue has been populated
64
+ Resque.redis.namespace = 'test_pubsub'
65
+ assert Resque.redis.keys.include?('queue:fanout:test_custom_topic')
66
+ assert Resque.redis.llen('queue:fanout:test_custom_topic')==1
67
+ # Now run the subscriber Resque
68
+ @worker = Resque::Worker.new('fanout:test_custom_topic')
69
+ @worker.process
70
+ assert Resque.redis.llen('fanout:test_custom_topic')==0
71
+ assert TestSubscriberCustom.last_message=='Test custom message'
72
+ # Also make sure TestSubscriber DIDN'T get the message
73
+ assert TestSubscriber.last_message!='Test custom message'
74
+ end
75
+
76
+ def check_subscription(subscribers, klass, namespace)
77
+ subscribers.inject(false) {|result, s|
78
+ sinfo = JSON.parse(s)
79
+ result = result || (sinfo["class"]==klass && sinfo['namespace']==namespace)
80
+ }
81
+ end
82
+
83
+ end
@@ -0,0 +1,132 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./test/redis-test.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 9736
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds (0 to disable)
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # The filename where to dump the DB
38
+ dbfilename dump.rdb
39
+
40
+ # For default save/load DB in/from the working directory
41
+ # Note that you must specify a directory not a file name.
42
+ dir ./test/
43
+
44
+ # Set server verbosity to 'debug'
45
+ # it can be one of:
46
+ # debug (a lot of information, useful for development/testing)
47
+ # notice (moderately verbose, what you want in production probably)
48
+ # warning (only very important / critical messages are logged)
49
+ loglevel debug
50
+
51
+ # Specify the log file name. Also 'stdout' can be used to force
52
+ # the demon to log on the standard output. Note that if you use standard
53
+ # output for logging but daemonize, logs will be sent to /dev/null
54
+ logfile stdout
55
+
56
+ # Set the number of databases. The default database is DB 0, you can select
57
+ # a different one on a per-connection basis using SELECT <dbid> where
58
+ # dbid is a number between 0 and 'databases'-1
59
+ databases 16
60
+
61
+ ################################# REPLICATION #################################
62
+
63
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
64
+ # another Redis server. Note that the configuration is local to the slave
65
+ # so for example it is possible to configure the slave to save the DB with a
66
+ # different interval, or to listen to another port, and so on.
67
+
68
+ # slaveof <masterip> <masterport>
69
+
70
+ ################################## SECURITY ###################################
71
+
72
+ # Require clients to issue AUTH <PASSWORD> before processing any other
73
+ # commands. This might be useful in environments in which you do not trust
74
+ # others with access to the host running redis-server.
75
+ #
76
+ # This should stay commented out for backward compatibility and because most
77
+ # people do not need auth (e.g. they run their own servers).
78
+
79
+ # requirepass foobared
80
+
81
+ ################################### LIMITS ####################################
82
+
83
+ # Set the max number of connected clients at the same time. By default there
84
+ # is no limit, and it's up to the number of file descriptors the Redis process
85
+ # is able to open. The special value '0' means no limts.
86
+ # Once the limit is reached Redis will close all the new connections sending
87
+ # an error 'max number of clients reached'.
88
+
89
+ # maxclients 128
90
+
91
+ # Don't use more memory than the specified amount of bytes.
92
+ # When the memory limit is reached Redis will try to remove keys with an
93
+ # EXPIRE set. It will try to start freeing keys that are going to expire
94
+ # in little time and preserve keys with a longer time to live.
95
+ # Redis will also try to remove objects from free lists if possible.
96
+ #
97
+ # If all this fails, Redis will start to reply with errors to commands
98
+ # that will use more memory, like SET, LPUSH, and so on, and will continue
99
+ # to reply to most read-only commands like GET.
100
+ #
101
+ # WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
102
+ # 'state' server or cache, not as a real DB. When Redis is used as a real
103
+ # database the memory usage will grow over the weeks, it will be obvious if
104
+ # it is going to use too much memory in the long run, and you'll have the time
105
+ # to upgrade. With maxmemory after the limit is reached you'll start to get
106
+ # errors for write operations, and this may even lead to DB inconsistency.
107
+
108
+ # maxmemory <bytes>
109
+
110
+ ############################### ADVANCED CONFIG ###############################
111
+
112
+ # Glue small output buffers together in order to send small replies in a
113
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
114
+ # in terms of number of queries per second. Use 'yes' if unsure.
115
+ glueoutputbuf yes
116
+
117
+ # Use object sharing. Can save a lot of memory if you have many common
118
+ # string in your dataset, but performs lookups against the shared objects
119
+ # pool so it uses more CPU and can be a bit slower. Usually it's a good
120
+ # idea.
121
+ #
122
+ # When object sharing is enabled (shareobjects yes) you can use
123
+ # shareobjectspoolsize to control the size of the pool used in order to try
124
+ # object sharing. A bigger pool size will lead to better sharing capabilities.
125
+ # In general you want this value to be at least the double of the number of
126
+ # very common strings you have in your dataset.
127
+ #
128
+ # WARNING: object sharing is experimental, don't enable this feature
129
+ # in production before of Redis 1.0-stable. Still please try this feature in
130
+ # your development environment so that we can test it better.
131
+ #shareobjects no
132
+ #shareobjectspoolsize 1024
@@ -0,0 +1,42 @@
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+ $TESTING = true
4
+
5
+ require 'rubygems'
6
+ require 'test/unit'
7
+ require 'resque'
8
+ require 'active_support'
9
+ require 'active_support/test_case'
10
+
11
+ require 'resque-pubsub'
12
+
13
+ ##
14
+ # make sure we can run redis
15
+ if !system("which redis-server")
16
+ puts '', "** can't find `redis-server` in your path"
17
+ puts "** try running `sudo rake install`"
18
+ abort ''
19
+ end
20
+
21
+ ##
22
+ # start our own redis when the tests start,
23
+ # kill it when they end
24
+ at_exit do
25
+ next if $!
26
+
27
+ if defined?(MiniTest)
28
+ exit_code = MiniTest::Unit.new.run(ARGV)
29
+ else
30
+ exit_code = Test::Unit::AutoRunner.run
31
+ end
32
+
33
+ pid = `ps -e -o pid,command | grep [r]edis-test`.split(" ")[0]
34
+ puts "Killing test redis server..."
35
+ `rm -f #{dir}/dump.rdb`
36
+ Process.kill("KILL", pid.to_i)
37
+ exit exit_code
38
+ end
39
+
40
+ puts "Starting redis for testing at localhost:9736..."
41
+ `redis-server #{dir}/redis-test.conf`
42
+ Resque.redis = '127.0.0.1:9736'
@@ -0,0 +1,4 @@
1
+ class TestPublisher
2
+ require 'resque-pubsub'
3
+
4
+ end
@@ -0,0 +1,17 @@
1
+ class TestSubscriber
2
+ require 'resque-pubsub'
3
+
4
+ subscribe 'test_topic'
5
+
6
+ @@last_message = nil
7
+
8
+ def self.read_test_topic_message(message)
9
+ puts "got test topic message: #{message.inspect}"
10
+ @@last_message = message
11
+ end
12
+
13
+ def self.last_message
14
+ @@last_message
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ class TestSubscriberCustom
2
+ require 'resque-pubsub'
3
+
4
+ subscribe 'test_custom_topic', :reader_method => 'simple'
5
+
6
+ @@last_message = nil
7
+
8
+ def self.simple(message)
9
+ puts "in simple, got test custom topic message: #{message.inspect}"
10
+ @@last_message = message
11
+ end
12
+
13
+ def self.last_message
14
+ @@last_message
15
+ end
16
+
17
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-pubsub
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Monica McArthur
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-14 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: resque
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 39
30
+ segments:
31
+ - 1
32
+ - 9
33
+ - 10
34
+ version: 1.9.10
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: " A Resque plugin. Provides a lightweight publish/subscribe messaging system, with message persistence when clients are down.\n"
38
+ email: mechaferret@gmail.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - README.md
47
+ - Rakefile
48
+ - MIT-LICENSE
49
+ - HISTORY.md
50
+ - lib/resque/plugins/pubsub/broker.rb
51
+ - lib/resque/plugins/pubsub/exchange.rb
52
+ - lib/resque/plugins/pubsub/publisher.rb
53
+ - lib/resque/plugins/pubsub/subscriber.rb
54
+ - lib/resque-pubsub.rb
55
+ - test/debug.log
56
+ - test/pubsub_test.rb
57
+ - test/redis-test.conf
58
+ - test/test_helper.rb
59
+ - test/test_publisher.rb
60
+ - test/test_subscriber.rb
61
+ - test/test_subscriber_custom.rb
62
+ has_rdoc: true
63
+ homepage: http://github.com/mechaferret/resque-pubsub
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options: []
68
+
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.5.2
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: A Resque plugin that provides a lightweight publish/subscribe messaging system.
96
+ test_files: []
97
+