synapse-core 0.5.4 → 0.5.5
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/lib/synapse/command/async_command_bus.rb +3 -5
- data/lib/synapse/common.rb +0 -1
- data/lib/synapse/configuration/component/command_bus/async_command_bus.rb +3 -2
- data/lib/synapse/configuration/component/{mixin → shared}/thread_pool.rb +10 -8
- data/lib/synapse/configuration/dependent.rb +2 -2
- data/lib/synapse/configuration/ext.rb +58 -29
- data/lib/synapse/configuration.rb +1 -1
- data/lib/synapse/domain/aggregate_root.rb +43 -19
- data/lib/synapse/domain/errors.rb +9 -0
- data/lib/synapse/domain/event_container.rb +3 -3
- data/lib/synapse/domain/message.rb +2 -2
- data/lib/synapse/domain/message_builder.rb +2 -2
- data/lib/synapse/domain/simple_stream.rb +39 -0
- data/lib/synapse/domain/stream.rb +2 -41
- data/lib/synapse/domain.rb +3 -0
- data/lib/synapse/event_sourcing/aggregate_root.rb +102 -2
- data/lib/synapse/event_sourcing/caching.rb +1 -1
- data/lib/synapse/event_sourcing/entity.rb +2 -2
- data/lib/synapse/event_sourcing/member.rb +3 -13
- data/lib/synapse/event_sourcing/repository.rb +9 -2
- data/lib/synapse/event_sourcing/snapshot/taker.rb +2 -2
- data/lib/synapse/mapping/mapping.rb +2 -2
- data/lib/synapse/process_manager/simple_process_manager.rb +1 -0
- data/lib/synapse/rails/injection_helper.rb +23 -0
- data/lib/synapse/railtie.rb +17 -0
- data/lib/synapse/repository/lock_manager.rb +3 -3
- data/lib/synapse/uow/listener.rb +2 -2
- data/lib/synapse/uow/listener_collection.rb +7 -51
- data/lib/synapse/version.rb +1 -1
- data/lib/synapse-core.rb +1 -0
- data/lib/synapse.rb +3 -0
- data/test/command/async_command_bus_test.rb +8 -11
- data/test/configuration/component/command_bus/async_command_bus_test.rb +7 -6
- data/test/configuration/component/serialization/serializer_test.rb +2 -2
- data/test/configuration/fixtures/dependent.rb +1 -1
- data/test/rails/injection_helper_test.rb +27 -0
- data/test/serialization/converter/ox_test.rb +2 -2
- data/test/serialization/serializer/oj_test.rb +1 -1
- data/test/serialization/serializer/ox_test.rb +1 -1
- data/test/test_helper.rb +8 -9
- data/test/uow/uow_test.rb +2 -2
- metadata +221 -222
- data/lib/synapse/common/concurrency/executor.rb +0 -13
- data/test/support/countdown_latch.rb +0 -18
@@ -62,7 +62,7 @@ module Synapse
|
|
62
62
|
aggregate.initialize_from_stream stream
|
63
63
|
|
64
64
|
if aggregate.deleted?
|
65
|
-
raise AggregateDeletedError
|
65
|
+
raise AggregateDeletedError.new type_identifier, aggregate_id
|
66
66
|
end
|
67
67
|
|
68
68
|
if expected_version and @conflict_resolver.nil?
|
@@ -138,6 +138,13 @@ module Synapse
|
|
138
138
|
end
|
139
139
|
|
140
140
|
# Raised when an aggregate has been found but it was marked for deletion
|
141
|
-
class AggregateDeletedError < Repository::AggregateNotFoundError
|
141
|
+
class AggregateDeletedError < Repository::AggregateNotFoundError
|
142
|
+
# @param [String] type_identifier
|
143
|
+
# @param [Object] aggregate_id
|
144
|
+
# @return [undefined]
|
145
|
+
def initialize(type_identifier, aggregate_id)
|
146
|
+
super 'Aggregate marked for deletion [%s] [%s]' % [type_identifier, aggregate_id]
|
147
|
+
end
|
148
|
+
end
|
142
149
|
end
|
143
150
|
end
|
@@ -10,12 +10,12 @@ module Synapse
|
|
10
10
|
# @return [SnapshotEventStore]
|
11
11
|
attr_accessor :event_store
|
12
12
|
|
13
|
-
# @return [Executor]
|
13
|
+
# @return [Contender::Executor]
|
14
14
|
attr_accessor :executor
|
15
15
|
|
16
16
|
# @return [undefined]
|
17
17
|
def initialize
|
18
|
-
@executor = DirectExecutor.new
|
18
|
+
@executor = Contender::DirectExecutor.new
|
19
19
|
end
|
20
20
|
|
21
21
|
# Schedules a snapshot to be taken for an aggregate of the given type and with the given
|
@@ -4,6 +4,7 @@ module Synapse
|
|
4
4
|
class SimpleProcessManager < ProcessManager
|
5
5
|
# @return [Array] Types of events that will always result in the creation of a process
|
6
6
|
attr_accessor :always_create_events
|
7
|
+
|
7
8
|
# @return [Array] Types of events that will result in the creation of a process if one
|
8
9
|
# doesn't already exist
|
9
10
|
attr_accessor :optionally_create_events
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Synapse
|
2
|
+
module Rails
|
3
|
+
# Mixin for an action controller in Rails that adds dependency injection
|
4
|
+
module InjectionHelper
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_filter :inject_dependencies
|
9
|
+
end
|
10
|
+
|
11
|
+
# Performs one-time dependency injection before an action is called
|
12
|
+
# @return [undefined]
|
13
|
+
def inject_dependencies
|
14
|
+
return if @_dependencies_injected
|
15
|
+
|
16
|
+
container = Synapse.container
|
17
|
+
container.inject_into self
|
18
|
+
|
19
|
+
@_dependencies_injected = true
|
20
|
+
end
|
21
|
+
end # InjectionHelper
|
22
|
+
end # Rails
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Synapse
|
2
|
+
# Simple integration between the Synapse framework and Rails 3.2+
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
# Set the name of the Railtie
|
5
|
+
railtie_name :synapse
|
6
|
+
|
7
|
+
# Controllers will get dependencies injected automatically
|
8
|
+
initializer 'synapse.include_controller_mixins' do
|
9
|
+
ActionController::Base.class_eval do
|
10
|
+
include Synapse::Configuration::Dependent
|
11
|
+
include Synapse::Rails::InjectionHelper
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end # Railtie
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'synapse/rails/injection_helper'
|
@@ -26,7 +26,7 @@ module Synapse
|
|
26
26
|
# @param [Object] aggregate_id
|
27
27
|
# @return [undefined]
|
28
28
|
def release_lock(aggregate_id); end
|
29
|
-
end
|
29
|
+
end # LockManager
|
30
30
|
|
31
31
|
# Implementation of a lock manager that does no locking
|
32
32
|
class NullLockManager < LockManager
|
@@ -35,6 +35,6 @@ module Synapse
|
|
35
35
|
def validate_lock(aggregate)
|
36
36
|
true
|
37
37
|
end
|
38
|
-
end
|
39
|
-
end
|
38
|
+
end # NullLockManager
|
39
|
+
end # Repository
|
40
40
|
end
|
data/lib/synapse/uow/listener.rb
CHANGED
@@ -22,10 +22,7 @@ module Synapse
|
|
22
22
|
# @param [UnitOfWorkListener] listener
|
23
23
|
# @return [undefined]
|
24
24
|
def push(listener)
|
25
|
-
|
26
|
-
@logger.debug 'Registering listener [%s]' % listener.class
|
27
|
-
end
|
28
|
-
|
25
|
+
@logger.debug 'Registering listener [%s]' % listener.class
|
29
26
|
@listeners.push listener
|
30
27
|
end
|
31
28
|
|
@@ -34,17 +31,10 @@ module Synapse
|
|
34
31
|
# @param [UnitOfWork] unit
|
35
32
|
# @return [undefined]
|
36
33
|
def on_start(unit)
|
37
|
-
@logger.debug 'Notifying listeners that unit of work is starting'
|
38
|
-
|
39
34
|
@listeners.each do |listener|
|
40
|
-
|
41
|
-
@logger.debug 'Notifying [%s] of start' % listener.class
|
42
|
-
end
|
43
|
-
|
35
|
+
@logger.debug 'Notifying [%s] of start' % listener.class
|
44
36
|
listener.on_start unit
|
45
37
|
end
|
46
|
-
|
47
|
-
@logger.debug 'Listeners successfully notified'
|
48
38
|
end
|
49
39
|
|
50
40
|
# @param [UnitOfWork] unit
|
@@ -63,78 +53,46 @@ module Synapse
|
|
63
53
|
# @param [Hash<EventBus, Array>] events
|
64
54
|
# @return [undefined]
|
65
55
|
def on_prepare_commit(unit, aggregates, events)
|
66
|
-
@logger.debug 'Notifying listeners that commit was requested'
|
67
|
-
|
68
56
|
@listeners.each do |listener|
|
69
|
-
|
70
|
-
@logger.debug 'Notifying [%s] of commit' % listener.class
|
71
|
-
end
|
72
|
-
|
57
|
+
@logger.debug 'Notifying [%s] of commit' % listener.class
|
73
58
|
listener.on_prepare_commit unit, aggregates, events
|
74
59
|
end
|
75
|
-
|
76
|
-
@logger.debug 'Listeners successfully notified'
|
77
60
|
end
|
78
61
|
|
79
62
|
# @param [UnitOfWork] unit
|
80
63
|
# @param [Object] transaction
|
81
64
|
# @return [undefined]
|
82
65
|
def on_prepare_transaction_commit(unit, transaction)
|
83
|
-
@logger.debug 'Notifying listeners that transactional commit was requested'
|
84
|
-
|
85
66
|
@listeners.each do |listener|
|
86
|
-
|
87
|
-
@logger.debug 'Notifying [%s] of transactional commit' % listener.class
|
88
|
-
end
|
89
|
-
|
67
|
+
@logger.debug 'Notifying [%s] of transactional commit' % listener.class
|
90
68
|
listener.on_prepare_transaction_commit unit, transaction
|
91
69
|
end
|
92
|
-
|
93
|
-
@logger.debug 'Listeners successfully notified'
|
94
70
|
end
|
95
71
|
|
96
72
|
# @param [UnitOfWork] unit
|
97
73
|
# @return [undefined]
|
98
74
|
def after_commit(unit)
|
99
|
-
@logger.debug 'Notifying listeners that commit has finished'
|
100
|
-
|
101
75
|
@listeners.reverse_each do |listener|
|
102
|
-
|
103
|
-
@logger.debug 'Notifying [%s] of finished commit' % listener.class
|
104
|
-
end
|
105
|
-
|
76
|
+
@logger.debug 'Notifying [%s] of finished commit' % listener.class
|
106
77
|
listener.after_commit unit
|
107
78
|
end
|
108
|
-
|
109
|
-
@logger.debug 'Listeners successfully notified'
|
110
79
|
end
|
111
80
|
|
112
81
|
# @param [UnitOfWork] unit
|
113
82
|
# @param [Error] cause
|
114
83
|
# @return [undefined]
|
115
84
|
def on_rollback(unit, cause = nil)
|
116
|
-
@logger.debug 'Notifying listeners of rollback'
|
117
|
-
|
118
85
|
@listeners.reverse_each do |listener|
|
119
|
-
|
120
|
-
@logger.debug 'Notifying [%s] of rollback' % listener.class
|
121
|
-
end
|
122
|
-
|
86
|
+
@logger.debug 'Notifying [%s] of rollback' % listener.class
|
123
87
|
listener.on_rollback unit, cause
|
124
88
|
end
|
125
|
-
|
126
|
-
@logger.debug 'Listeners successfully notified'
|
127
89
|
end
|
128
90
|
|
129
91
|
# @param [UnitOfWork] unit
|
130
92
|
# @return [undefined]
|
131
93
|
def on_cleanup(unit)
|
132
|
-
@logger.debug 'Notifying listeners of cleanup'
|
133
|
-
|
134
94
|
@listeners.reverse_each do |listener|
|
135
|
-
|
136
|
-
@logger.debug 'Notifying [%s] of cleanup' % listener.class
|
137
|
-
end
|
95
|
+
@logger.debug 'Notifying [%s] of cleanup' % listener.class
|
138
96
|
|
139
97
|
begin
|
140
98
|
listener.on_cleanup unit
|
@@ -143,8 +101,6 @@ module Synapse
|
|
143
101
|
@logger.warn 'Listener raised an exception during cleanup: %s' % exception.inspect
|
144
102
|
end
|
145
103
|
end
|
146
|
-
|
147
|
-
@logger.debug 'Listeners successfully notified'
|
148
104
|
end
|
149
105
|
end # UnitOfWorkListenerCollection
|
150
106
|
end # UnitOfWork
|
data/lib/synapse/version.rb
CHANGED
data/lib/synapse-core.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'synapse'
|
data/lib/synapse.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
require 'active_support/core_ext'
|
3
|
+
require 'contender'
|
3
4
|
require 'forwardable'
|
4
5
|
require 'logging'
|
5
6
|
require 'set'
|
@@ -29,3 +30,5 @@ module Synapse
|
|
29
30
|
autoload :ProcessManager
|
30
31
|
autoload :Upcasting
|
31
32
|
end
|
33
|
+
|
34
|
+
require 'synapse/railtie' if defined? Rails
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'test_helper'
|
2
|
-
require 'support/countdown_latch'
|
3
2
|
|
4
3
|
module Synapse
|
5
4
|
module Command
|
@@ -9,14 +8,16 @@ module Synapse
|
|
9
8
|
unit_factory = UnitOfWork::UnitOfWorkFactory.new unit_provider
|
10
9
|
|
11
10
|
@bus = AsynchronousCommandBus.new unit_factory
|
12
|
-
@bus.thread_pool =
|
11
|
+
@bus.thread_pool = Contender::Pool::ThreadPoolExecutor.new
|
12
|
+
@bus.thread_pool.start
|
13
13
|
end
|
14
14
|
|
15
15
|
should 'be able to dispatch commands asynchronously using a thread pool' do
|
16
16
|
x = 5 # Number of commands to dispatch
|
17
17
|
|
18
18
|
command = CommandMessage.as_message TestCommand.new
|
19
|
-
|
19
|
+
latch = Contender::CountdownLatch.new x
|
20
|
+
handler = TestAsyncHandler.new latch
|
20
21
|
|
21
22
|
@bus.subscribe TestCommand, handler
|
22
23
|
|
@@ -24,23 +25,19 @@ module Synapse
|
|
24
25
|
@bus.dispatch command
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
-
handler.latch.count == 0
|
29
|
-
end
|
28
|
+
assert latch.await 5
|
30
29
|
|
31
30
|
@bus.shutdown
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
34
|
class TestAsyncHandler
|
36
|
-
|
37
|
-
|
38
|
-
def initialize(x)
|
39
|
-
@latch = CountdownLatch.new x
|
35
|
+
def initialize(latch)
|
36
|
+
@latch = latch
|
40
37
|
end
|
41
38
|
|
42
39
|
def handle(command, unit)
|
43
|
-
@latch.countdown
|
40
|
+
@latch.countdown
|
44
41
|
end
|
45
42
|
end
|
46
43
|
|
@@ -16,20 +16,21 @@ module Synapse
|
|
16
16
|
assert command_bus.is_a? Command::AsynchronousCommandBus
|
17
17
|
|
18
18
|
thread_pool = command_bus.thread_pool
|
19
|
-
|
20
|
-
|
19
|
+
assert_instance_of Contender::Pool::ThreadPoolExecutor, thread_pool
|
20
|
+
assert thread_pool.active?
|
21
|
+
thread_pool.shutdown
|
21
22
|
end
|
22
23
|
|
23
|
-
should 'build with a custom thread pool
|
24
|
+
should 'build with a custom thread pool options' do
|
24
25
|
@builder.async_command_bus do
|
25
|
-
|
26
|
+
use_pool_options size: 4, non_block: true
|
26
27
|
end
|
27
28
|
|
28
29
|
command_bus = @container.resolve :command_bus
|
29
30
|
|
30
31
|
thread_pool = command_bus.thread_pool
|
31
|
-
|
32
|
-
|
32
|
+
assert thread_pool.active?
|
33
|
+
thread_pool.shutdown
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -40,7 +40,7 @@ module Synapse
|
|
40
40
|
end
|
41
41
|
|
42
42
|
should 'build with OxSerializer' do
|
43
|
-
|
43
|
+
omit 'Ox not supported on JRuby' if defined? JRUBY_VERSION
|
44
44
|
|
45
45
|
serialize_options = { :circular => true }
|
46
46
|
|
@@ -56,7 +56,7 @@ module Synapse
|
|
56
56
|
end
|
57
57
|
|
58
58
|
should 'build with OjSerializer' do
|
59
|
-
|
59
|
+
omit 'Oj not supported on JRuby' if defined? JRUBY_VERSION
|
60
60
|
|
61
61
|
serialize_options = { :indent => 2, :circular => true }
|
62
62
|
deserialize_options = { :symbol_keys => true }
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
require 'synapse/railtie'
|
5
|
+
|
6
|
+
module Synapse
|
7
|
+
module Rails
|
8
|
+
class InjectionHelperTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@controller_class = Class.new
|
12
|
+
@controller = @controller_class.new
|
13
|
+
mock(@controller_class).before_filter(:inject_dependencies)
|
14
|
+
@controller_class.send :include, InjectionHelper
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'inject dependencies only once' do
|
18
|
+
container_mock = mock(Synapse).container.mock!
|
19
|
+
container_mock.inject_into(@controller)
|
20
|
+
|
21
|
+
@controller.inject_dependencies
|
22
|
+
@controller.inject_dependencies
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -4,7 +4,7 @@ module Synapse
|
|
4
4
|
module Serialization
|
5
5
|
class OxDocumentToXmlConverterTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
-
|
7
|
+
omit 'Ox not supported on JRuby' if defined? JRUBY_VERSION
|
8
8
|
end
|
9
9
|
|
10
10
|
should 'convert an Ox document to an XML string' do
|
@@ -22,7 +22,7 @@ module Synapse
|
|
22
22
|
|
23
23
|
class XmlToOxDocumentConverterTest < Test::Unit::TestCase
|
24
24
|
def setup
|
25
|
-
|
25
|
+
omit 'Ox not supported on JRuby' if defined? JRUBY_VERSION
|
26
26
|
end
|
27
27
|
|
28
28
|
should 'convert an XML string to an Ox document' do
|
@@ -6,7 +6,7 @@ module Synapse
|
|
6
6
|
|
7
7
|
class OjSerializerTest < Test::Unit::TestCase
|
8
8
|
def setup
|
9
|
-
|
9
|
+
omit 'Oj not supported on JRuby' if defined? JRUBY_VERSION
|
10
10
|
end
|
11
11
|
|
12
12
|
should 'support serializing and deserializing content' do
|
data/test/test_helper.rb
CHANGED
@@ -8,19 +8,18 @@ else
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
# Need this for Contender, since we get it from GitHub for now
|
12
|
+
require 'bundler/setup'
|
13
|
+
|
12
14
|
require 'synapse'
|
15
|
+
|
16
|
+
require 'pp'
|
13
17
|
require 'test/unit'
|
14
|
-
require '
|
15
|
-
|
18
|
+
require 'test/unit/rr'
|
19
|
+
|
16
20
|
require 'timecop'
|
21
|
+
require 'shoulda/context'
|
17
22
|
|
18
23
|
require 'test_ext'
|
19
24
|
|
20
|
-
# I guess RR broke
|
21
|
-
# http://stackoverflow.com/questions/3657972
|
22
|
-
unless defined? Test::Unit::AssertionFailedError
|
23
|
-
Test::Unit::AssertionFailedError = ActiveSupport::TestCase::Assertion
|
24
|
-
end
|
25
|
-
|
26
25
|
ActiveSupport::Autoload.eager_autoload!
|
data/test/uow/uow_test.rb
CHANGED
@@ -159,8 +159,8 @@ module Synapse
|
|
159
159
|
|
160
160
|
should 'rollback if an aggregate storage callback raises an exception' do
|
161
161
|
aggregate_root = Object.new
|
162
|
-
|
163
|
-
|
162
|
+
stub(aggregate_root).add_registration_listener
|
163
|
+
stub(aggregate_root).id
|
164
164
|
|
165
165
|
event_bus = Object.new
|
166
166
|
cause = TestError.new
|