banter 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +1 -1
  4. data/Gemfile +1 -4
  5. data/README.md +0 -33
  6. data/Rakefile +0 -28
  7. data/banter.gemspec +2 -5
  8. data/lib/banter.rb +1 -1
  9. data/lib/banter/configuration.rb +2 -4
  10. data/lib/banter/notifier.rb +16 -0
  11. data/lib/banter/publisher.rb +1 -1
  12. data/lib/banter/railtie.rb +0 -4
  13. data/lib/banter/server/client_queue_listener.rb +4 -37
  14. data/lib/banter/server/rabbit_mq_subscriber.rb +6 -6
  15. data/lib/banter/server/subscriber_server.rb +0 -13
  16. data/lib/banter/version.rb +1 -1
  17. data/spec/banter/notifier_spec.rb +40 -0
  18. data/spec/banter/server/client_queue_listener_spec.rb +36 -84
  19. data/spec/banter/server/rabbitmq_subscriber_spec.rb +14 -10
  20. data/spec/banter/server/subscriber_server_spec.rb +0 -60
  21. data/spec/banter/subscriber_spec.rb +0 -81
  22. data/spec/spec_helper.rb +1 -8
  23. data/spec/support/test_notifier.rb +17 -0
  24. metadata +33 -100
  25. data/.ruby-version +0 -1
  26. data/lib/banter/web.rb +0 -34
  27. data/lib/banter/web/application.rb +0 -85
  28. data/lib/banter/web/helpers.rb +0 -13
  29. data/lib/banter/web/models/banter_message.rb +0 -124
  30. data/lib/banter/web/models/banter_worker.rb +0 -72
  31. data/lib/banter/web/serializers/banter_message_serializer.rb +0 -35
  32. data/lib/banter/web/serializers/banter_worker_serializer.rb +0 -40
  33. data/lib/banter/web/serializers/subscriber_serializer.rb +0 -26
  34. data/spec/banter/web/application_spec.rb +0 -181
  35. data/spec/banter/web/serializers/banter_message_serializer_spec.rb +0 -42
  36. data/spec/banter/web/serializers/banter_worker_serializer_spec.rb +0 -44
  37. data/spec/factories/banter_messages.rb +0 -28
  38. data/spec/factories/banter_workers.rb +0 -17
  39. data/spec/mongoid.yml +0 -7
  40. data/web/assets/javascripts/banter.js +0 -449
  41. data/web/assets/javascripts/dashboard_app/app.coffee +0 -4
  42. data/web/assets/javascripts/dashboard_app/controllers/message_controller.coffee +0 -28
  43. data/web/assets/javascripts/dashboard_app/controllers/messages_controller.coffee +0 -58
  44. data/web/assets/javascripts/dashboard_app/controllers/subscribers_controller.coffee +0 -25
  45. data/web/assets/javascripts/dashboard_app/controllers/worker_controller.coffee +0 -30
  46. data/web/assets/javascripts/dashboard_app/controllers/workers_list_controller.coffee +0 -28
  47. data/web/assets/javascripts/dashboard_app/routes.coffee +0 -82
  48. data/web/assets/javascripts/dashboard_app/services/common_methods_service.coffee +0 -6
  49. data/web/assets/javascripts/dashboard_app/services/message_methods_service.coffee +0 -18
  50. data/web/assets/javascripts/dashboard_app/services/messages_service.coffee +0 -17
  51. data/web/assets/javascripts/dashboard_app/services/subscribers_service.coffee +0 -8
  52. data/web/assets/javascripts/dashboard_app/services/worker_methods_service.coffee +0 -11
  53. data/web/assets/javascripts/dashboard_app/services/worker_service.coffee +0 -15
  54. data/web/assets/javascripts/ng-prettyjson.js +0 -15
  55. data/web/assets/stylesheets/banter.css +0 -78
  56. data/web/views/_message.haml +0 -74
  57. data/web/views/_messages.haml +0 -77
  58. data/web/views/_subscribers.haml +0 -22
  59. data/web/views/_worker.haml +0 -52
  60. data/web/views/_workers_list.haml +0 -35
  61. data/web/views/index.haml +0 -19
  62. data/web/views/layout.haml +0 -51
