banter 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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