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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6681c9dc22f7c1e4da8144cf567f748e1bdfc61d
4
- data.tar.gz: b2764f1eb5460c2de25dfda57d975f1be16c9ba6
3
+ metadata.gz: 766bf8d7ee5c34e57bf403ad040952cb5f8d91ec
4
+ data.tar.gz: b592b42578fcc34b9f6a2d42c16590a6b4c9d847
5
5
  SHA512:
6
- metadata.gz: 86911d58dcb31ed8474b2ed60b7256a9e3bfc1e96b8191377a3431c559c69078fcf8449905c8366cffa1ff89cae46e48922e14ef86cea4ca60dce7f68a62286d
7
- data.tar.gz: f20705ed020be7a890933b4a746e8d518dba3138d88b99df8f8b7563775b2460e0279d7d1144d92289639be124ddc2d2591163b21a8ba3d72049f7ad77091488
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
 
@@ -0,0 +1,8 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'utracker'
5
+ require 'utracker/mongodb'
6
+
7
+ drawer = Utracker::MongoDB::Drawer.new
8
+ drawer.write_graph("examples/services.dot")
@@ -0,0 +1,13 @@
1
+ digraph message_flow {
2
+ node [style=filled fillcolor=white]
3
+ rankdir=LR
4
+ carl
5
+ carl -> alice
6
+ carl -> bob
7
+ bob
8
+ bob -> carl
9
+ bob -> alice
10
+ alice
11
+ alice -> bob
12
+ alice -> carl
13
+ }
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
@@ -1,5 +1,6 @@
1
1
  module Utracker
2
2
  module MongoDB
3
+ autoload :Drawer, 'utracker/mongodb/drawer'
3
4
  autoload :Logger, 'utracker/mongodb/logger'
4
5
  end
5
6
  end
@@ -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
- module Utracker
4
- module MongoDB
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
- def initialize(database_name: "utracker", collection_name: "entries")
10
- @client = Mongo::MongoClient.new
11
- @database = @client[database_name]
12
- @collection_name = collection_name
13
- end
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
- def write(event)
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
- def event_collection
29
- @event_collection ||= database[@collection_name]
30
- end
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
- end
25
+ def collection
26
+ @collection ||= database[@collection_name]
33
27
  end
28
+
34
29
  end
@@ -1,5 +1,5 @@
1
1
  module Utracker
2
2
  module MongoDB
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  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
@@ -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.1
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: '0'
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: '0'
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