banter 0.8.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/Rakefile +29 -0
- data/lib/banter/subscriber.rb +18 -0
- data/lib/banter/version.rb +1 -1
- data/lib/banter/web.rb +6 -0
- data/lib/banter/web/application.rb +62 -13
- data/lib/banter/web/helpers.rb +6 -2
- data/lib/banter/web/models/banter_message.rb +45 -5
- data/lib/banter/web/models/banter_worker.rb +5 -0
- data/lib/banter/web/serializers/banter_message_serializer.rb +34 -0
- data/lib/banter/web/serializers/banter_worker_serializer.rb +30 -0
- data/lib/banter/web/serializers/subscriber_serializer.rb +26 -0
- data/spec/banter/subscriber_spec.rb +82 -1
- data/spec/banter/web/application_spec.rb +173 -2
- data/spec/factories/banter_messages.rb +28 -0
- data/spec/spec_helper.rb +0 -1
- data/web/assets/javascripts/banter.js +449 -0
- data/web/assets/javascripts/dashboard_app/app.coffee +4 -0
- data/web/assets/javascripts/dashboard_app/controllers/message_controller.coffee +27 -0
- data/web/assets/javascripts/dashboard_app/controllers/messages_controller.coffee +57 -0
- data/web/assets/javascripts/dashboard_app/controllers/subscribers_controller.coffee +25 -0
- data/web/assets/javascripts/dashboard_app/controllers/worker_controller.coffee +30 -0
- data/web/assets/javascripts/dashboard_app/controllers/workers_list_controller.coffee +28 -0
- data/web/assets/javascripts/dashboard_app/routes.coffee +82 -0
- data/web/assets/javascripts/dashboard_app/services/common_methods_service.coffee +6 -0
- data/web/assets/javascripts/dashboard_app/services/message_methods_service.coffee +18 -0
- data/web/assets/javascripts/dashboard_app/services/messages_service.coffee +17 -0
- data/web/assets/javascripts/dashboard_app/services/subscribers_service.coffee +8 -0
- data/web/assets/javascripts/dashboard_app/services/worker_methods_service.coffee +11 -0
- data/web/assets/javascripts/dashboard_app/services/worker_service.coffee +15 -0
- data/web/assets/javascripts/ng-prettyjson.js +15 -0
- data/web/assets/stylesheets/banter.css +13 -1
- data/web/views/_message.haml +59 -0
- data/web/views/_messages.haml +77 -0
- data/web/views/_subscribers.haml +22 -0
- data/web/views/_worker.haml +52 -0
- data/web/views/_workers_list.haml +35 -0
- data/web/views/index.haml +16 -29
- data/web/views/layout.haml +16 -10
- metadata +28 -7
- data/web/views/message.haml +0 -52
- data/web/views/messages.haml +0 -20
- data/web/views/subscribers.haml +0 -17
- data/web/views/worker.haml +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 51871d5d895dbf72454f67a614a14aa8af5cd6ee
|
4
|
+
data.tar.gz: 37321de3cd2605a5b7d99ffce5e979167b7597df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9dba68030359665879dbd785c613523282f97a5b91a721824c91dd4375e87a8299e39f68af759595ffe5963b584b7981b526a7a5d0071f05b2a4a02cc1c95669
|
7
|
+
data.tar.gz: 16ba97865260c2e81463d374f1c4806cf17ad65628022aa6abc90da7e6d8af8741a0166afd67887f59a5d87c5f9f8dc53ccb989e7609f376e379212d5707173a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -5,3 +5,32 @@ begin
|
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
6
|
task :default => :spec
|
7
7
|
end
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'coffee-script'
|
11
|
+
|
12
|
+
namespace :js do
|
13
|
+
def add_javascript(js_file, output_file)
|
14
|
+
js_file_souce = File.read("#{File.dirname(__FILE__)}/web/assets/javascripts/#{js_file}.js")
|
15
|
+
output_file.puts js_file_souce
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "compile coffee-scripts from ./assets/javascripts"
|
19
|
+
task :compile do
|
20
|
+
source = "#{File.dirname(__FILE__)}/web/assets/javascripts/**/*.coffee"
|
21
|
+
target = "#{File.dirname(__FILE__)}/web/assets/javascripts/banter.js"
|
22
|
+
file = File.open(target, 'w+')
|
23
|
+
|
24
|
+
add_javascript("ng-prettyjson", file)
|
25
|
+
|
26
|
+
Dir.glob(source) do |cf|
|
27
|
+
puts cf
|
28
|
+
file.puts CoffeeScript.compile File.read(cf)
|
29
|
+
end
|
30
|
+
|
31
|
+
file.close
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
data/lib/banter/subscriber.rb
CHANGED
@@ -90,6 +90,24 @@ module Banter
|
|
90
90
|
|
91
91
|
private
|
92
92
|
|
93
|
+
# @param [Integer] number The expected number of total objects that may be processed due to the message
|
94
|
+
def total(number)
|
95
|
+
return unless Banter::Configuration.web_enabled
|
96
|
+
BanterMessage.update_progress_total(number)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param [Integer] number The current progress of the execution of the message
|
100
|
+
def at(number)
|
101
|
+
return unless Banter::Configuration.web_enabled
|
102
|
+
BanterMessage.update_progress_at(number)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param [Object] object An object that indicates the current progress of the message
|
106
|
+
def progress(object)
|
107
|
+
return unless Banter::Configuration.web_enabled
|
108
|
+
BanterMessage.update_progress(object)
|
109
|
+
end
|
110
|
+
|
93
111
|
def self.validate_routing_key_name(key)
|
94
112
|
return true if key.blank?
|
95
113
|
key.match(/\A([a-z]+\.?)*([a-z]+)\Z/).present?
|
data/lib/banter/version.rb
CHANGED
data/lib/banter/web.rb
CHANGED
@@ -20,6 +20,12 @@ module Banter
|
|
20
20
|
module Web
|
21
21
|
autoload :Application, 'banter/web/application'
|
22
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
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
@@ -8,29 +8,78 @@ module Banter
|
|
8
8
|
helpers Banter::Web::Helpers
|
9
9
|
|
10
10
|
get '/' do
|
11
|
-
|
12
|
-
haml :index, locals: { workers: @workers }
|
11
|
+
redirect "#{root_path}dashboard"
|
13
12
|
end
|
14
13
|
|
15
|
-
get '/
|
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
|
16
26
|
worker = BanterWorker.find(params[:id])
|
17
|
-
|
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
|
18
58
|
end
|
19
59
|
|
20
|
-
get '/
|
21
|
-
|
22
|
-
|
60
|
+
get '/subscribers.json' do
|
61
|
+
content_type :json
|
62
|
+
{
|
63
|
+
subscribers: BanterWorker.subscribers.map { |s| serialize_subscriber(s) }
|
64
|
+
}.to_json
|
23
65
|
end
|
24
66
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
29
73
|
end
|
30
74
|
|
31
|
-
|
32
|
-
|
75
|
+
def serialize_worker(worker)
|
76
|
+
Banter::Web::Serializers::BanterWorkerSerializer.new(worker).to_hash
|
33
77
|
end
|
78
|
+
|
79
|
+
def serialize_subscriber(subscriber)
|
80
|
+
Banter::Web::Serializers::SubscriberSerializer.new(subscriber).to_hash
|
81
|
+
end
|
82
|
+
|
34
83
|
end
|
35
84
|
end
|
36
85
|
end
|
data/lib/banter/web/helpers.rb
CHANGED
@@ -14,17 +14,29 @@ class BanterMessage
|
|
14
14
|
field :status, type: String
|
15
15
|
field :error_message, type: String
|
16
16
|
field :worker_id
|
17
|
-
|
17
|
+
field :progress_at, type: Integer
|
18
|
+
field :progress_total, type: Integer
|
19
|
+
field :progress
|
18
20
|
|
19
|
-
STATUS_STARTED
|
20
|
-
STATUS_SUCCESS
|
21
|
-
STATUS_ERROR
|
22
|
-
STATUS_VALIDATION_FAILED
|
21
|
+
STATUS_STARTED = 'started'
|
22
|
+
STATUS_SUCCESS = 'success'
|
23
|
+
STATUS_ERROR = 'error'
|
24
|
+
STATUS_VALIDATION_FAILED = 'validation_failed'
|
23
25
|
|
24
26
|
cattr_reader :current
|
25
27
|
|
26
28
|
scope :ordered, ->() { order_by(:started_at.desc) }
|
29
|
+
scope :for_subscriber, ->(subscriber) { where(subscriber_class: subscriber) }
|
30
|
+
scope :successful, ->() { where(status: STATUS_SUCCESS) }
|
31
|
+
scope :errored, ->() { where(status: STATUS_ERROR) }
|
32
|
+
scope :validation_failed, ->() { where(status: STATUS_VALIDATION_FAILED) }
|
33
|
+
scope :started, ->() { where(status: STATUS_STARTED) }
|
27
34
|
|
35
|
+
# Creates a BanterMessage to record a message that is received by a subscriber.
|
36
|
+
# It records the created message as BanterMessage.current
|
37
|
+
# @param [Subscriber] subscriber_class
|
38
|
+
# @param [Banter::Server::ClientQueueListener] worker
|
39
|
+
# @param [Object] payload
|
28
40
|
def self.message_received(subscriber_class, worker, payload)
|
29
41
|
return unless BanterWorker.current
|
30
42
|
|
@@ -47,6 +59,7 @@ class BanterMessage
|
|
47
59
|
BanterWorker.record_current!(obj)
|
48
60
|
end
|
49
61
|
|
62
|
+
# Records the current message as successful. Clears the BanterMessage.current
|
50
63
|
def self.message_successful
|
51
64
|
current.status = STATUS_SUCCESS
|
52
65
|
current.done_at = Time.now
|
@@ -55,6 +68,9 @@ class BanterMessage
|
|
55
68
|
@@current = nil
|
56
69
|
end
|
57
70
|
|
71
|
+
# Records the current message as errored or validation failed with error message. Clears the BanterMessage.current
|
72
|
+
# @param [String] error_message
|
73
|
+
# @param [String] status
|
58
74
|
def self.message_failed(error_message, status)
|
59
75
|
current.status = status
|
60
76
|
current.done_at = Time.now
|
@@ -64,6 +80,29 @@ class BanterMessage
|
|
64
80
|
@@current = nil
|
65
81
|
end
|
66
82
|
|
83
|
+
# Records the current progress as a number for the current message.
|
84
|
+
# @param [Integer] num Current progress
|
85
|
+
def self.update_progress_at(num)
|
86
|
+
return unless current
|
87
|
+
current.progress_at = num
|
88
|
+
current.save!
|
89
|
+
end
|
90
|
+
|
91
|
+
# Records the number of objects expected to be processed for the current message.
|
92
|
+
# @param [Integer] num Total number of objects expected to be processed.
|
93
|
+
def self.update_progress_total(num)
|
94
|
+
return unless current
|
95
|
+
current.progress_total = num
|
96
|
+
current.save!
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param [Object] object Any object that indicates the progress of the message
|
100
|
+
def self.update_progress(object)
|
101
|
+
return unless current
|
102
|
+
current.progress = object
|
103
|
+
current.save!
|
104
|
+
end
|
105
|
+
|
67
106
|
def executing?
|
68
107
|
self.status == STATUS_STARTED
|
69
108
|
end
|
@@ -76,6 +115,7 @@ class BanterMessage
|
|
76
115
|
self.status == STATUS_ERROR || self.status == STATUS_VALIDATION_FAILED
|
77
116
|
end
|
78
117
|
|
118
|
+
# @return [BanterWorker] The worker that is responsible for executing the current message
|
79
119
|
def worker
|
80
120
|
@worker ||= BanterWorker.find(self['worker_id'].to_s)
|
81
121
|
end
|
@@ -37,6 +37,11 @@ class BanterWorker
|
|
37
37
|
@@current = nil
|
38
38
|
end
|
39
39
|
|
40
|
+
# @return [Array] Unique subscriber classes
|
41
|
+
def self.subscribers
|
42
|
+
distinct("worker_classes")
|
43
|
+
end
|
44
|
+
|
40
45
|
# @param [BanterMessage] banter_message Message that is currently being executed
|
41
46
|
def self.record_current!(banter_message)
|
42
47
|
current.current_message = banter_message.attributes
|
@@ -0,0 +1,34 @@
|
|
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
|
+
worker_id: message.worker_id,
|
26
|
+
progress_total: message.progress_total,
|
27
|
+
progress_at: message.progress_at,
|
28
|
+
progress: message.progress
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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: worker.current_message,
|
22
|
+
job_count: worker.job_count,
|
23
|
+
success_count: worker.success_count,
|
24
|
+
failed_count: worker.failed_count
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -16,7 +16,88 @@ describe Banter::Subscriber do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
describe
|
19
|
+
describe '#at' do
|
20
|
+
let(:subscriber) { Banter::Subscriber.new({}, {}, {}) }
|
21
|
+
context 'web not enabled' do
|
22
|
+
before do
|
23
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(false)
|
24
|
+
subscriber.send(:at, 123)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'doesnt do a thing' do
|
28
|
+
expect(BanterMessage.count).to eq(0)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'web enabled' do
|
33
|
+
let(:banter_message) { FactoryGirl.create(:banter_message)}
|
34
|
+
before do
|
35
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(true)
|
36
|
+
allow(BanterMessage).to receive(:current).and_return(banter_message)
|
37
|
+
subscriber.send(:at, 123)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'updates progress_at on current message' do
|
41
|
+
expect(banter_message.progress_at).to eq(123)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#total' do
|
47
|
+
let(:subscriber) { Banter::Subscriber.new({}, {}, {}) }
|
48
|
+
context 'web not enabled' do
|
49
|
+
before do
|
50
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(false)
|
51
|
+
subscriber.send(:total, 1230)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'doesnt do a thing' do
|
55
|
+
expect(BanterMessage.count).to eq(0)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'web enabled' do
|
60
|
+
let(:banter_message) { FactoryGirl.create(:banter_message)}
|
61
|
+
before do
|
62
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(true)
|
63
|
+
allow(BanterMessage).to receive(:current).and_return(banter_message)
|
64
|
+
subscriber.send(:total, 1230)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'updates progress_at on current message' do
|
68
|
+
expect(banter_message.progress_total).to eq(1230)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#progress' do
|
74
|
+
let(:subscriber) { Banter::Subscriber.new({}, {}, {}) }
|
75
|
+
context 'web not enabled' do
|
76
|
+
before do
|
77
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(false)
|
78
|
+
subscriber.send(:progress, foo: 'bar')
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'doesnt do a thing' do
|
82
|
+
expect(BanterMessage.count).to eq(0)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'web enabled' do
|
87
|
+
let(:banter_message) { FactoryGirl.create(:banter_message)}
|
88
|
+
before do
|
89
|
+
allow(Banter::Configuration).to receive(:web_enabled).and_return(true)
|
90
|
+
allow(BanterMessage).to receive(:current).and_return(banter_message)
|
91
|
+
subscriber.send(:progress, foo: 'bar')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'updates progress_at on current message' do
|
95
|
+
expect(banter_message.progress).to eq(foo: 'bar')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe ".validates_payload_with" do
|
20
101
|
before do
|
21
102
|
validators.each do |validator|
|
22
103
|
Klass.validates_payload_with validator
|