banter 0.8.0 → 1.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.
- 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
|