eventus 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|