eventus 0.3.5 → 0.3.6
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.
- data/Gemfile +1 -0
- data/Rakefile +0 -3
- data/lib/eventus/persistence/mongo.rb +76 -0
- data/lib/eventus/persistence.rb +1 -0
- data/lib/eventus/version.rb +1 -1
- data/spec/persistence/mongo_spec.rb +100 -0
- metadata +6 -9
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
module Eventus
|
4
|
+
module Persistence
|
5
|
+
class Mongo
|
6
|
+
attr_reader :db
|
7
|
+
|
8
|
+
def initialize(uri, options={})
|
9
|
+
collection_name = options.delete(:collection) || 'eventus_commits'
|
10
|
+
@db = build_db(uri, options)
|
11
|
+
@commits = db.collection(collection_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def commit(events)
|
15
|
+
seqs = events.map{|e| e['sequence']}
|
16
|
+
doc = {
|
17
|
+
_id: "#{events[0]['sid']}_#{seqs.min}",
|
18
|
+
sid: events[0]['sid'],
|
19
|
+
min: seqs.min,
|
20
|
+
max: seqs.max,
|
21
|
+
events: events,
|
22
|
+
dispatched: false
|
23
|
+
}
|
24
|
+
|
25
|
+
future = @commits.find_one({sid:doc[:sid], max:{:$gte => doc[:min]}})
|
26
|
+
raise Eventus::ConcurrencyError if future
|
27
|
+
begin
|
28
|
+
@commits.insert(doc, safe:true)
|
29
|
+
rescue ::Mongo::OperationFailure => e
|
30
|
+
raise Eventus::ConcurrencyError if e.error_code == 11000
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def load(id, min = nil)
|
35
|
+
Eventus.logger.debug "Loading stream: #{id}"
|
36
|
+
query = {sid:id}
|
37
|
+
|
38
|
+
if min
|
39
|
+
query[:max] = {:$gte => min}
|
40
|
+
end
|
41
|
+
|
42
|
+
min ||= 0
|
43
|
+
|
44
|
+
@commits.find(query).to_a
|
45
|
+
.map{|c| c['events']}
|
46
|
+
.flatten
|
47
|
+
.reject{|e| e['sequence'] < min}
|
48
|
+
.sort_by{|e| e['sequence']}
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_undispatched
|
52
|
+
commits = @commits.find(dispatched: false).to_a
|
53
|
+
if commits.length > 0
|
54
|
+
Eventus.logger.info "#{commits.length} undispatched commits loaded"
|
55
|
+
end
|
56
|
+
commits
|
57
|
+
end
|
58
|
+
|
59
|
+
def mark_dispatched(commit_id)
|
60
|
+
Eventus.logger.debug "Marking #{commit_id} dispatched"
|
61
|
+
@commits.update({_id: commit_id}, {dispatched: true})
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def build_db(uri, options={})
|
67
|
+
parts = URI.parse(uri)
|
68
|
+
raise "scheme must be mongodb, found #{parts.scheme}" unless parts.scheme == 'mongodb'
|
69
|
+
db = ::Mongo::Connection.new(parts.host, parts.port, options).db(parts.path.gsub(/^\//, ''))
|
70
|
+
db.authenticate(parts.user, parts.password) if parts.user && parts.password
|
71
|
+
db
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/eventus/persistence.rb
CHANGED
data/lib/eventus/version.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Eventus::Persistence::Mongo do
|
4
|
+
let(:persistence) { @persistence }
|
5
|
+
let(:uuid) { UUID.new }
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
@persistence = Eventus::Persistence::Mongo.new('mongodb://localhost/test')
|
9
|
+
@persistence.db.collection('eventus_commits').drop
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should store complex objects" do
|
13
|
+
id = uuid.generate :compact
|
14
|
+
o = {'a' => 'super', 'complex' => ['object', 'with', {'nested' => ['members', 'galore', 1]}]}
|
15
|
+
commit = create_commit(id, 1, o)
|
16
|
+
persistence.commit(commit)
|
17
|
+
|
18
|
+
result = persistence.load id
|
19
|
+
result[0].should == commit[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return no events when key not found" do
|
23
|
+
result = persistence.load "my_id"
|
24
|
+
result.should be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return events ordered" do
|
28
|
+
id = uuid.generate :compact
|
29
|
+
persistence.commit create_commit(id, 1, "one", "two")
|
30
|
+
persistence.commit create_commit(id, 3, "three", "four")
|
31
|
+
persistence.commit create_commit(id, 5, "five", "six")
|
32
|
+
persistence.commit create_commit(uuid.generate, 1, "cake", "batter")
|
33
|
+
|
34
|
+
result = persistence.load id
|
35
|
+
result.map{|r| r['body']}.should == ["one", "two", "three", "four", "five", "six"]
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "when events exist" do
|
39
|
+
let(:id) { uuid.generate :compact }
|
40
|
+
let(:events) { create_commit(id, 1, *(1..5)) }
|
41
|
+
before do
|
42
|
+
persistence.commit events
|
43
|
+
other_events = create_commit(uuid.generate(:compact), 1, (1..10))
|
44
|
+
persistence.commit other_events
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should load events" do
|
48
|
+
result = persistence.load id
|
49
|
+
result.length.should == events.length
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should load undispatched events" do
|
53
|
+
result = persistence.load_undispatched
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should mark an event as dispatched" do
|
57
|
+
result = persistence.load_undispatched[0]
|
58
|
+
persistence.mark_dispatched(result['_id'])
|
59
|
+
persistence.load_undispatched.any?{|c| c['_id'] == result['_id']}.should be_false
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should throw concurrency exception if the same event number is added" do
|
63
|
+
lambda {persistence.commit create_commit(id, 1, "This is taken")}.should raise_error(Eventus::ConcurrencyError)
|
64
|
+
lambda {persistence.commit create_commit(id, 2, "This is taken")}.should raise_error(Eventus::ConcurrencyError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should rollback changes on concurrency error" do
|
68
|
+
lambda {persistence.commit create_commit(id, 1, "first", "second", "third")}.should raise_error(Eventus::ConcurrencyError)
|
69
|
+
|
70
|
+
result = persistence.load id
|
71
|
+
result.should == events
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should load all events from a minimum" do
|
75
|
+
result = persistence.load id, 3
|
76
|
+
result.should == events.select {|e| e['sequence'] >= 3}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "when serialization is set" do
|
81
|
+
let(:serializer) { stub }
|
82
|
+
let(:persistence) { Eventus::Persistence::KyotoCabinet.new(:path => '%', :serializer => serializer) }
|
83
|
+
|
84
|
+
it "should use serializer" do
|
85
|
+
input = {:name => 'event'}
|
86
|
+
ser = "serialized!!"
|
87
|
+
id = uuid.generate :compact
|
88
|
+
commit = create_commit(id, 1, input)
|
89
|
+
|
90
|
+
serializer.should_receive(:serialize).with(commit[0]).and_return(ser)
|
91
|
+
serializer.should_receive(:deserialize).with(ser).and_return(input)
|
92
|
+
|
93
|
+
|
94
|
+
persistence.commit commit
|
95
|
+
result = persistence.load id
|
96
|
+
result[0].should == input
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eventus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-02-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: An Event Store
|
15
15
|
email:
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- lib/eventus/persistence.rb
|
33
33
|
- lib/eventus/persistence/in_memory.rb
|
34
34
|
- lib/eventus/persistence/kyotocabinet.rb
|
35
|
+
- lib/eventus/persistence/mongo.rb
|
35
36
|
- lib/eventus/serializers.rb
|
36
37
|
- lib/eventus/serializers/marshal.rb
|
37
38
|
- lib/eventus/serializers/msgpack.rb
|
@@ -41,6 +42,7 @@ files:
|
|
41
42
|
- spec/dispatchers/synchronous_spec.rb
|
42
43
|
- spec/persistence/in_memory_spec.rb
|
43
44
|
- spec/persistence/kyotocabinet_spec.rb
|
45
|
+
- spec/persistence/mongo_spec.rb
|
44
46
|
- spec/spec_helper.rb
|
45
47
|
- spec/stream_spec.rb
|
46
48
|
homepage: ''
|
@@ -55,21 +57,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
57
|
- - ! '>='
|
56
58
|
- !ruby/object:Gem::Version
|
57
59
|
version: '0'
|
58
|
-
segments:
|
59
|
-
- 0
|
60
|
-
hash: -247495815524544458
|
61
60
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
62
|
requirements:
|
64
63
|
- - ! '>='
|
65
64
|
- !ruby/object:Gem::Version
|
66
65
|
version: '0'
|
67
|
-
segments:
|
68
|
-
- 0
|
69
|
-
hash: -247495815524544458
|
70
66
|
requirements: []
|
71
67
|
rubyforge_project: eventus
|
72
|
-
rubygems_version: 1.8.
|
68
|
+
rubygems_version: 1.8.15
|
73
69
|
signing_key:
|
74
70
|
specification_version: 3
|
75
71
|
summary: Event Store
|
@@ -78,5 +74,6 @@ test_files:
|
|
78
74
|
- spec/dispatchers/synchronous_spec.rb
|
79
75
|
- spec/persistence/in_memory_spec.rb
|
80
76
|
- spec/persistence/kyotocabinet_spec.rb
|
77
|
+
- spec/persistence/mongo_spec.rb
|
81
78
|
- spec/spec_helper.rb
|
82
79
|
- spec/stream_spec.rb
|