├── .rspec ├── .rbenv-version ├── Rakefile ├── .gitignore ├── Gemfile ├── lib ├── resque_bus │ ├── version.rb │ ├── compatibility │ │ ├── task_manager.rb │ │ ├── subscriber.rb │ │ ├── driver.rb │ │ ├── heartbeat.rb │ │ ├── publisher.rb │ │ ├── rider.rb │ │ └── deprecated.rb │ ├── server.rb │ ├── adapter.rb │ ├── tasks.rb │ └── server │ │ └── views │ │ └── bus.erb └── resque-bus.rb ├── .rvmrc ├── spec ├── publisher_spec.rb ├── adapter_spec.rb ├── adapter │ ├── support.rb │ ├── retry_spec.rb │ ├── publish_at_spec.rb │ ├── compatibility_spec.rb │ └── integration_spec.rb ├── worker_spec.rb ├── heartbeat_spec.rb ├── spec_helper.rb ├── rider_spec.rb ├── subscription_list_spec.rb ├── integration_spec.rb ├── config_spec.rb ├── dispatch_spec.rb ├── subscription_spec.rb ├── publish_spec.rb ├── driver_spec.rb ├── matcher_spec.rb ├── application_spec.rb └── subscriber_spec.rb ├── CHANGELOG.md ├── MIT-LICENSE ├── resque-bus.gemspec └── README.mdown /.rspec: -------------------------------------------------------------------------------- 1 | --color -------------------------------------------------------------------------------- /.rbenv-version: -------------------------------------------------------------------------------- 1 | 1.9.3-p194 -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift 'lib' 2 | require 'resque_bus/tasks' 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "rake" 6 | -------------------------------------------------------------------------------- /lib/resque_bus/version.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | VERSION = "0.7.0" 3 | end 4 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm use 1.9.3-p194@resque-bus --install --create 2 | export PATH=./bin:$PATH 3 | -------------------------------------------------------------------------------- /spec/publisher_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Publisher do 5 | it "should call publish as expected" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/task_manager.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | class TaskManager < ::QueueBus::TaskManager 3 | def initialize(logging) 4 | ResqueBus.note_deprecation "[DEPRECATION] ResqueBus::TaskManager is deprecated. Use QueueBus::TaskManager instead." 5 | super(logging) 6 | end 7 | end 8 | end -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/subscriber.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | module Subscriber 3 | def self.included(base) 4 | ResqueBus.note_deprecation "[DEPRECATION] ResqueBus::Subscriber is deprecated. Use QueueBus::Subscriber instead." 5 | base.send(:include, ::QueueBus::Subscriber) 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/driver.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | class Driver 3 | class << self 4 | def perform(attributes={}) 5 | ResqueBus.note_deprecation "[MIGRATION] Note: new events will be using QueueBus::Driver" 6 | ::QueueBus::Driver.perform(attributes) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/heartbeat.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | class Heartbeat 3 | class << self 4 | def perform(attributes={}) 5 | ResqueBus.note_deprecation "[MIGRATION] Note: new events will be using QueueBus::Heartbeat" 6 | ::QueueBus::Heartbeat.perform(attributes) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/publisher.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | # publishes on a delay 3 | class Publisher 4 | class << self 5 | def perform(event_type, attributes = {}) 6 | attributes["bus_event_type"] = event_type # now using one hash only 7 | ResqueBus.note_deprecation "[MIGRATION] Note: new events will be using QueueBus::Publisher" 8 | ::QueueBus::Publisher.perform(attributes) 9 | end 10 | end 11 | 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/adapter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "adapter is set" do 4 | it "should call it's enabled! method on init" do 5 | QueueBus.send(:reset) 6 | adapter_under_test_class.any_instance.should_receive(:enabled!) 7 | instance = adapter_under_test_class.new 8 | QueueBus.send(:reset) 9 | end 10 | 11 | it "should be defaulting to Data from spec_helper" do 12 | QueueBus.adapter.is_a?(adapter_under_test_class).should == true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/adapter/support.rb: -------------------------------------------------------------------------------- 1 | require 'resque-bus' 2 | require 'resque' 3 | require 'resque/scheduler' 4 | 5 | def reset_test_adapter 6 | QueueBus.send(:reset) 7 | QueueBus.adapter = QueueBus::Adapters::Resque.new 8 | end 9 | 10 | def adapter_under_test_class 11 | QueueBus::Adapters::Resque 12 | end 13 | 14 | def adapter_under_test_symbol 15 | :resque 16 | end 17 | 18 | def perform_next_job(worker, &block) 19 | return unless job = worker.reserve 20 | worker.perform(job, &block) 21 | worker.done_working 22 | end 23 | 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.7.0] 2019-07-29 10 | 11 | ### Added 12 | - Adds `QueueBus.has_adapter?` to check whether the adapter is set before setting it to resque. This will allow multiple adapters to be loaded without error. 13 | 14 | ### Changed 15 | - Bump version dependency of queue-bus to at least 0.7 16 | -------------------------------------------------------------------------------- /lib/resque_bus/server.rb: -------------------------------------------------------------------------------- 1 | require 'resque-bus' 2 | require 'resque/server' 3 | require 'erb' 4 | 5 | # MIGRATE TODO: move to resque gem 6 | # Extend ::Resque::Server to add tabs. 7 | module ResqueBus 8 | module Server 9 | 10 | def self.included(base) 11 | base.class_eval { 12 | 13 | get "/bus" do 14 | erb File.read(File.join(File.dirname(__FILE__), "server/views/bus.erb")) 15 | end 16 | 17 | 18 | post '/bus/unsubscribe' do 19 | app = ::QueueBus::Application.new(params[:name]).unsubscribe 20 | redirect u('bus') 21 | end 22 | 23 | } 24 | end 25 | end 26 | end 27 | 28 | ::Resque::Server.tabs << 'Bus' 29 | ::Resque::Server.class_eval do 30 | include ::ResqueBus::Server 31 | end -------------------------------------------------------------------------------- /lib/resque-bus.rb: -------------------------------------------------------------------------------- 1 | require "queue-bus" 2 | require "resque_bus/adapter" 3 | require "resque_bus/version" 4 | 5 | module ResqueBus 6 | # TODO: all of this will be removed 7 | 8 | autoload :Deprecated, 'resque_bus/compatibility/deprecated' 9 | autoload :Subscriber, 'resque_bus/compatibility/subscriber' 10 | autoload :TaskManager, 'resque_bus/compatibility/task_manager' 11 | autoload :Driver, 'resque_bus/compatibility/driver' 12 | autoload :Rider, 'resque_bus/compatibility/rider' 13 | autoload :Publisher, 'resque_bus/compatibility/publisher' 14 | autoload :Heartbeat, 'resque_bus/compatibility/heartbeat' 15 | 16 | extend ::ResqueBus::Deprecated 17 | end 18 | 19 | if QueueBus.has_adapter? 20 | warn '[ResqueBus] Not setting adapter on queue-bus because ' \ 21 | "#{QueueBus.adapter.class.name} is already the adapter" 22 | else 23 | QueueBus.adapter = QueueBus::Adapters::Resque.new 24 | end 25 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/rider.rb: -------------------------------------------------------------------------------- 1 | require 'resque-retry' 2 | 3 | module ResqueBus 4 | class Rider 5 | extend Resque::Plugins::ExponentialBackoff 6 | 7 | class << self 8 | def perform(attributes = {}) 9 | ResqueBus.note_deprecation "[MIGRATION] Note: new events will be using QueueBus::Rider" 10 | ::QueueBus::Rider.perform(attributes) 11 | end 12 | 13 | # @failure_hooks_already_ran on https://github.com/defunkt/resque/tree/1-x-stable 14 | # to prevent running twice 15 | def queue 16 | @my_queue 17 | end 18 | 19 | def on_failure_aaa(exception, *args) 20 | # note: sorted alphabetically 21 | # queue needs to be set for rety to work (know what queue in Requeue.class_to_queue) 22 | @my_queue = args[0]["bus_rider_queue"] 23 | end 24 | 25 | def on_failure_zzz(exception, *args) 26 | # note: sorted alphabetically 27 | @my_queue = nil 28 | end 29 | 30 | end 31 | end 32 | end -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Brian Leonard 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. 21 | -------------------------------------------------------------------------------- /resque-bus.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "resque_bus/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "resque-bus" 7 | s.version = ResqueBus::VERSION 8 | s.authors = ["Brian Leonard"] 9 | s.email = ["brian@bleonard.com"] 10 | s.homepage = "https://github.com/queue-bus/resque-bus" 11 | s.summary = %q{A simple event bus on top of Resque} 12 | s.description = %q{A simple event bus on top of Resque. Publish and subscribe to events as they occur through a queue.} 13 | 14 | s.files = `git ls-files`.split("\n") 15 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 16 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 17 | s.require_paths = ["lib"] 18 | 19 | s.add_dependency('queue-bus', ['>= 0.7', '< 1']) 20 | s.add_dependency('resque', ['>= 1.10.0', '< 2.0']) 21 | s.add_dependency('resque-scheduler', '>= 2.0.1') 22 | s.add_dependency('resque-retry') 23 | 24 | s.add_development_dependency("rspec") 25 | s.add_development_dependency("timecop") 26 | s.add_development_dependency("json_pure") 27 | end 28 | -------------------------------------------------------------------------------- /spec/worker_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Worker do 5 | it "should proxy to given class" do 6 | hash = {"bus_class_proxy" => "QueueBus::Driver", "ok" => true} 7 | QueueBus::Driver.should_receive(:perform).with(hash) 8 | QueueBus::Worker.perform(JSON.generate(hash)) 9 | end 10 | 11 | it "should use instance" do 12 | hash = {"bus_class_proxy" => "QueueBus::Rider", "ok" => true} 13 | QueueBus::Rider.should_receive(:perform).with(hash) 14 | QueueBus::Worker.new.perform(JSON.generate(hash)) 15 | end 16 | 17 | it "should not freak out if class not there anymore" do 18 | hash = {"bus_class_proxy" => "QueueBus::BadClass", "ok" => true} 19 | lambda { 20 | QueueBus::Worker.perform(JSON.generate(hash)) 21 | }.should_not raise_error 22 | end 23 | 24 | it "should raise error if proxy raises error" do 25 | hash = {"bus_class_proxy" => "QueueBus::Rider", "ok" => true} 26 | QueueBus::Rider.should_receive(:perform).with(hash).and_raise("rider crash") 27 | lambda { 28 | QueueBus::Worker.perform(JSON.generate(hash)) 29 | }.should raise_error 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/resque_bus/compatibility/deprecated.rb: -------------------------------------------------------------------------------- 1 | module ResqueBus 2 | module Deprecated 3 | def show_deprecations=val 4 | @show_deprecations = val 5 | end 6 | 7 | def show_deprecations? 8 | return @show_deprecations if defined?(@show_deprecations) 9 | return true if !ENV['QUEUES'] && !ENV['QUEUE'] # not in background, probably test 10 | return true if ENV['VVERBOSE'] || ENV['LOGGING'] || ENV['VERBOSE'] 11 | false 12 | end 13 | 14 | def note_deprecation(message) 15 | @noted_deprecations ||= {} 16 | if @noted_deprecations[message] 17 | @noted_deprecations[message] += 1 18 | else 19 | warn(message) if show_deprecations? 20 | @noted_deprecations[message] = 1 21 | end 22 | end 23 | 24 | def redis 25 | ResqueBus.note_deprecation "[DEPRECATION] ResqueBus direct usage is deprecated. Use `QueueBus.redis` instead. Note that it also requires block usage now." 26 | ::Resque.redis 27 | end 28 | 29 | def redis=val 30 | ResqueBus.note_deprecation "[DEPRECATION] ResqueBus can no longer set redis directly. It will use Resque's instance of redis." 31 | end 32 | 33 | def method_missing(method_name, *args, &block) 34 | ResqueBus.note_deprecation "[DEPRECATION] ResqueBus direct usage is deprecated. Use `QueueBus.#{method_name}` instead." 35 | ::QueueBus.send(method_name, *args, &block) 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/heartbeat_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Heartbeat do 5 | def now_attributes 6 | { 7 | "epoch_seconds" => (Time.now.to_i / 60) * 60, # rounded 8 | "epoch_minutes" => Time.now.to_i / 60, 9 | "epoch_hours" => Time.now.to_i / (60*60), 10 | "epoch_days" => Time.now.to_i / (60*60*24), 11 | "minute" => Time.now.min, 12 | "hour" => Time.now.hour, 13 | "day" => Time.now.day, 14 | "month" => Time.now.month, 15 | "year" => Time.now.year, 16 | "yday" => Time.now.yday, 17 | "wday" => Time.now.wday 18 | } 19 | end 20 | 21 | it "should publish the current time once" do 22 | Timecop.freeze "12/12/2013 12:01:19" do 23 | QueueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes) 24 | Heartbeat.perform 25 | end 26 | 27 | Timecop.freeze "12/12/2013 12:01:40" do 28 | Heartbeat.perform 29 | end 30 | end 31 | 32 | it "should publish a minute later" do 33 | Timecop.freeze "12/12/2013 12:01:19" do 34 | QueueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes) 35 | Heartbeat.perform 36 | end 37 | 38 | Timecop.freeze "12/12/2013 12:02:01" do 39 | QueueBus.should_receive(:publish).with("heartbeat_minutes", now_attributes) 40 | Heartbeat.perform 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'timecop' 2 | require 'queue-bus' 3 | require 'adapter/support' 4 | 5 | reset_test_adapter 6 | 7 | module QueueBus 8 | class Runner 9 | def self.value 10 | @value ||= 0 11 | end 12 | 13 | def self.attributes 14 | @attributes 15 | end 16 | 17 | def self.run(attrs) 18 | @value ||= 0 19 | @value += 1 20 | @attributes = attrs 21 | end 22 | 23 | def self.reset 24 | @value = nil 25 | @attributes = nil 26 | end 27 | end 28 | 29 | class Runner1 < Runner 30 | end 31 | 32 | class Runner2 < Runner 33 | end 34 | end 35 | 36 | def test_sub(event_name, queue="default") 37 | matcher = {"bus_event_type" => event_name} 38 | QueueBus::Subscription.new(queue, event_name, "::QueueBus::Rider", matcher, nil) 39 | end 40 | 41 | def test_list(*args) 42 | out = QueueBus::SubscriptionList.new 43 | args.each do |sub| 44 | out.add(sub) 45 | end 46 | out 47 | end 48 | 49 | RSpec.configure do |config| 50 | config.mock_with :rspec do |c| 51 | c.syntax = :should 52 | end 53 | config.expect_with :rspec do |c| 54 | c.syntax = :should 55 | end 56 | 57 | config.before(:each) do 58 | reset_test_adapter 59 | ResqueBus.show_deprecations = true 60 | end 61 | config.after(:each) do 62 | begin 63 | QueueBus.redis { |redis| redis.flushall } 64 | rescue 65 | end 66 | QueueBus.send(:reset) 67 | QueueBus::Runner1.reset 68 | QueueBus::Runner2.reset 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/adapter/retry_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Retry" do 4 | class RetryTest1 5 | include QueueBus::Subscriber 6 | application :my_thing 7 | subscribe :event_sub 8 | def event_sub(attributes) 9 | QueueBus::Runner1.run(attributes) 10 | end 11 | end 12 | 13 | it "should have the methods" do 14 | ::QueueBus::Worker.methods.should include(:on_failure_aaa) 15 | ::QueueBus::Worker.methods.should include(:on_failure_zzz) 16 | end 17 | 18 | # it "should retry failed riders" 19 | 20 | describe "Failed Jobs" do 21 | before(:each) do 22 | QueueBus.enqueue_to("testing", "QueueBus::Worker", { "bus_class_proxy" => "QueueBus::Rider", "bus_rider_app_key" => "r2", "bus_rider_sub_key" => "event_name", "bus_event_type" => "event_name", "ok" => true, "bus_rider_queue" => "testing" }) 23 | 24 | @worker = Resque::Worker.new(:testing) 25 | @worker.register_worker 26 | end 27 | 28 | it "should put it in the failed jobs" do 29 | 30 | QueueBus.dispatch("r2") do 31 | subscribe "event_name" do |attributes| 32 | raise "boo!" 33 | end 34 | end 35 | 36 | perform_next_job @worker 37 | Resque.info[:processed].should == 1 38 | Resque.info[:failed].should == 1 39 | Resque.info[:pending].should == 1 # requeued 40 | 41 | perform_next_job @worker 42 | Resque.info[:processed].should == 2 43 | Resque.info[:failed].should == 2 44 | Resque.info[:pending].should == 0 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /spec/rider_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Rider do 5 | it "should call execute" do 6 | QueueBus.should_receive(:dispatcher_execute) 7 | Rider.perform("bus_rider_app_key" => "app", "bus_rider_sub_key" => "sub", "ok" => true, "bus_event_type" => "event_name") 8 | end 9 | 10 | it "should change the value" do 11 | QueueBus.dispatch("r1") do 12 | subscribe "event_name" do |attributes| 13 | Runner1.run(attributes) 14 | end 15 | end 16 | Runner1.value.should == 0 17 | Rider.perform("bus_locale" => "en", "bus_timezone" => "PST", "bus_rider_app_key" => "r1", "bus_rider_sub_key" => "event_name", "ok" => true, "bus_event_type" => "event_name") 18 | Rider.perform("bus_rider_app_key" => "other", "bus_rider_sub_key" => "event_name", "ok" => true, "bus_event_type" => "event_name") 19 | Runner1.value.should == 1 20 | end 21 | 22 | it "should set the timezone and locale if present" do 23 | QueueBus.dispatch("r1") do 24 | subscribe "event_name" do |attributes| 25 | Runner1.run(attributes) 26 | end 27 | end 28 | 29 | defined?(I18n).should be_nil 30 | Time.respond_to?(:zone).should eq(false) 31 | 32 | stub_const("I18n", Class.new) 33 | I18n.should_receive(:locale=).with("en") 34 | Time.should_receive(:zone=).with("PST") 35 | 36 | Rider.perform("bus_locale" => "en", "bus_timezone" => "PST", "bus_rider_app_key" => "r1", "bus_rider_sub_key" => "event_name", "ok" => true, "bus_event_type" => "event_name") 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/subscription_list_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe SubscriptionList do 5 | describe ".from_redis" do 6 | it "should return from attributes" do 7 | mult = {"event_one" => {"class" => "MyClass", "queue_name" => "default", "key" => "event_one", "matcher" => {"bus_event_type" => "event_one"}}, 8 | "event_two" => {"class" => "MyClass", "queue_name" => "else", "key" => "event_two", "matcher" => {"bus_event_type" => "event_two"}}} 9 | 10 | list = SubscriptionList.from_redis(mult) 11 | list.size.should == 2 12 | one = list.key("event_one") 13 | two = list.key("event_two") 14 | 15 | one.key.should == "event_one" 16 | one.key.should == "event_one" 17 | one.queue_name.should == "default" 18 | one.class_name.should == "MyClass" 19 | one.matcher.filters.should == {"bus_event_type" => "event_one"} 20 | 21 | two.key.should == "event_two" 22 | two.key.should == "event_two" 23 | two.queue_name.should == "else" 24 | two.class_name.should == "MyClass" 25 | two.matcher.filters.should == {"bus_event_type" => "event_two"} 26 | end 27 | end 28 | 29 | describe "#to_redis" do 30 | it "should generate what to store" do 31 | list = SubscriptionList.new 32 | list.add(Subscription.new("default", "key1", "MyClass", {"bus_event_type" => "event_one"})) 33 | list.add(Subscription.new("else_ok", "key2", "MyClass", {"bus_event_type" => "event_two"})) 34 | 35 | hash = list.to_redis 36 | hash.should == { "key1" => {"queue_name" => "default", "key" => "key1", "class" => "MyClass", "matcher" => {"bus_event_type" => "event_one"}}, 37 | "key2" => {"queue_name" => "else_ok", "key" => "key2", "class" => "MyClass", "matcher" => {"bus_event_type" => "event_two"}} 38 | } 39 | 40 | end 41 | end 42 | end 43 | end -------------------------------------------------------------------------------- /spec/adapter/publish_at_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Publishing an event in the future" do 4 | 5 | before(:each) do 6 | Timecop.freeze(now) 7 | QueueBus.stub(:generate_uuid).and_return("idfhlkj") 8 | end 9 | after(:each) do 10 | Timecop.return 11 | end 12 | let(:delayed_attrs) { {"bus_delayed_until" => future.to_i, 13 | "bus_id" => "#{now.to_i}-idfhlkj", 14 | "bus_app_hostname" => `hostname 2>&1`.strip.sub(/.local/,'')} } 15 | 16 | let(:bus_attrs) { delayed_attrs.merge({"bus_published_at" => worktime.to_i})} 17 | let(:now) { Time.parse("01/01/2013 5:00")} 18 | let(:future) { Time.at(now.to_i + 60) } 19 | let(:worktime) {Time.at(future.to_i + 1)} 20 | 21 | it "should add it to Redis then to the real queue" do 22 | hash = {:one => 1, "two" => "here", "id" => 12 } 23 | event_name = "event_name" 24 | QueueBus.publish_at(future, event_name, hash) 25 | 26 | schedule = QueueBus.redis { |redis| redis.zrange("delayed_queue_schedule", 0, 1) } 27 | schedule.should == [future.to_i.to_s] 28 | 29 | val = QueueBus.redis { |redis| redis.lpop("delayed:#{future.to_i}") } 30 | hash = JSON.parse(val) 31 | 32 | hash["class"].should == "QueueBus::Worker" 33 | hash["args"].size.should == 1 34 | JSON.parse(hash["args"].first).should == {"bus_class_proxy" => "QueueBus::Publisher", "bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(delayed_attrs) 35 | hash["queue"].should == "bus_incoming" 36 | 37 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 38 | val.should == nil # nothing really added 39 | 40 | Timecop.freeze(worktime) 41 | QueueBus::Publisher.perform(JSON.parse(hash["args"].first)) 42 | 43 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 44 | hash = JSON.parse(val) 45 | hash["class"].should == "QueueBus::Worker" 46 | hash["args"].size.should == 1 47 | JSON.parse(hash["args"].first).should == {"bus_class_proxy" => "QueueBus::Driver", "bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(bus_attrs) 48 | end 49 | 50 | end 51 | -------------------------------------------------------------------------------- /spec/integration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe "Integration" do 5 | it "should round trip attributes" do 6 | write1 = Subscription.new("default", "key1", "MyClass1", {"bus_event_type" => "event_one"}) 7 | write2 = Subscription.new("else_ok", "key2", "MyClass2", {"bus_event_type" => /^[ab]here/}) #regex 8 | 9 | write1.matches?("bus_event_type" => "event_one").should == true 10 | write1.matches?("bus_event_type" => "event_one1").should == false 11 | write1.matches?("bus_event_type" => "aevent_one").should == false 12 | 13 | write2.matches?("bus_event_type" => "ahere").should == true 14 | write2.matches?("bus_event_type" => "bhere").should == true 15 | write2.matches?("bus_event_type" => "qhere").should == false 16 | write2.matches?("bus_event_type" => "abhere").should == false 17 | write2.matches?("bus_event_type" => "[ab]here").should == false 18 | 19 | write = SubscriptionList.new 20 | write.add(write1) 21 | write.add(write2) 22 | 23 | app = Application.new("test") 24 | app.subscribe(write) 25 | 26 | reset_test_adapter # reset to make sure we read from redis 27 | app = Application.new("test") 28 | read = app.send(:subscriptions) 29 | 30 | read.size.should == 2 31 | read1 = read.key("key1") 32 | read2 = read.key("key2") 33 | read1.should_not be_nil 34 | read2.should_not be_nil 35 | 36 | read1.queue_name.should == "default" 37 | read1.class_name.should == "MyClass1" 38 | read2.queue_name.should == "else_ok" 39 | read2.class_name.should == "MyClass2" 40 | 41 | read1.matches?("bus_event_type" => "event_one").should == true 42 | read1.matches?("bus_event_type" => "event_one1").should == false 43 | read1.matches?("bus_event_type" => "aevent_one").should == false 44 | 45 | read2.matches?("bus_event_type" => "ahere").should == true 46 | read2.matches?("bus_event_type" => "bhere").should == true 47 | read2.matches?("bus_event_type" => "qhere").should == false 48 | read2.matches?("bus_event_type" => "abhere").should == false 49 | read2.matches?("bus_event_type" => "[ab]here").should == false 50 | 51 | end 52 | end 53 | end -------------------------------------------------------------------------------- /spec/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | module Adapters 5 | class TestOne 6 | 7 | end 8 | end 9 | end 10 | 11 | describe "QueueBus config" do 12 | it "should set the default app key" do 13 | QueueBus.default_app_key.should == nil 14 | 15 | QueueBus.default_app_key = "my_app" 16 | QueueBus.default_app_key.should == "my_app" 17 | 18 | QueueBus.default_app_key = "something here" 19 | QueueBus.default_app_key.should == "something_here" 20 | end 21 | 22 | it "should set the default queue" do 23 | QueueBus.default_queue.should == nil 24 | 25 | QueueBus.default_queue = "my_queue" 26 | QueueBus.default_queue.should == "my_queue" 27 | end 28 | 29 | it "should set the local mode" do 30 | QueueBus.local_mode.should == nil 31 | QueueBus.local_mode = :standalone 32 | QueueBus.local_mode.should == :standalone 33 | end 34 | 35 | it "should set the hostname" do 36 | QueueBus.hostname.should_not == nil 37 | QueueBus.hostname = "whatever" 38 | QueueBus.hostname.should == "whatever" 39 | end 40 | 41 | it "should set before_publish callback" do 42 | QueueBus.before_publish = lambda {|attributes| 42 } 43 | QueueBus.before_publish_callback({}).should == 42 44 | end 45 | 46 | 47 | it "should use the default Redis connection" do 48 | QueueBus.redis { |redis| redis }.should_not eq(nil) 49 | end 50 | 51 | it "should default to given adapter" do 52 | QueueBus.adapter.is_a?(adapter_under_test_class).should == true 53 | 54 | # and should raise if already set 55 | lambda { 56 | QueueBus.adapter = :data 57 | }.should raise_error 58 | end 59 | 60 | context "with a fresh load" do 61 | before(:each) do 62 | QueueBus.send(:reset) 63 | end 64 | 65 | it "should be able to be set to resque" do 66 | QueueBus.adapter = adapter_under_test_symbol 67 | QueueBus.adapter.is_a?(adapter_under_test_class).should == true 68 | 69 | # and should raise if already set 70 | lambda { 71 | QueueBus.adapter = :data 72 | }.should raise_error 73 | end 74 | 75 | it "should be able to be set to something else" do 76 | 77 | QueueBus.adapter = :test_one 78 | QueueBus.adapter.is_a?(QueueBus::Adapters::TestOne).should == true 79 | end 80 | end 81 | 82 | 83 | end 84 | -------------------------------------------------------------------------------- /lib/resque_bus/adapter.rb: -------------------------------------------------------------------------------- 1 | module QueueBus 2 | module Adapters 3 | class Resque < QueueBus::Adapters::Base 4 | def enabled! 5 | # know we are using it 6 | require 'resque' 7 | require 'resque/scheduler' 8 | require 'resque-retry' 9 | 10 | QueueBus::Worker.extend(::Resque::Plugins::ExponentialBackoff) 11 | QueueBus::Worker.extend(::QueueBus::Adapters::Resque::RetryHandlers) 12 | end 13 | 14 | def redis(&block) 15 | block.call(::Resque.redis) 16 | end 17 | 18 | def enqueue(queue_name, klass, json) 19 | ::Resque.enqueue_to(queue_name, klass, json) 20 | end 21 | 22 | def enqueue_at(epoch_seconds, queue_name, klass, json) 23 | ::Resque.enqueue_at_with_queue(queue_name, epoch_seconds, klass, json) 24 | end 25 | 26 | def setup_heartbeat!(queue_name) 27 | # turn on the heartbeat 28 | # should be down after loading scheduler yml if you do that 29 | # otherwise, anytime 30 | name = 'resquebus_heartbeat' 31 | schedule = { 'class' => '::QueueBus::Worker', 32 | 'args'=>[::QueueBus::Util.encode({'bus_class_proxy' => '::QueueBus::Heartbeat'})], 33 | 'cron' => '* * * * *', # every minute 34 | 'queue' => queue_name, 35 | 'description' => 'I publish a heartbeat_minutes event every minute' 36 | } 37 | if ::Resque::Scheduler.dynamic 38 | ::Resque.set_schedule(name, schedule) 39 | end 40 | ::Resque.schedule[name] = schedule 41 | end 42 | 43 | private 44 | 45 | module RetryHandlers 46 | # @failure_hooks_already_ran on https://github.com/defunkt/resque/tree/1-x-stable 47 | # to prevent running twice 48 | def queue 49 | @my_queue 50 | end 51 | 52 | def on_failure_aaa(exception, *args) 53 | # note: sorted alphabetically 54 | # queue needs to be set for rety to work (know what queue in Requeue.class_to_queue) 55 | hash = ::QueueBus::Util.decode(args[0]) 56 | @my_queue = hash["bus_rider_queue"] 57 | end 58 | 59 | def on_failure_zzz(exception, *args) 60 | # note: sorted alphabetically 61 | @my_queue = nil 62 | end 63 | end 64 | end 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /spec/dispatch_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Dispatch do 5 | it "should not start with any applications" do 6 | Dispatch.new("d").subscriptions.size.should == 0 7 | end 8 | 9 | it "should register code to run and execute it" do 10 | dispatch = Dispatch.new("d") 11 | dispatch.subscribe("my_event") do |attrs| 12 | Runner1.run(attrs) 13 | end 14 | sub = dispatch.subscriptions.key("my_event") 15 | sub.send(:executor).is_a?(Proc).should == true 16 | 17 | Runner.value.should == 0 18 | dispatch.execute("my_event", {"bus_event_type" => "my_event", "ok" => true}) 19 | Runner1.value.should == 1 20 | Runner1.attributes.should == {"bus_event_type" => "my_event", "ok" => true} 21 | 22 | end 23 | 24 | it "should not crash if not there" do 25 | lambda { 26 | Dispatch.new("d").execute("fdkjh", "bus_event_type" => "fdkjh") 27 | }.should_not raise_error 28 | end 29 | 30 | describe "Top Level" do 31 | before(:each) do 32 | QueueBus.dispatch("testit") do 33 | subscribe "event1" do |attributes| 34 | Runner2.run(attributes) 35 | end 36 | 37 | subscribe "event2" do 38 | Runner2.run({}) 39 | end 40 | 41 | high "event3" do 42 | Runner2.run({}) 43 | end 44 | 45 | low /^patt.+ern/ do 46 | Runner.run({}) 47 | end 48 | end 49 | end 50 | 51 | it "should register and run" do 52 | Runner2.value.should == 0 53 | QueueBus.dispatcher_execute("testit", "event2", "bus_event_type" => "event2") 54 | Runner2.value.should == 1 55 | QueueBus.dispatcher_execute("testit", "event1", "bus_event_type" => "event1") 56 | Runner2.value.should == 2 57 | QueueBus.dispatcher_execute("testit", "event1", "bus_event_type" => "event1") 58 | Runner2.value.should == 3 59 | end 60 | 61 | it "should return the subscriptions" do 62 | dispatcher = QueueBus.dispatcher_by_key("testit") 63 | subs = dispatcher.subscriptions.all 64 | tuples = subs.collect{ |sub| [sub.key, sub.queue_name]} 65 | tuples.should =~ [ ["event1", "testit_default"], 66 | ["event2", "testit_default"], 67 | ["event3", "testit_high"], 68 | [ "(?-mix:^patt.+ern)", "testit_low"] 69 | ] 70 | end 71 | 72 | end 73 | end 74 | 75 | end 76 | 77 | -------------------------------------------------------------------------------- /spec/subscription_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module QueueBus 4 | describe Subscription do 5 | it "should normalize the queue name" do 6 | Subscription.new("test", "my_event", "MyClass", {}, nil).queue_name.should == "test" 7 | Subscription.new("tes t", "my_event", "MyClass", {}, nil).queue_name.should == "tes_t" 8 | Subscription.new("t%s", "my_event", "MyClass", {}, nil).queue_name.should == "t_s" 9 | end 10 | 11 | describe ".register" do 12 | it "should take in args from dispatcher" do 13 | executor = Proc.new { |attributes| } 14 | sub = Subscription.register("queue_name", "mykey", "MyClass", {"bus_event_type" => "my_event"}, executor) 15 | sub.send(:executor).should == executor 16 | sub.matcher.filters.should == {"bus_event_type" => "my_event"} 17 | sub.queue_name.should == "queue_name" 18 | sub.key.should == "mykey" 19 | sub.class_name.should == "MyClass" 20 | end 21 | end 22 | 23 | describe "#execute!" do 24 | it "should call the executor with the attributes" do 25 | exec = Object.new 26 | exec.should_receive(:call) 27 | 28 | sub = Subscription.new("x", "y", "ClassName", {}, exec) 29 | sub.execute!({"ok" => true}) 30 | end 31 | end 32 | 33 | describe "#to_redis" do 34 | it "should return what to store for this subscription" do 35 | sub = Subscription.new("queue_one", "xyz", "ClassName", {"bus_event_type" => "my_event"}, nil) 36 | sub.to_redis.should == {"queue_name" => "queue_one", "key" => "xyz", "class" => "ClassName", "matcher" => {"bus_event_type" => "my_event"}} 37 | end 38 | end 39 | 40 | describe "#matches?" do 41 | it "should do pattern stuff" do 42 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "one"}).matches?("bus_event_type" => "one").should == true 43 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "one"}).matches?("bus_event_type" => "onex").should == false 44 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "^one.*$"}).matches?("bus_event_type" => "onex").should == true 45 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "one.*"}).matches?("bus_event_type" => "onex").should == true 46 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "one.?"}).matches?("bus_event_type" => "onex").should == true 47 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "one.?"}).matches?("bus_event_type" => "one").should == true 48 | Subscription.new("x", "id", "ClassName", {"bus_event_type" => "\\"}).matches?("bus_event_type" => "one").should == false 49 | end 50 | end 51 | 52 | end 53 | end -------------------------------------------------------------------------------- /spec/adapter/compatibility_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Compatibility with old resque-bus" do 4 | before(:each) do 5 | ResqueBus.show_deprecations = false # expected 6 | 7 | QueueBus.dispatch("r1") do 8 | subscribe "event_name" do |attributes| 9 | QueueBus::Runner1.run(attributes) 10 | end 11 | end 12 | 13 | QueueBus::TaskManager.new(false).subscribe! 14 | 15 | @incoming = Resque::Worker.new(:resquebus_incoming) 16 | @incoming.register_worker 17 | 18 | @new_incoming = Resque::Worker.new(:bus_incoming) 19 | @new_incoming.register_worker 20 | 21 | @rider = Resque::Worker.new(:r1_default) 22 | @rider.register_worker 23 | end 24 | 25 | describe "Publisher" do 26 | it "should still publish as expected" do 27 | val = QueueBus.redis { |redis| redis.lpop("queue:resquebus_incoming") } 28 | val.should == nil 29 | 30 | args = [ "event_name", {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12} ] 31 | item = {:class => "ResqueBus::Publisher", :args => args} 32 | 33 | QueueBus.redis { |redis| redis.sadd(:queues, "resquebus_incoming") } 34 | QueueBus.redis { |redis| redis.rpush "queue:resquebus_incoming", Resque.encode(item) } 35 | 36 | QueueBus::Runner1.value.should == 0 37 | 38 | perform_next_job @incoming # publish 39 | 40 | QueueBus::Runner1.value.should == 0 41 | 42 | perform_next_job @new_incoming # drive 43 | 44 | QueueBus::Runner1.value.should == 0 45 | 46 | perform_next_job @rider # ride 47 | 48 | QueueBus::Runner1.value.should == 1 49 | 50 | end 51 | end 52 | 53 | describe "Rider" do 54 | it "should still ride as expected" do 55 | val = QueueBus.redis { |redis| redis.lpop("queue:r1_default") } 56 | val.should == nil 57 | 58 | args = [ {"bus_rider_app_key"=>"r1", "x" => "y", "bus_event_type" => "event_name", 59 | "bus_rider_sub_key"=>"event_name", "bus_rider_queue" => "default", 60 | "bus_rider_class_name"=>"::ResqueBus::Rider"}] 61 | item = {:class => "ResqueBus::Rider", :args => args} 62 | 63 | QueueBus.redis { |redis| redis.sadd(:queues, "r1_default") } 64 | QueueBus.redis { |redis| redis.rpush "queue:r1_default", Resque.encode(item) } 65 | 66 | QueueBus::Runner1.value.should == 0 67 | 68 | perform_next_job @rider 69 | 70 | QueueBus::Runner1.value.should == 1 71 | end 72 | end 73 | 74 | describe "Driver" do 75 | it "should still drive as expected" do 76 | val = QueueBus.redis { |redis| redis.lpop("queue:resquebus_incoming") } 77 | val.should == nil 78 | 79 | args = [ {"bus_event_type" => "event_name", "two"=>"here", "one"=>1, "id" => 12} ] 80 | item = {:class => "ResqueBus::Driver", :args => args} 81 | 82 | QueueBus.redis { |redis| redis.sadd(:queues, "resquebus_incoming") } 83 | QueueBus.redis { |redis| redis.rpush "queue:resquebus_incoming", Resque.encode(item) } 84 | 85 | QueueBus::Runner1.value.should == 0 86 | 87 | perform_next_job @incoming 88 | 89 | QueueBus::Runner1.value.should == 0 90 | 91 | perform_next_job @rider 92 | 93 | QueueBus::Runner1.value.should == 1 94 | 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /spec/publish_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Publishing an event" do 4 | 5 | before(:each) do 6 | Timecop.freeze 7 | QueueBus.stub(:generate_uuid).and_return("idfhlkj") 8 | end 9 | after(:each) do 10 | Timecop.return 11 | end 12 | let(:bus_attrs) { {"bus_class_proxy"=>"QueueBus::Driver", 13 | "bus_published_at" => Time.now.to_i, 14 | "bus_id"=>"#{Time.now.to_i}-idfhlkj", 15 | "bus_app_hostname" => `hostname 2>&1`.strip.sub(/.local/,'')} } 16 | 17 | it "should add it to Redis" do 18 | hash = {:one => 1, "two" => "here", "id" => 12 } 19 | event_name = "event_name" 20 | 21 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 22 | val.should == nil 23 | 24 | QueueBus.publish(event_name, hash) 25 | 26 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 27 | hash = JSON.parse(val) 28 | hash["class"].should == "QueueBus::Worker" 29 | hash["args"].size.should == 1 30 | JSON.parse(hash["args"].first).should == {"bus_event_type" => event_name, "two"=>"here", "one"=>1, "id" => 12}.merge(bus_attrs) 31 | 32 | end 33 | 34 | it "should use the id if given" do 35 | hash = {:one => 1, "two" => "here", "bus_id" => "app-given" } 36 | event_name = "event_name" 37 | 38 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 39 | val.should == nil 40 | 41 | QueueBus.publish(event_name, hash) 42 | 43 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 44 | hash = JSON.parse(val) 45 | hash["class"].should == "QueueBus::Worker" 46 | hash["args"].size.should == 1 47 | JSON.parse(hash["args"].first).should == {"bus_event_type" => event_name, "two"=>"here", "one"=>1}.merge(bus_attrs).merge("bus_id" => 'app-given') 48 | end 49 | 50 | it "should add metadata via callback" do 51 | myval = 0 52 | QueueBus.before_publish = lambda { |att| 53 | att["mine"] = 4 54 | myval += 1 55 | } 56 | 57 | hash = {:one => 1, "two" => "here", "bus_id" => "app-given" } 58 | event_name = "event_name" 59 | 60 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 61 | val.should == nil 62 | 63 | QueueBus.publish(event_name, hash) 64 | 65 | 66 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 67 | hash = JSON.parse(val) 68 | att = JSON.parse(hash["args"].first) 69 | att["mine"].should == 4 70 | myval.should == 1 71 | end 72 | 73 | it "should set the timezone and locale if available" do 74 | defined?(I18n).should be_nil 75 | Time.respond_to?(:zone).should eq(false) 76 | 77 | stub_const("I18n", Class.new) 78 | I18n.stub(:locale).and_return("jp") 79 | 80 | Time.stub(:zone).and_return(double('zone', :name => "EST")) 81 | 82 | hash = {:one => 1, "two" => "here", "bus_id" => "app-given" } 83 | event_name = "event_name" 84 | 85 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 86 | val.should == nil 87 | 88 | QueueBus.publish(event_name, hash) 89 | 90 | val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") } 91 | hash = JSON.parse(val) 92 | hash["class"].should == "QueueBus::Worker" 93 | att = JSON.parse(hash["args"].first) 94 | att["bus_locale"].should == "jp" 95 | att["bus_timezone"].should == "EST" 96 | end 97 | 98 | end 99 | -------------------------------------------------------------------------------- /lib/resque_bus/tasks.rb: -------------------------------------------------------------------------------- 1 | # require 'resque_bus/tasks' 2 | # will give you these tasks 3 | 4 | require "queue_bus/tasks" 5 | require "resque/tasks" 6 | 7 | namespace :resquebus do 8 | # deprecated 9 | task :setup => ["queuebus:setup"] do 10 | ResqueBus.note_deprecation "[DEPRECATION] rake resquebus:setup is deprecated. Use rake queuebus:setup instead." 11 | end 12 | 13 | task :driver => ["queuebus:driver"] do 14 | ResqueBus.note_deprecation "[DEPRECATION] rake resquebus:driver is deprecated. Use rake queuebus:driver instead." 15 | end 16 | 17 | task :subscribe => ["queuebus:subscribe"] do 18 | ResqueBus.note_deprecation "[DEPRECATION] rake resquebus:subscribe is deprecated. Use rake queuebus:subscribe instead." 19 | end 20 | 21 | task :unsubsribe => ["queuebus:unsubsribe"] do 22 | ResqueBus.note_deprecation "[DEPRECATION] rake resquebus:driver is deprecated. Use rake queuebus:unsubsribe instead." 23 | end 24 | end 25 | 26 | namespace :queuebus do 27 | 28 | desc "Setup will configure a resque task to run before resque:work" 29 | task :setup => [ :preload ] do 30 | 31 | if ENV['QUEUES'].nil? 32 | manager = ::QueueBus::TaskManager.new(true) 33 | queues = manager.queue_names 34 | ENV['QUEUES'] = queues.join(",") 35 | else 36 | queues = ENV['QUEUES'].split(",") 37 | end 38 | 39 | if queues.size == 1 40 | puts " >> Working Queue : #{queues.first}" 41 | else 42 | puts " >> Working Queues: #{queues.join(", ")}" 43 | end 44 | end 45 | 46 | desc "Sets the queue to work the driver Use: `rake queuebus:driver resque:work`" 47 | task :driver => [ :preload ] do 48 | ENV['QUEUES'] = ::QueueBus.incoming_queue 49 | end 50 | 51 | # Preload app files if this is Rails 52 | task :preload do 53 | require "resque" 54 | require "resque-bus" 55 | require "resque/failure/redis" 56 | require "resque/failure/multiple_with_retry_suppression" 57 | 58 | Resque::Failure::MultipleWithRetrySuppression.classes = [Resque::Failure::Redis] 59 | Resque::Failure.backend = Resque::Failure::MultipleWithRetrySuppression 60 | 61 | Rake::Task["resque:setup"].invoke # loads the environment and such if defined 62 | end 63 | 64 | 65 | # examples to test out the system 66 | namespace :example do 67 | desc "Publishes events to example applications" 68 | task :publish => [ "queuebus:preload", "queuebus:setup" ] do 69 | which = ["one", "two", "three", "other"][rand(4)] 70 | QueueBus.publish("event_#{which}", { "rand" => rand(99999)}) 71 | QueueBus.publish("event_all", { "rand" => rand(99999)}) 72 | QueueBus.publish("none_subscribed", { "rand" => rand(99999)}) 73 | puts "published event_#{which}, event_all, none_subscribed" 74 | end 75 | 76 | desc "Sets up an example config" 77 | task :register => [ "queuebus:preload"] do 78 | QueueBus.dispatch("example") do 79 | subscribe "event_one" do 80 | puts "event1 happened" 81 | end 82 | 83 | subscribe "event_two" do 84 | puts "event2 happened" 85 | end 86 | 87 | high "event_three" do 88 | puts "event3 happened (high)" 89 | end 90 | 91 | low "event_.*" do |attributes| 92 | puts "LOG ALL: #{attributes.inspect}" 93 | end 94 | end 95 | end 96 | 97 | desc "Subscribes this application to QueueBus example events" 98 | task :subscribe => [ :register, "queuebus:subscribe" ] 99 | 100 | desc "Start a QueueBus example worker" 101 | task :work => [ :register, "queuebus:setup", "resque:work" ] 102 | 103 | desc "Start a QueueBus example worker" 104 | task :driver => [ :register, "queuebus:driver", "resque:work" ] 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/resque_bus/server/views/bus.erb: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | <% 16 | app_hash = {} 17 | class_hash = {} 18 | event_hash = {} 19 | 20 | # collect each differently 21 | ::QueueBus::Application.all.each do |app| 22 | app_key = app.app_key 23 | 24 | app_hash[app_key] ||= [] 25 | app.event_display_tuples.each do |tuple| 26 | class_name, queue, filters = tuple 27 | if filters["bus_event_type"] 28 | event = filters["bus_event_type"] 29 | else 30 | event = "see filter" 31 | end 32 | 33 | app_hash[app_key] << [event, class_name, queue, filters] 34 | 35 | class_hash[class_name] ||= [] 36 | class_hash[class_name] << [app_key, event, queue, filters] 37 | 38 | event_hash[event] ||= [] 39 | event_hash[event] << [app_key, class_name, queue, filters] 40 | end 41 | end 42 | 43 | # sort each list item by secondary label 44 | class_hash.each do |_, array| 45 | array.sort!{ |a,b| a.first <=> b.first } 46 | end 47 | event_hash.each do |_, array| 48 | array.sort!{ |a,b| a.first <=> b.first } 49 | end 50 | 51 | # helper to display either 52 | def display_row(name, val, button=nil, first=false) 53 | form = "" 54 | if button 55 | text, url = button 56 | form = "
" 57 | end 58 | 59 | if !val 60 | out = "The apps below have registered the given classes and queues.
92 || App Key | 95 |Event Type | 96 |Class Name | 97 |Queue | 98 |Filters | 99 |
|---|
104 | 105 |
The events below have been registered by the given applications and queues.
107 || Event Type | 110 |App Key | 111 |Class Name | 112 |Queue | 113 |Filters | 114 |
|---|
121 | 122 |
The classes below have been registered by the given applications and queues.
124 || Class Name | 127 |App Key | 128 |Event Type | 129 |Queue | 130 |Filters | 131 |
|---|