@@ -1 +0,0 @@
1
- 2.0
@@ -1,34 +0,0 @@
1
- begin
2
- require 'sinatra/base'
3
- rescue LoadError
4
- raise "sinatra must be installed for banter/web to work. Add gem 'sinatra' to your Gemfile"
5
- end
6
-
7
- begin
8
- require 'haml'
9
- rescue LoadError
10
- raise "haml must be installed for banter/web to work. Add gem 'haml' to your Gemfile"
11
- end
12
-
13
- begin
14
- require 'mongoid'
15
- rescue LoadError
16
- raise "mongoid must be installed for banter/web to work. Add gem 'mongoid' to your Gemfile"
17
- end
18
-
19
- module Banter
20
- module Web
21
- autoload :Application, 'banter/web/application'
22
- autoload :Helpers, 'banter/web/helpers'
23
-
24
- module Serializers
25
- autoload :BanterWorkerSerializer, 'banter/web/serializers/banter_worker_serializer'
26
- autoload :BanterMessageSerializer, 'banter/web/serializers/banter_message_serializer'
27
- autoload :SubscriberSerializer, 'banter/web/serializers/subscriber_serializer'
28
- end
29
- end
30
- end
31
-
32
- require 'banter'
33
- require 'banter/web/models/banter_worker'
34
- require 'banter/web/models/banter_message'
@@ -1,85 +0,0 @@
1
- module Banter
2
- module Web
3
- class Application < Sinatra::Base
4
- set :root, File.expand_path(File.dirname(__FILE__) + "/../../../web")
5
- set :public_folder, Proc.new { "#{root}/assets" }
6
- set :views, Proc.new { "#{root}/views" }
7
-
8
- helpers Banter::Web::Helpers
9
-
10
- get '/' do
11
- redirect "#{root_path}dashboard"
12
- end
13
-
14
- get '/dashboard*', provides: :html do
15
- haml :index
16
- end
17
-
18
- get '/workers.json' do
19
- content_type :json
20
- workers = BanterWorker.running.ordered.map { |w| serialize_worker(w) }
21
- { workers: workers }.to_json
22
- end
23
-
24
- get '/workers/:id.json' do
25
- content_type :json
26
- worker = BanterWorker.find(params[:id])
27
- { worker: serialize_worker(worker) }.to_json
28
- end
29
-
30
- get '/messages/:message_id.json' do
31
- content_type :json
32
- message = BanterMessage.find(params[:message_id])
33
- {
34
- message: serialize_message(message, true)
35
- }.to_json
36
- end
37
-
38
- get '/messages.json' do
39
- content_type :json
40
- offset = 0
41
- worker = nil
42
- offset = 50 * (params[:page].to_i - 1) if params[:page]
43
- messages = BanterMessage.ordered.limit(50).offset(offset)
44
- if params[:worker_id].present?
45
- worker = BanterWorker.find(params[:worker_id])
46
- messages = messages.where(worker_id: worker.id).ordered
47
- end
48
-
49
- if params[:subscriber].present?
50
- messages = messages.where(subscriber_class: params[:subscriber])
51
- end
52
-
53
- hash = {
54
- messages: messages.map { |m| serialize_message(m, true) }
55
- }
56
- hash[:worker] = serialize_worker(worker) if worker
57
- hash.to_json
58
- end
59
-
60
- get '/subscribers.json' do
61
- content_type :json
62
- {
63
- subscribers: BanterWorker.subscribers.map { |s| serialize_subscriber(s) }
64
- }.to_json
65
- end
66
-
67
- private
68
-
69
- def serialize_message(message, include_worker = false)
70
- Banter::Web::Serializers::BanterMessageSerializer.new(message).to_hash.tap do |hash|
71
- hash[:worker] = serialize_worker(message.worker) if include_worker
72
- end
73
- end
74
-
75
- def serialize_worker(worker)
76
- Banter::Web::Serializers::BanterWorkerSerializer.new(worker).to_hash
77
- end
78
-
79
- def serialize_subscriber(subscriber)
80
- Banter::Web::Serializers::SubscriberSerializer.new(subscriber).to_hash
81
- end
82
-
83
- end
84
- end
85
- end
@@ -1,13 +0,0 @@
1
- module Banter
2
- module Web
3
- module Helpers
4
- def root_path(path = nil)
5
- "#{env['SCRIPT_NAME']}/#{path}"
6
- end
7
-
8
- def dashboard_path(path = nil)
9
- root_path("dashboard/#{path}")
10
- end
11
- end
12
- end
13
- end
@@ -1,124 +0,0 @@
1
- class BanterMessage
2
- include Mongoid::Document
3
-
4
- field :subscriber_class, type: String
5
- field :queue_name, type: String
6
- field :subscribed_key, type: String
7
- field :payload_key, type: String
8
- field :routing_data
9
- field :properties
10
- field :payload
11
- field :context
12
- field :started_at, type: Time
13
- field :done_at, type: Time
14
- field :status, type: String
15
- field :error_message, type: String
16
- field :error_backtrace
17
- field :worker_id
18
- field :progress_at, type: Integer
19
- field :progress_total, type: Integer
20
- field :progress
21
-
22
- STATUS_STARTED = 'started'
23
- STATUS_SUCCESS = 'success'
24
- STATUS_ERROR = 'error'
25
- STATUS_VALIDATION_FAILED = 'validation_failed'
26
-
27
- cattr_reader :current
28
-
29
- scope :ordered, ->() { order_by(:started_at.desc) }
30
- scope :for_subscriber, ->(subscriber) { where(subscriber_class: subscriber) }
31
- scope :successful, ->() { where(status: STATUS_SUCCESS) }
32
- scope :errored, ->() { where(status: STATUS_ERROR) }
33
- scope :validation_failed, ->() { where(status: STATUS_VALIDATION_FAILED) }
34
- scope :started, ->() { where(status: STATUS_STARTED) }
35
-
36
- # Creates a BanterMessage to record a message that is received by a subscriber.
37
- # It records the created message as BanterMessage.current
38
- # @param [Subscriber] subscriber_class
39
- # @param [Banter::Server::ClientQueueListener] worker
40
- # @param [Object] payload
41
- def self.message_received(subscriber_class, worker, payload)
42
- return unless BanterWorker.current
43
-
44
- obj = new(
45
- subscriber_class: subscriber_class.name,
46
- queue_name: subscriber_class.subscribed_queue,
47
- subscribed_key: subscriber_class.subscribed_key,
48
- payload_key: worker.routing_key,
49
- # routing_data: worker.delivery_routing_data.to_hash,
50
- # properties: worker.delivery_properties.to_hash,
51
- payload: payload,
52
- context: worker.context,
53
- started_at: Time.now,
54
- status: STATUS_STARTED,
55
- worker_id: BanterWorker.current.id
56
- )
57
-
58
- obj.save!
59
- @@current = obj
60
- BanterWorker.record_current!(obj)
61
- end
62
-
63
- # Records the current message as successful. Clears the BanterMessage.current
64
- def self.message_successful
65
- current.status = STATUS_SUCCESS
66
- current.done_at = Time.now
67
- current.save!
68
- BanterWorker.clear_current_message!(true)
69
- @@current = nil
70
- end
71
-
72
- # Records the current message as errored or validation failed with error message. Clears the BanterMessage.current
73
- # @param [String] error_message
74
- # @param [String] status
75
- def self.message_failed(error, status)
76
- current.status = status
77
- current.done_at = Time.now
78
- current.error_message = error.message
79
- current.error_backtrace = error.backtrace
80
- current.save!
81
- BanterWorker.clear_current_message!(false)
82
- @@current = nil
83
- end
84
-
85
- # Records the current progress as a number for the current message.
86
- # @param [Integer] num Current progress
87
- def self.update_progress_at(num)
88
- return unless current
89
- current.progress_at = num
90
- current.save!
91
- end
92
-
93
- # Records the number of objects expected to be processed for the current message.
94
- # @param [Integer] num Total number of objects expected to be processed.
95
- def self.update_progress_total(num)
96
- return unless current
97
- current.progress_total = num
98
- current.save!
99
- end
100
-
101
- # @param [Object] object Any object that indicates the progress of the message
102
- def self.update_progress(object)
103
- return unless current
104
- current.progress = object
105
- current.save!
106
- end
107
-
108
- def executing?
109
- self.status == STATUS_STARTED
110
- end
111
-
112
- def succeeded?
113
- self.status == STATUS_SUCCESS
114
- end
115
-
116
- def failed?
117
- self.status == STATUS_ERROR || self.status == STATUS_VALIDATION_FAILED
118
- end
119
-
120
- # @return [BanterWorker] The worker that is responsible for executing the current message
121
- def worker
122
- @worker ||= BanterWorker.find(self['worker_id'].to_s)
123
- end
124
- end
@@ -1,72 +0,0 @@
1
- class BanterWorker
2
- include Mongoid::Document
3
- field :process_name, type: String
4
- field :pid, type: Integer
5
- field :worker_classes
6
- field :hostname, type: String
7
- field :started_at, type: Time
8
- field :stopped_at, type: Time
9
- field :current_message
10
- field :job_count, type: Integer, default: 0
11
- field :success_count, type: Integer, default: 0
12
- field :failed_count, type: Integer, default: 0
13
-
14
- cattr_reader :current
15
-
16
- scope :running, ->() { where(:stopped_at => nil) }
17
- scope :ordered, ->() { order_by(:started_at.desc) }
18
-
19
- # @param [String] process_name
20
- # @param [String] process_pid
21
- # @param [String] hostname
22
- # @param [Array(Subscriber)] workers The subscriber classes that are being started by this worker
23
- def self.worker_started
24
- server_instance = Banter::Server::SubscriberServer.instance
25
- worker = new(process_name: server_instance.process_name,
26
- pid: server_instance.pid,
27
- hostname: server_instance.hostname,
28
- started_at: Time.now,
29
- worker_classes: Array.wrap(server_instance.workers).map(&:worker_class).map(&:name))
30
- worker.save!
31
- @@current = worker
32
- worker
33
- end
34
-
35
- def self.worker_stopped
36
- current.try(:stop!)
37
- @@current = nil
38
- end
39
-
40
- # @return [Array] Unique subscriber classes
41
- def self.subscribers
42
- distinct("worker_classes")
43
- end
44
-
45
- # @param [BanterMessage] banter_message Message that is currently being executed
46
- def self.record_current!(banter_message)
47
- current.current_message = banter_message.attributes
48
- current.save!
49
- end
50
-
51
- # Clears the current message key for the worker
52
- # @param [Boolean] success Indicate whether the job was successful or not
53
- def self.clear_current_message!(success = true)
54
- current.current_message = nil
55
- current.job_count += 1
56
- if success
57
- current.success_count += 1
58
- else
59
- current.failed_count += 1
60
- end
61
- current.save!
62
- end
63
-
64
- def executing?
65
- current_message.present?
66
- end
67
-
68
- def stop!
69
- self.stopped_at = Time.now
70
- save!
71
- end
72
- end
@@ -1,35 +0,0 @@
1
- module Banter
2
- module Web
3
-
4
- module Serializers
5
- class BanterMessageSerializer
6
- attr_accessor :message
7
-
8
- def initialize(message)
9
- @message = message
10
- end
11
-
12
- def to_hash
13
- {
14
- id: message.id.to_s,
15
- subscriber_class: message.subscriber_class,
16
- queue_name: message.queue_name,
17
- subscribed_key: message.subscribed_key,
18
- payload_key: message.payload_key,
19
- payload: message.payload,
20
- context: message.context,
21
- started_at: message.started_at,
22
- done_at: message.done_at,
23
- status: message.status,
24
- error_message: message.error_message,
25
- error_backtrace: message.error_backtrace,
26
- worker_id: message.worker_id,
27
- progress_total: message.progress_total,
28
- progress_at: message.progress_at,
29
- progress: message.progress
30
- }
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,40 +0,0 @@
1
- module Banter
2
- module Web
3
-
4
- module Serializers
5
- class BanterWorkerSerializer
6
- attr_accessor :worker
7
-
8
- def initialize(worker)
9
- @worker = worker
10
- end
11
-
12
- def to_hash
13
- {
14
- id: worker.id.to_s,
15
- process_name: worker.process_name,
16
- pid: worker.pid,
17
- started_at: worker.started_at,
18
- stopped_at: worker.stopped_at,
19
- worker_classes: Array.wrap(worker.worker_classes),
20
- hostname: worker.hostname,
21
- current_message: current_message_serialized,
22
- job_count: worker.job_count,
23
- success_count: worker.success_count,
24
- failed_count: worker.failed_count
25
- }
26
- end
27
-
28
- def current_message_serialized
29
- return if worker.current_message.blank?
30
- worker.current_message.tap do |hash|
31
- _id = hash.delete('_id')
32
- if _id
33
- hash["id"] = _id.to_s
34
- end
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,26 +0,0 @@
1
- module Banter
2
- module Web
3
-
4
- module Serializers
5
- class SubscriberSerializer
6
- attr_accessor :subscriber_class_name
7
-
8
- def initialize(subscriber_class_name)
9
- @subscriber_class_name = subscriber_class_name
10
- end
11
-
12
- def to_hash
13
- messages = BanterMessage.for_subscriber(subscriber_class_name)
14
- {
15
- class_name: subscriber_class_name,
16
- total: messages.count,
17
- success_count: messages.successful.count,
18
- started_count: messages.started.count,
19
- errored_count: messages.errored.count,
20
- validation_failed_count: messages.validation_failed.count
21
- }
22
- end
23
- end
24
- end
25
- end
26
- end
@@ -1,181 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Banter::Web::Application do
4
- let(:response_json) { JSON.parse(last_response.body) }
5
- describe 'GET /' do
6
- before { get '/' }
7
- it 'redirects to dashboard' do
8
- expect(last_response.status).to eq 302
9
- end
10
-
11
- it { expect(last_response.location).to include("/dashboard") }
12
- end
13
-
14
- describe "GET /dashboard*" do
15
- context "GET /dashboard" do
16
- before { get '/dashboard' }
17
- it "is successful" do
18
- expect(last_response.status).to be(200)
19
- end
20
- it "includes dashboardApp" do
21
- expect(last_response.body).to include('dashboardApp')
22
- end
23
- end
24
-
25
- context "GET /dashboard/workers/123" do
26
- before { get '/dashboard/workers/123' }
27
- it "is successful" do
28
- expect(last_response.status).to be(200)
29
- end
30
- it "includes dashboardApp" do
31
- expect(last_response.body).to include('dashboardApp')
32
- end
33
- end
34
-
35
- context "GET /dashboard/wtf" do
36
- before { get '/dashboard/wtf' }
37
- it "is successful" do
38
- expect(last_response.status).to be(200)
39
- end
40
- it "includes dashboardApp" do
41
- expect(last_response.body).to include('dashboardApp')
42
- end
43
- end
44
- end
45
-
46
- describe "GET /workers.json" do
47
- let!(:worker_1) { FactoryGirl.create(:banter_worker) }
48
- let!(:worker_2) { FactoryGirl.create(:banter_worker) }
49
- let!(:worker_3) { FactoryGirl.create(:banter_worker, :stopped) }
50
- let(:workers_json) { response_json['workers'] }
51
-
52
- before { get "/workers.json" }
53
- it 'is successful' do
54
- expect(last_response.status).to be(200)
55
- end
56
-
57
- it "includes only running workers" do
58
- expect(workers_json.size).to eq(2)
59
- end
60
-
61
- it do
62
- worker_ids = workers_json.map { |worker| worker['id'] }
63
- expect(worker_ids).to match_array([worker_1.id.to_s, worker_2.id.to_s])
64
- end
65
- end
66
-
67
- describe "GET /workers/:worker_id.json" do
68
- let(:worker_json) { response_json['worker'] }
69
-
70
- def self.it_works
71
- before { get "/workers/#{worker.id.to_s}.json" }
72
- it 'is successful' do
73
- expect(last_response.status).to be 200
74
- end
75
-
76
- it 'includes worker data' do
77
- expect(worker_json['id']).to eq(worker.id.to_s)
78
- end
79
- end
80
-
81
- describe "alive worker" do
82
- let(:worker) { FactoryGirl.create(:banter_worker) }
83
- it_works
84
- end
85
-
86
- describe "dead worker" do
87
- let(:worker) { FactoryGirl.create(:banter_worker, :stopped) }
88
- it_works
89
- end
90
- end
91
-
92
- describe "GET /messages/:message_id.json" do
93
- let(:message_json) { response_json['message'] }
94
- let(:message) { FactoryGirl.create(:banter_message) }
95
-
96
- before { get "/messages/#{message.id.to_s}.json" }
97
-
98
- it 'is successful' do
99
- expect(last_response.status).to be 200
100
- end
101
-
102
- it 'includes message' do
103
- expect(message_json['id']).to eq(message.id.to_s)
104
- end
105
- end
106
-
107
- describe "GET /messages.json" do
108
- let(:messages_json) { response_json['messages'] }
109
- let(:worker_id) { nil }
110
-
111
- def includes_messages(*messages)
112
- message_ids = messages_json.map { |m| m['id']}
113
- expect(message_ids).to match_array(messages.map(&:id).map(&:to_s))
114
- end
115
-
116
- context "all messages" do
117
- let!(:message_1) { FactoryGirl.create(:banter_message) }
118
- let!(:message_2) { FactoryGirl.create(:banter_message) }
119
- let!(:message_3) { FactoryGirl.create(:banter_message, :errored) }
120
- before { get "/messages.json?worker_id=#{worker_id}" }
121
-
122
- it 'is successful' do
123
- expect(last_response.status).to be 200
124
- end
125
-
126
- it 'includes messages' do
127
- includes_messages(message_1, message_2, message_3)
128
- end
129
- end
130
-
131
- context "by worker" do
132
- let(:worker) { FactoryGirl.create(:banter_worker) }
133
- let(:worker_id) { worker.id }
134
- let!(:message_1) { FactoryGirl.create(:banter_message, worker_id: worker.id ) }
135
- let!(:message_2) { FactoryGirl.create(:banter_message, worker_id: worker.id) }
136
- let!(:message_3) { FactoryGirl.create(:banter_message, :errored, worker_id: worker.id) }
137
- let!(:message_4) { FactoryGirl.create(:banter_message) }
138
- before { get "/messages.json?worker_id=#{worker_id}" }
139
- it 'is successful' do
140
- expect(last_response.status).to be 200
141
- end
142
-
143
- it 'includes messages' do
144
- includes_messages(message_1, message_2, message_3)
145
- end
146
- end
147
-
148
- context "by subscriber" do
149
- let(:subscriber) { 'MyTestClass' }
150
- let!(:message_1) { FactoryGirl.create(:banter_message, subscriber_class: subscriber ) }
151
- let!(:message_2) { FactoryGirl.create(:banter_message, subscriber_class: subscriber) }
152
- let!(:message_3) { FactoryGirl.create(:banter_message, :errored) }
153
- let!(:message_4) { FactoryGirl.create(:banter_message, :errored, subscriber_class: subscriber) }
154
- before { get "/messages.json?subscriber=#{subscriber}" }
155
- it 'is successful' do
156
- expect(last_response.status).to be 200
157
- end
158
-
159
- it 'includes messages' do
160
- includes_messages(message_1, message_2, message_4)
161
- end
162
- end
163
- end
164
-
165
- describe "GET /subscribers.json" do
166
- let!(:worker_1) { FactoryGirl.create(:banter_worker, worker_classes: [ 'FooWorker1', 'BarWorker2'])}
167
- let!(:worker_2) { FactoryGirl.create(:banter_worker, :stopped, worker_classes: [ 'FooWorker2', 'BarWorker1'])}
168
-
169
- let(:subscribers_json) { response_json['subscribers'] }
170
-
171
- before { get '/subscribers.json'}
172
- it 'is successful' do
173
- expect(last_response.status).to be 200
174
- end
175
-
176
- it 'includes message' do
177
- subscribers = subscribers_json.map { |s| s['class_name']}.sort
178
- expect(subscribers).to eq(['BarWorker1', 'BarWorker2', 'FooWorker1', 'FooWorker2'])
179
- end
180
- end
181
- end