utracker-mongodb 0.0.1 → 0.0.2
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/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
|
[](https://travis-ci.org/nicoolas25/micro-tracker-mongodb)
|
4
4
|
[](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb)
|
5
5
|
[](https://codeclimate.com/github/nicoolas25/micro-tracker-mongodb)
|
6
|
+
[](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
|