utracker-mongodb 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/examples/draw_services.rb +8 -0
- data/examples/services.dot +13 -0
- data/examples/services.dot.png +0 -0
- data/examples/services.rb +112 -0
- data/lib/utracker/mongodb.rb +1 -0
- data/lib/utracker/mongodb/drawer.rb +104 -0
- data/lib/utracker/mongodb/logger.rb +21 -26
- data/lib/utracker/mongodb/version.rb +1 -1
- data/spec/utracker/mongodb/drawer_spec.rb +46 -0
- data/utracker-mongodb.gemspec +1 -1
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 766bf8d7ee5c34e57bf403ad040952cb5f8d91ec
|
4
|
+
data.tar.gz: b592b42578fcc34b9f6a2d42c16590a6b4c9d847
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b43fee3b6fc379c10f36340a58038ea713a2b8c19e5675ed2d4d73c20b3fa457c7f7150e60dbe14a1594fd2d34459e8cdd686e0a84d7337d03c787b9e8c3a3ef
|
7
|
+
data.tar.gz: 8fe68fbf330be9659fb2776e22c87fef13ab18ccb4f0ca3dbffcc71bc1f2f34ea181ca16267bc76cbab53898d766972b76d7072de3b02267318a962dfd674c12
|
data/README.md
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
[![Build Status](https://travis-ci.org/nicoolas25/micro-tracker-mongodb.svg)](https://travis-ci.org/nicoolas25/micro-tracker-mongodb)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb/badges/gpa.svg)](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb)
|
5
5
|
[![Test Coverage](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb/badges/coverage.svg)](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/utracker-mongodb.svg)](http://badge.fury.io/rb/utracker-mongodb)
|
6
7
|
|
7
8
|
This is a MongoDB backend for the [utracker][utracker] gem.
|
8
9
|
|
Binary file
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#
|
2
|
+
# In this example 3 bots are sending each other messages. Each bot run in a
|
3
|
+
# separated thread. A bot follows this behaviour:
|
4
|
+
#
|
5
|
+
# 1. Check its inbox (queue)
|
6
|
+
# 2. If there is no message in the queue, he sends a message to another bot
|
7
|
+
# 3. If there is some message in the queue he reads them one by one
|
8
|
+
# 4. For each read message, the robot can send a message to another bot
|
9
|
+
# 5. The bot rests
|
10
|
+
#
|
11
|
+
# For the steps 2, 3 and 4 the bot will log the following events:
|
12
|
+
#
|
13
|
+
# - seeding
|
14
|
+
# - handle
|
15
|
+
# - reply
|
16
|
+
#
|
17
|
+
|
18
|
+
|
19
|
+
lib = File.expand_path('../lib', __FILE__)
|
20
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
21
|
+
|
22
|
+
require 'thread'
|
23
|
+
require 'utracker'
|
24
|
+
require 'utracker/mongodb'
|
25
|
+
|
26
|
+
BOTS = {
|
27
|
+
"alice" => nil,
|
28
|
+
"bob" => nil,
|
29
|
+
"carl" => nil,
|
30
|
+
}
|
31
|
+
|
32
|
+
class Bot
|
33
|
+
attr_accessor :queue
|
34
|
+
|
35
|
+
def initialize(name)
|
36
|
+
@name = name
|
37
|
+
@queue = Queue.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
loop do
|
42
|
+
consume_queue
|
43
|
+
rest
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def thread
|
48
|
+
Thread.current
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def consume_queue
|
54
|
+
if @queue.empty?
|
55
|
+
if target = others.sample
|
56
|
+
message = Utracker::Message.pack("I have nothing to do...")
|
57
|
+
target.queue.push(message.to_json)
|
58
|
+
message.log("seeding")
|
59
|
+
end
|
60
|
+
else
|
61
|
+
until @queue.empty?
|
62
|
+
serialization = @queue.pop
|
63
|
+
handle(serialization)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def handle(serialization)
|
69
|
+
message = Utracker::Message.unpack(serialization)
|
70
|
+
message.log("handle", hide_payload: true)
|
71
|
+
reply_to(message)
|
72
|
+
end
|
73
|
+
|
74
|
+
def reply_to(message)
|
75
|
+
if rand(2) == 0 && (target = others.sample)
|
76
|
+
reply = message.pack("Unleash the kraken!")
|
77
|
+
target.queue.push(reply.to_json)
|
78
|
+
reply.log("reply")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def others
|
83
|
+
BOTS.each_with_object([]) do |(name, bot), list|
|
84
|
+
list << bot if bot && name != @name
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def rest
|
89
|
+
sleep rand
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
threads = BOTS.keys.map do |name|
|
95
|
+
Thread.new do
|
96
|
+
Utracker.configure do |config|
|
97
|
+
config[:service_name] = name
|
98
|
+
config[:logger_class] = Utracker::MongoDB::Logger
|
99
|
+
end
|
100
|
+
|
101
|
+
Bot.new(name).tap do |bot|
|
102
|
+
BOTS[name] = bot
|
103
|
+
bot.run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
begin
|
109
|
+
threads.each(&:join)
|
110
|
+
rescue Interrupt
|
111
|
+
threads.each(&:terminate)
|
112
|
+
end
|
data/lib/utracker/mongodb.rb
CHANGED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
class Utracker::MongoDB::Drawer < Utracker::Drawer
|
4
|
+
attr_reader :database
|
5
|
+
|
6
|
+
def initialize(database_name: "utracker", collection_name: "entries")
|
7
|
+
@client = Mongo::MongoClient.new
|
8
|
+
@database = @client[database_name]
|
9
|
+
@collection_name = collection_name
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def build_graph
|
15
|
+
nodes.values.each do |node|
|
16
|
+
node.edges = edges_for(node)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def nodes
|
23
|
+
@nodes ||= service_names.each_with_object({}) do |service_name, directory|
|
24
|
+
directory[service_name] = Utracker::Drawer::Node.new(service_name, nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def service_names
|
29
|
+
collection.distinct('service')
|
30
|
+
end
|
31
|
+
|
32
|
+
def edges_for(node)
|
33
|
+
aggregate = edges.find { |agg| agg["_id"]["service"] == node.service }
|
34
|
+
aggregate && aggregate["edges"].map{ |service_name| nodes[service_name] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def edges
|
38
|
+
@edges ||= edge_collection.aggregate([
|
39
|
+
{ "$unwind" => "$value.handled_by" },
|
40
|
+
{ "$group" => {
|
41
|
+
"_id" => { "service" => "$value.authored_by" },
|
42
|
+
"edges" => { "$addToSet" => "$value.handled_by" },
|
43
|
+
},
|
44
|
+
},
|
45
|
+
])
|
46
|
+
end
|
47
|
+
|
48
|
+
def edge_collection
|
49
|
+
@edge_collection ||= collection.map_reduce(
|
50
|
+
EDGE_MAP_FN,
|
51
|
+
EDGE_REDUCE_FN,
|
52
|
+
out: { replace: "#{@collection_name}_drawer" }
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def collection
|
57
|
+
@collection ||= database[@collection_name]
|
58
|
+
end
|
59
|
+
|
60
|
+
EDGE_MAP_FN = <<-MAP
|
61
|
+
function() {
|
62
|
+
var value = { authored_by: this.service, handled_by: [], handled_at: {} };
|
63
|
+
value.handled_at[this.service] = this.datetime;
|
64
|
+
var key = this.uuid;
|
65
|
+
emit(key, value);
|
66
|
+
}
|
67
|
+
MAP
|
68
|
+
|
69
|
+
EDGE_REDUCE_FN = <<-REDUCE
|
70
|
+
function(key, values) {
|
71
|
+
var handled_at = {};
|
72
|
+
var handled_by = [];
|
73
|
+
var first_handled = new Date();
|
74
|
+
var first_handler;
|
75
|
+
|
76
|
+
values.forEach(function(value) {
|
77
|
+
var author = value.authored_by;
|
78
|
+
var datetime = value.handled_at[author];
|
79
|
+
|
80
|
+
if (datetime < first_handled) {
|
81
|
+
first_handler = author;
|
82
|
+
first_handled = datetime;
|
83
|
+
}
|
84
|
+
|
85
|
+
if (!(author in handled_at) || datetime < handled_at[author]) {
|
86
|
+
handled_at[author] = datetime;
|
87
|
+
}
|
88
|
+
});
|
89
|
+
|
90
|
+
for(var service in handled_at) {
|
91
|
+
if (service !== first_handler) {
|
92
|
+
handled_by.push(service);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
return {
|
97
|
+
authored_by: first_handler,
|
98
|
+
handled_by: handled_by,
|
99
|
+
handled_at: handled_at
|
100
|
+
};
|
101
|
+
}
|
102
|
+
REDUCE
|
103
|
+
|
104
|
+
end
|
@@ -1,34 +1,29 @@
|
|
1
1
|
require 'mongo'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class Logger < Utracker::Logger
|
6
|
-
attr_reader :client
|
7
|
-
attr_reader :database
|
3
|
+
class Utracker::MongoDB::Logger < Utracker::Logger
|
4
|
+
attr_reader :client, :database, :collection_name
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
protected
|
6
|
+
def initialize(database_name: "utracker", collection_name: "entries")
|
7
|
+
@client = Mongo::MongoClient.new
|
8
|
+
@database = @client[database_name]
|
9
|
+
@collection_name = collection_name
|
10
|
+
end
|
16
11
|
|
17
|
-
|
18
|
-
event_collection << {
|
19
|
-
datetime: event.datetime,
|
20
|
-
service: event.service,
|
21
|
-
description: event.description,
|
22
|
-
uuid: event.message.uuid,
|
23
|
-
parent_uuid: event.message.parent_uuid,
|
24
|
-
payload: event.payload,
|
25
|
-
}
|
26
|
-
end
|
12
|
+
protected
|
27
13
|
|
28
|
-
|
29
|
-
|
30
|
-
|
14
|
+
def write(event)
|
15
|
+
collection << {
|
16
|
+
datetime: event.datetime,
|
17
|
+
service: event.service,
|
18
|
+
description: event.description,
|
19
|
+
uuid: event.message.uuid,
|
20
|
+
parent_uuid: event.message.parent_uuid,
|
21
|
+
payload: event.payload,
|
22
|
+
}
|
23
|
+
end
|
31
24
|
|
32
|
-
|
25
|
+
def collection
|
26
|
+
@collection ||= database[@collection_name]
|
33
27
|
end
|
28
|
+
|
34
29
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
RSpec.describe Utracker::MongoDB::Drawer do
|
2
|
+
let(:instance) { described_class.new(database_name: database_name,
|
3
|
+
collection_name: collection_name) }
|
4
|
+
|
5
|
+
let(:database_name) { "utracker_test" }
|
6
|
+
let(:collection_name) { "entries" }
|
7
|
+
|
8
|
+
before { instance.database.drop_collection(collection_name) }
|
9
|
+
|
10
|
+
describe "#build_graph" do
|
11
|
+
subject { instance.__send__(:build_graph) }
|
12
|
+
it { is_expected.to eq [] }
|
13
|
+
|
14
|
+
context "after writing event via the logger" do
|
15
|
+
let(:logger) { Utracker::MongoDB::Logger.new(database_name: database_name,
|
16
|
+
collection_name: collection_name) }
|
17
|
+
|
18
|
+
let(:graph) do
|
19
|
+
node1 = Utracker::Drawer::Node.new("node1", [])
|
20
|
+
node2 = Utracker::Drawer::Node.new("node2", nil)
|
21
|
+
node1.edges << node1
|
22
|
+
[node1, node2]
|
23
|
+
end
|
24
|
+
|
25
|
+
before do
|
26
|
+
node1_event = {
|
27
|
+
datetime: Time.now,
|
28
|
+
service: "node1",
|
29
|
+
description: "sending",
|
30
|
+
message: double(parent_uuid: nil, uuid: '1'),
|
31
|
+
payload: "payload",
|
32
|
+
options: {},
|
33
|
+
}
|
34
|
+
node2_event = node1_event.merge({
|
35
|
+
datetime: Time.now,
|
36
|
+
service: "node2",
|
37
|
+
description: "receiving",
|
38
|
+
})
|
39
|
+
logger.__send__(:write, double("Event", node1_event))
|
40
|
+
logger.__send__(:write, double("Event", node2_event))
|
41
|
+
end
|
42
|
+
|
43
|
+
it { is_expected.to eq graph }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/utracker-mongodb.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_dependency "utracker"
|
20
|
+
spec.add_dependency "utracker", "~> 0.0.2"
|
21
21
|
spec.add_dependency "bson_ext"
|
22
22
|
spec.add_dependency "mongo"
|
23
23
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: utracker-mongodb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas ZERMATI
|
@@ -14,16 +14,16 @@ dependencies:
|
|
14
14
|
name: utracker
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.0.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.0.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bson_ext
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,10 +151,16 @@ files:
|
|
151
151
|
- LICENSE.txt
|
152
152
|
- README.md
|
153
153
|
- Rakefile
|
154
|
+
- examples/draw_services.rb
|
155
|
+
- examples/services.dot
|
156
|
+
- examples/services.dot.png
|
157
|
+
- examples/services.rb
|
154
158
|
- lib/utracker/mongodb.rb
|
159
|
+
- lib/utracker/mongodb/drawer.rb
|
155
160
|
- lib/utracker/mongodb/logger.rb
|
156
161
|
- lib/utracker/mongodb/version.rb
|
157
162
|
- spec/spec_helper.rb
|
163
|
+
- spec/utracker/mongodb/drawer_spec.rb
|
158
164
|
- spec/utracker/mongodb/logger_spec.rb
|
159
165
|
- utracker-mongodb.gemspec
|
160
166
|
homepage: http://github.com/nicoolas25/micro-tracker-mongodb
|
@@ -183,4 +189,5 @@ specification_version: 4
|
|
183
189
|
summary: MongoDB backend for utracker.
|
184
190
|
test_files:
|
185
191
|
- spec/spec_helper.rb
|
192
|
+
- spec/utracker/mongodb/drawer_spec.rb
|
186
193
|
- spec/utracker/mongodb/logger_spec.rb
|