synapse-core 0.4.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/synapse/command/async_command_bus.rb +41 -0
- data/lib/synapse/command/command_callback.rb +49 -2
- data/lib/synapse/command/command_handler.rb +2 -0
- data/lib/synapse/command/filters/validation.rb +2 -2
- data/lib/synapse/command/gateway/interval_retry_scheduler.rb +75 -0
- data/lib/synapse/command/gateway/retry_scheduler.rb +26 -0
- data/lib/synapse/command/gateway/retrying_callback.rb +46 -0
- data/lib/synapse/command/gateway.rb +56 -11
- data/lib/synapse/command/interceptor_chain.rb +2 -2
- data/lib/synapse/command/interceptors/serialization.rb +2 -2
- data/lib/synapse/command/message.rb +16 -0
- data/lib/synapse/command/simple_command_bus.rb +6 -2
- data/lib/synapse/command/wiring.rb +3 -3
- data/lib/synapse/command.rb +7 -1
- data/lib/synapse/common/concurrency/identifier_lock.rb +2 -17
- data/lib/synapse/common/concurrency/public_lock.rb +8 -9
- data/lib/synapse/common/errors.rb +1 -1
- data/lib/synapse/common/message.rb +2 -6
- data/lib/synapse/common.rb +9 -0
- data/lib/synapse/configuration/component/command_bus/async_command_bus.rb +41 -0
- data/lib/synapse/configuration/component/command_bus/gateway.rb +38 -0
- data/lib/synapse/configuration/component/command_bus/simple_command_bus.rb +81 -0
- data/lib/synapse/configuration/component/command_bus.rb +35 -0
- data/lib/synapse/configuration/component/event_bus/simple_event_bus.rb +41 -0
- data/lib/synapse/configuration/component/event_bus.rb +15 -0
- data/lib/synapse/configuration/component/event_sourcing/repository.rb +62 -0
- data/lib/synapse/configuration/component/event_sourcing.rb +15 -0
- data/lib/synapse/configuration/component/repository/locking_repository.rb +85 -0
- data/lib/synapse/configuration/component/repository/simple_repository.rb +31 -0
- data/lib/synapse/configuration/component/repository.rb +15 -0
- data/lib/synapse/configuration/component/serialization/converter_factory.rb +50 -0
- data/lib/synapse/configuration/component/serialization/serializer.rb +90 -0
- data/lib/synapse/configuration/component/serialization.rb +25 -0
- data/lib/synapse/configuration/component/uow/unit_factory.rb +51 -0
- data/lib/synapse/configuration/component/uow.rb +22 -0
- data/lib/synapse/configuration/component/upcasting/upcaster_chain.rb +61 -0
- data/lib/synapse/configuration/component/upcasting.rb +15 -0
- data/lib/synapse/configuration/container.rb +80 -0
- data/lib/synapse/configuration/container_builder.rb +108 -0
- data/lib/synapse/configuration/definition.rb +31 -0
- data/lib/synapse/configuration/definition_builder.rb +138 -0
- data/lib/synapse/configuration/dependent.rb +31 -0
- data/lib/synapse/configuration/ext.rb +35 -0
- data/lib/synapse/configuration.rb +32 -0
- data/lib/synapse/domain/aggregate_root.rb +25 -26
- data/lib/synapse/domain/event_container.rb +5 -5
- data/lib/synapse/domain/message.rb +16 -0
- data/lib/synapse/event_bus/event_listener.rb +2 -0
- data/lib/synapse/event_bus/event_publisher.rb +19 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +21 -30
- data/lib/synapse/event_bus/wiring.rb +5 -4
- data/lib/synapse/event_bus.rb +1 -1
- data/lib/synapse/event_sourcing/aggregate_root.rb +6 -4
- data/lib/synapse/process_manager/container_resource_injector.rb +18 -0
- data/lib/synapse/process_manager/pessimistic_lock_manager.rb +1 -1
- data/lib/synapse/process_manager/process.rb +4 -0
- data/lib/synapse/process_manager/process_factory.rb +3 -3
- data/lib/synapse/process_manager/repository/in_memory.rb +1 -1
- data/lib/synapse/process_manager/wiring/process.rb +6 -6
- data/lib/synapse/process_manager/wiring/process_manager.rb +8 -8
- data/lib/synapse/process_manager.rb +2 -0
- data/lib/synapse/repository/locking.rb +5 -3
- data/lib/synapse/repository/optimistic_lock_manager.rb +2 -7
- data/lib/synapse/repository/pessimistic_lock_manager.rb +3 -3
- data/lib/synapse/repository/repository.rb +2 -2
- data/lib/synapse/repository/simple_repository.rb +69 -0
- data/lib/synapse/repository.rb +1 -0
- data/lib/synapse/serialization/converter/chain.rb +2 -2
- data/lib/synapse/serialization/converter_factory.rb +2 -2
- data/lib/synapse/serialization/lazy_object.rb +2 -2
- data/lib/synapse/serialization/message/serialization_aware_message.rb +3 -3
- data/lib/synapse/serialization/message/serialized_message.rb +6 -10
- data/lib/synapse/serialization/message/serialized_message_builder.rb +4 -4
- data/lib/synapse/serialization/message/serialized_object_cache.rb +2 -2
- data/lib/synapse/serialization/message/serializer.rb +2 -2
- data/lib/synapse/serialization/revision_resolver.rb +3 -3
- data/lib/synapse/serialization/serialized_object.rb +2 -2
- data/lib/synapse/serialization/serialized_type.rb +2 -2
- data/lib/synapse/serialization/serializer/attribute.rb +2 -2
- data/lib/synapse/serialization/serializer/marshal.rb +2 -2
- data/lib/synapse/serialization/serializer/oj.rb +2 -2
- data/lib/synapse/serialization/serializer/ox.rb +2 -2
- data/lib/synapse/serialization/serializer.rb +2 -2
- data/lib/synapse/uow/factory.rb +2 -2
- data/lib/synapse/uow/listener_collection.rb +2 -2
- data/lib/synapse/uow/nesting.rb +9 -2
- data/lib/synapse/uow/provider.rb +2 -2
- data/lib/synapse/uow/uow.rb +8 -2
- data/lib/synapse/upcasting/{chain.rb → upcaster_chain.rb} +0 -0
- data/lib/synapse/upcasting.rb +1 -1
- data/lib/synapse/version.rb +1 -1
- data/lib/synapse/wiring/message_wiring.rb +31 -0
- data/lib/synapse.rb +2 -14
- data/test/auditing/data_provider_test.rb +2 -2
- data/test/auditing/dispatch_interceptor_test.rb +1 -1
- data/test/auditing/unit_listener_test.rb +3 -3
- data/test/command/async_command_bus_test.rb +49 -0
- data/test/command/duplication_test.rb +2 -2
- data/test/command/gateway/interval_retry_scheduler_test.rb +42 -0
- data/test/command/gateway/retrying_callback_test.rb +57 -0
- data/test/command/gateway_test.rb +41 -7
- data/test/command/interceptor_chain_test.rb +1 -1
- data/test/command/message_test.rb +17 -0
- data/test/command/serialization_test.rb +2 -2
- data/test/command/simple_command_bus_test.rb +7 -7
- data/test/command/validation_test.rb +3 -3
- data/test/command/wiring_test.rb +3 -3
- data/test/common/concurrency/identifier_lock_test.rb +2 -13
- data/test/common/concurrency/public_lock_test.rb +6 -6
- data/test/{duplication_test.rb → common/duplication_test.rb} +3 -3
- data/test/configuration/component/command_bus/async_command_bus_test.rb +36 -0
- data/test/configuration/component/command_bus/simple_command_bus_test.rb +57 -0
- data/test/configuration/component/event_bus/simple_event_bus_test.rb +58 -0
- data/test/configuration/component/serialization/converter_factory_test.rb +48 -0
- data/test/configuration/component/serialization/serializer_test.rb +78 -0
- data/test/configuration/component/uow/unit_factory_test.rb +46 -0
- data/test/configuration/container_builder_test.rb +47 -0
- data/test/configuration/container_test.rb +88 -0
- data/test/configuration/definition_builder_test.rb +126 -0
- data/test/configuration/definition_test.rb +41 -0
- data/test/configuration/dependent_test.rb +30 -0
- data/test/configuration/ext_test.rb +19 -0
- data/test/configuration/fixtures/dependent.rb +10 -0
- data/test/domain/aggregate_root_test.rb +5 -5
- data/test/domain/message_test.rb +15 -3
- data/test/domain/stream_test.rb +2 -2
- data/test/event_bus/publisher_test.rb +29 -0
- data/test/event_bus/wiring_test.rb +1 -1
- data/test/event_sourcing/aggregate_factory_test.rb +12 -6
- data/test/event_sourcing/aggregate_root_test.rb +4 -4
- data/test/event_sourcing/entity_test.rb +10 -9
- data/test/event_sourcing/repository_test.rb +6 -6
- data/test/event_sourcing/storage_listener_test.rb +8 -4
- data/test/event_store/in_memory_test.rb +3 -3
- data/test/process_manager/container_resource_injector_test.rb +19 -0
- data/test/process_manager/correlation_set_test.rb +2 -2
- data/test/process_manager/correlation_test.rb +2 -2
- data/test/process_manager/in_memory_test.rb +3 -3
- data/test/process_manager/process_factory_test.rb +2 -2
- data/test/process_manager/process_test.rb +3 -3
- data/test/process_manager/simple_process_manager_test.rb +5 -5
- data/test/process_manager/wiring/process_manager_test.rb +4 -4
- data/test/process_manager/wiring/process_test.rb +2 -2
- data/test/repository/locking_test.rb +4 -4
- data/test/repository/optimistic_test.rb +2 -2
- data/test/repository/pessimistic_test.rb +1 -1
- data/test/repository/simple_repository_test.rb +79 -0
- data/test/support/countdown_latch.rb +18 -0
- data/test/test_helper.rb +6 -3
- data/test/upcasting/data_test.rb +31 -0
- metadata +84 -25
- data/lib/synapse/event_bus/event_listener_proxy.rb +0 -12
- data/lib/synapse/partitioning/memory_queue_reader.rb +0 -31
- data/lib/synapse/partitioning/memory_queue_writer.rb +0 -19
- data/lib/synapse/partitioning/message_receipt.rb +0 -25
- data/lib/synapse/partitioning/packing/json_packer.rb +0 -93
- data/lib/synapse/partitioning/packing/json_unpacker.rb +0 -83
- data/lib/synapse/partitioning/packing.rb +0 -27
- data/lib/synapse/partitioning/queue_reader.rb +0 -32
- data/lib/synapse/partitioning/queue_writer.rb +0 -17
- data/lib/synapse/partitioning.rb +0 -18
- data/test/partitioning/memory_test.rb +0 -34
- data/test/partitioning/packing/json_test.rb +0 -62
@@ -0,0 +1,19 @@
|
|
1
|
+
module Synapse
|
2
|
+
module EventBus
|
3
|
+
# Mixin for an object that wishes to easily be able to publish events to an event bus
|
4
|
+
module EventPublisher
|
5
|
+
# @return [EventBus]
|
6
|
+
attr_accessor :event_bus
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
# Publishes the given event object or event message to the configured event bus
|
11
|
+
#
|
12
|
+
# @param [Object] event
|
13
|
+
# @return [undefined]
|
14
|
+
def publish_event(event)
|
15
|
+
@event_bus.publish(Domain::EventMessage.as_message(event))
|
16
|
+
end
|
17
|
+
end # EventPublisher
|
18
|
+
end # EventBus
|
19
|
+
end
|
@@ -8,62 +8,53 @@ module Synapse
|
|
8
8
|
@logger = Logging.logger[self.class]
|
9
9
|
end
|
10
10
|
|
11
|
+
# @api public
|
11
12
|
# @param [EventMessage...] events
|
12
13
|
# @return [undefined]
|
13
14
|
def publish(*events)
|
14
|
-
if @listeners.empty?
|
15
|
-
return
|
16
|
-
end
|
15
|
+
return if @listeners.empty?
|
17
16
|
|
18
17
|
events.flatten!
|
19
18
|
events.each do |event|
|
20
19
|
@listeners.each do |listener|
|
21
|
-
|
22
|
-
|
23
|
-
@logger.debug 'Dispatching event [%s] to listener [%s]' %
|
24
|
-
[event.payload_type, listener_type]
|
25
|
-
end
|
20
|
+
@logger.debug 'Dispatching event [%s] to listener [%s]' %
|
21
|
+
[event.payload_type, listener.class]
|
26
22
|
|
27
23
|
listener.notify event
|
28
24
|
end
|
29
25
|
end
|
30
26
|
end
|
31
27
|
|
28
|
+
# Returns true if the given listener is subscribed to this event bus
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
# @param [EventListener] listener
|
32
|
+
# @return [Boolean]
|
33
|
+
def subscribed?(listener)
|
34
|
+
@listeners.include? listener
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api public
|
32
38
|
# @param [EventListener] listener
|
33
39
|
# @return [undefined]
|
34
40
|
def subscribe(listener)
|
35
|
-
listener_type = actual_type listener
|
36
|
-
|
37
41
|
if @listeners.add? listener
|
38
|
-
@logger.debug 'Event listener [%s] subscribed' %
|
42
|
+
@logger.debug 'Event listener [%s] subscribed' % listener.class
|
39
43
|
else
|
40
|
-
@logger.info 'Event listener [%s] not added, was already subscribed' %
|
44
|
+
@logger.info 'Event listener [%s] not added, was already subscribed' % listener.class
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
48
|
+
# @api public
|
44
49
|
# @param [EventListener] listener
|
45
50
|
# @return [undefined]
|
46
51
|
def unsubscribe(listener)
|
47
|
-
listener_type = actual_type listener
|
48
|
-
|
49
52
|
if @listeners.delete? listener
|
50
|
-
@logger.debug 'Event listener [%s] unsubscribed' %
|
51
|
-
else
|
52
|
-
@logger.info 'Event listener [%s] not removed, was not subscribed' % listener_type
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
# @param [EventListener] listener
|
59
|
-
# @return [Class]
|
60
|
-
def actual_type(listener)
|
61
|
-
if listener.respond_to? :proxied_type
|
62
|
-
listener.proxied_type
|
53
|
+
@logger.debug 'Event listener [%s] unsubscribed' % listener.class
|
63
54
|
else
|
64
|
-
listener.class
|
55
|
+
@logger.info 'Event listener [%s] not removed, was not subscribed' % listener.class
|
65
56
|
end
|
66
57
|
end
|
67
|
-
end
|
68
|
-
end
|
58
|
+
end # SimpleEventBus
|
59
|
+
end # EventBus
|
69
60
|
end
|
@@ -9,10 +9,11 @@ module Synapse
|
|
9
9
|
# @param [EventMessage] event
|
10
10
|
# @return [undefined]
|
11
11
|
def notify(event)
|
12
|
-
wire =
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
wire = wire_registry.wire_for event.payload_type
|
13
|
+
|
14
|
+
return unless wire
|
15
|
+
|
16
|
+
invoke_wire event, wire
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/synapse/event_bus.rb
CHANGED
@@ -67,6 +67,7 @@ module Synapse
|
|
67
67
|
# Creates an event with the given metadata and payload, publishes it using the event
|
68
68
|
# container, and finally handles it locally and recursively down the aggregate.
|
69
69
|
#
|
70
|
+
# @api public
|
70
71
|
# @param [Object] payload
|
71
72
|
# @param [Hash] metadata
|
72
73
|
# @return [undefined]
|
@@ -76,10 +77,10 @@ module Synapse
|
|
76
77
|
handle_recursively event
|
77
78
|
else
|
78
79
|
# This is a workaround for aggregates that set the aggregate identifier in an event handler
|
79
|
-
event = Domain::DomainEventMessage.build do |
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
event = Domain::DomainEventMessage.build do |builder|
|
81
|
+
builder.metadata = metadata
|
82
|
+
builder.payload = payload
|
83
|
+
builder.sequence_number = 0
|
83
84
|
end
|
84
85
|
|
85
86
|
handle_recursively event
|
@@ -89,6 +90,7 @@ module Synapse
|
|
89
90
|
|
90
91
|
# Handles the event locally and then cascades to any registered child entities
|
91
92
|
#
|
93
|
+
# @api private
|
92
94
|
# @param [DomainEventMessage] event
|
93
95
|
# @return [undefined]
|
94
96
|
def handle_recursively(event)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Synapse
|
2
|
+
module ProcessManager
|
3
|
+
# Resource injector that uses the service container and dependency DSL to inject resources
|
4
|
+
class ContainerResourceInjector < ResourceInjector
|
5
|
+
# @param [Configuration::Container] container
|
6
|
+
# @return [undefined]
|
7
|
+
def initialize(container)
|
8
|
+
@container = container
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [Process] process
|
12
|
+
# @return [undefined]
|
13
|
+
def inject_resources(process)
|
14
|
+
@container.inject_into process
|
15
|
+
end
|
16
|
+
end # ContainerResourceInjector
|
17
|
+
end # ProcessManager
|
18
|
+
end
|
@@ -6,6 +6,8 @@ module Synapse
|
|
6
6
|
# "maintain the state of the sequence and determine the next processing step based on
|
7
7
|
# intermediate results" (Hohpe 279). Processes are also called sagas in some CQRS frameworks.
|
8
8
|
#
|
9
|
+
# Consider using the implementation of a process that uses message wiring.
|
10
|
+
#
|
9
11
|
# @abstract
|
10
12
|
class Process
|
11
13
|
# @return [String] The unique identifier of this process
|
@@ -47,6 +49,7 @@ module Synapse
|
|
47
49
|
|
48
50
|
# Correlates this process instance with the given key and value
|
49
51
|
#
|
52
|
+
# @api public
|
50
53
|
# @param [Symbol] key
|
51
54
|
# @param [String] value
|
52
55
|
# @return [undefined]
|
@@ -56,6 +59,7 @@ module Synapse
|
|
56
59
|
|
57
60
|
# Dissociates this process instance from the given key and value
|
58
61
|
#
|
62
|
+
# @api public
|
59
63
|
# @param [Symbol] key
|
60
64
|
# @param [String] value
|
61
65
|
# @return [undefined]
|
@@ -19,7 +19,7 @@ module Synapse
|
|
19
19
|
# @param [Class] process_type
|
20
20
|
# @return [Boolean]
|
21
21
|
def supports(process_type); end
|
22
|
-
end
|
22
|
+
end # ProcessFactory
|
23
23
|
|
24
24
|
# Generic implementation of a process factory that supports any process implementations that
|
25
25
|
# have a no-argument constructor
|
@@ -47,6 +47,6 @@ module Synapse
|
|
47
47
|
ctor = process_type.instance_method :initialize
|
48
48
|
ctor.arity <= 0
|
49
49
|
end
|
50
|
-
end
|
51
|
-
end
|
50
|
+
end # GenericProcessFactory
|
51
|
+
end # ProcessManager
|
52
52
|
end
|
@@ -15,13 +15,13 @@ module Synapse
|
|
15
15
|
def handle(event)
|
16
16
|
return unless @active
|
17
17
|
|
18
|
-
wire =
|
18
|
+
wire = wire_registry.wire_for event.payload_type
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
return unless wire
|
21
|
+
|
22
|
+
invoke_wire event, wire
|
23
|
+
finish if wire.options[:finish]
|
24
24
|
end
|
25
25
|
end # WiringProcess
|
26
|
-
end
|
26
|
+
end # ProcessManager
|
27
27
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Synapse
|
2
2
|
module ProcessManager
|
3
3
|
# Process manager that is aware of processes that use the wiring DSL
|
4
|
-
# @see
|
4
|
+
# @see WiringProcess
|
5
5
|
class WiringProcessManager < ProcessManager
|
6
6
|
# @raise [ArgumentError] If a process type is given that doesn't support the wiring DSL
|
7
7
|
# @param [ProcessRepository] repository
|
@@ -44,11 +44,11 @@ module Synapse
|
|
44
44
|
def extract_correlation(process_type, event)
|
45
45
|
wire = process_type.wire_registry.wire_for event.payload_type
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
return unless wire
|
48
|
+
|
49
|
+
correlation_key = wire.options[:correlate]
|
50
|
+
if correlation_key
|
51
|
+
correlation_value event.payload, correlation_key
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -67,6 +67,6 @@ module Synapse
|
|
67
67
|
Correlation.new correlation_key, value
|
68
68
|
end
|
69
69
|
end
|
70
|
-
end
|
71
|
-
end
|
70
|
+
end # WiringProcessManager
|
71
|
+
end # ProcessManager
|
72
72
|
end
|
@@ -8,6 +8,8 @@ require 'synapse/process_manager/process_factory'
|
|
8
8
|
require 'synapse/process_manager/process_manager'
|
9
9
|
require 'synapse/process_manager/process_repository'
|
10
10
|
require 'synapse/process_manager/resource_injector'
|
11
|
+
# Must be loaded after the resource injector
|
12
|
+
require 'synapse/process_manager/container_resource_injector'
|
11
13
|
require 'synapse/process_manager/simple_process_manager'
|
12
14
|
|
13
15
|
require 'synapse/process_manager/wiring/process'
|
@@ -13,6 +13,7 @@ module Synapse
|
|
13
13
|
@logger = Logging.logger[self.class]
|
14
14
|
end
|
15
15
|
|
16
|
+
# @api public
|
16
17
|
# @raise [AggregateNotFoundError]
|
17
18
|
# If the aggregate with the given identifier could not be found
|
18
19
|
# @raise [ConflictingModificationError]
|
@@ -37,6 +38,7 @@ module Synapse
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
# @api public
|
40
42
|
# @raise [ArgumentError] If the version of the aggregate is not null
|
41
43
|
# @param [AggregateRoot] aggregate
|
42
44
|
# @return [undefined]
|
@@ -69,7 +71,7 @@ module Synapse
|
|
69
71
|
# @param [Integer] expected_version
|
70
72
|
# @return [AggregateRoot]
|
71
73
|
def perform_load(aggregate_id, expected_version); end
|
72
|
-
end
|
74
|
+
end # LockingRepository
|
73
75
|
|
74
76
|
# Unit of work listener that releases the lock on an aggregate when the unit of work
|
75
77
|
# is cleaning up
|
@@ -87,6 +89,6 @@ module Synapse
|
|
87
89
|
def on_cleanup(unit)
|
88
90
|
@lock_manager.release_lock @aggregate_id
|
89
91
|
end
|
90
|
-
end
|
91
|
-
end
|
92
|
+
end # LockCleaningUnitOfWorkListener
|
93
|
+
end # Repository
|
92
94
|
end
|
@@ -65,7 +65,7 @@ module Synapse
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end # OptimisticLockManager
|
69
69
|
|
70
70
|
# Lock that keeps track of an aggregate's version
|
71
71
|
# @api private
|
@@ -88,12 +88,7 @@ module Synapse
|
|
88
88
|
def validate(aggregate)
|
89
89
|
last_committed = aggregate.version
|
90
90
|
if @version.nil? or @version.eql? last_committed
|
91
|
-
|
92
|
-
last_committed = 0
|
93
|
-
end
|
94
|
-
|
95
|
-
@version = last_committed + aggregate.uncommitted_event_count
|
96
|
-
|
91
|
+
@version = (last_committed or 0) + aggregate.uncommitted_event_count
|
97
92
|
true
|
98
93
|
else
|
99
94
|
false
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Synapse
|
2
2
|
module Repository
|
3
|
-
#
|
3
|
+
# Implementation of a lock manager that blocks until a lock can be obtained
|
4
4
|
class PessimisticLockManager < LockManager
|
5
5
|
def initialize
|
6
6
|
@aggregates = IdentifierLock.new
|
@@ -23,6 +23,6 @@ module Synapse
|
|
23
23
|
def release_lock(aggregate_id)
|
24
24
|
@aggregates.release_lock aggregate_id
|
25
25
|
end
|
26
|
-
end
|
27
|
-
end
|
26
|
+
end # PessimisticLockManager
|
27
|
+
end # Repository
|
28
28
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Synapse
|
2
|
+
module Repository
|
3
|
+
# Simple repository that works with all sorts of different object mappers, including:
|
4
|
+
#
|
5
|
+
# - ActiveRecord
|
6
|
+
# - DataMapper
|
7
|
+
# - Mongoid
|
8
|
+
# - MongoMapper
|
9
|
+
#
|
10
|
+
# The only requirement of the model is that it properly increment the version field upon save
|
11
|
+
class SimpleRepository < LockingRepository
|
12
|
+
# @param [LockManager] lock_manager
|
13
|
+
# @param [Class] aggregate_type
|
14
|
+
# @return [undefined]
|
15
|
+
def initialize(lock_manager, aggregate_type)
|
16
|
+
super lock_manager
|
17
|
+
|
18
|
+
@aggregate_type = aggregate_type
|
19
|
+
@storage_listener = SimpleStorageListener.new
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
# @raise [AggregateNotFoundError]
|
25
|
+
# If the aggregate with the given identifier could not be found
|
26
|
+
# @raise [ConflictingModificationError]
|
27
|
+
# If the expected version doesn't match the aggregate's actual version
|
28
|
+
# @param [Object] aggregate_id
|
29
|
+
# @param [Integer] expected_version
|
30
|
+
# @return [AggregateRoot]
|
31
|
+
def perform_load(aggregate_id, expected_version)
|
32
|
+
# Most ORMs that I can think of use #find like this -- no need for orm_adapter or anything
|
33
|
+
# crazy like that
|
34
|
+
aggregate = @aggregate_type.find aggregate_id
|
35
|
+
aggregate.tap do
|
36
|
+
unless aggregate
|
37
|
+
raise AggregateNotFoundError
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_version_expected aggregate, expected_version
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Class]
|
45
|
+
def aggregate_type
|
46
|
+
@aggregate_type
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [StorageListener]
|
50
|
+
def storage_listener
|
51
|
+
@storage_listener
|
52
|
+
end
|
53
|
+
end # SimpleRepository
|
54
|
+
|
55
|
+
# Storage listener that simply calls #save on the aggregate, unless it has been marked for
|
56
|
+
# deletion. In that case, then the #destroy method is called instead.
|
57
|
+
class SimpleStorageListener < UnitOfWork::StorageListener
|
58
|
+
# @param [AggregateRoot] aggregate
|
59
|
+
# @return [undefined]
|
60
|
+
def store(aggregate)
|
61
|
+
if aggregate.deleted?
|
62
|
+
aggregate.destroy
|
63
|
+
else
|
64
|
+
aggregate.save
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end # SimpleStorageListener
|
68
|
+
end # Repository
|
69
|
+
end
|
data/lib/synapse/repository.rb
CHANGED
@@ -55,12 +55,12 @@ module Synapse
|
|
55
55
|
|
56
56
|
# Delegators for message attribute readers
|
57
57
|
def_delegators :@message, :id, :metadata, :payload, :payload_type, :timestamp
|
58
|
-
end
|
58
|
+
end # SerializationAwareEventMessage
|
59
59
|
|
60
60
|
# Decorator for a domain event message that adds serialization awareness
|
61
61
|
class SerializationAwareDomainEventMessage < SerializationAwareEventMessage
|
62
62
|
# Delegators for domain event specific attribute readers
|
63
63
|
def_delegators :@message, :aggregate_id, :sequence_number
|
64
|
-
end
|
65
|
-
end
|
64
|
+
end # SerializationAwareDomainEventMessage
|
65
|
+
end # Serialization
|
66
66
|
end
|
@@ -44,9 +44,7 @@ module Synapse
|
|
44
44
|
# @param [Hash] additional_metadata
|
45
45
|
# @return [SerializedMessage]
|
46
46
|
def and_metadata(additional_metadata)
|
47
|
-
if additional_metadata.empty?
|
48
|
-
return self
|
49
|
-
end
|
47
|
+
return self if additional_metadata.empty?
|
50
48
|
|
51
49
|
self.class.build do |builder|
|
52
50
|
build_duplicate builder, metadata.merge(additional_metadata)
|
@@ -59,9 +57,7 @@ module Synapse
|
|
59
57
|
# @param [Hash] replacement_metadata
|
60
58
|
# @return [SerializedMessage]
|
61
59
|
def with_metadata(replacement_metadata)
|
62
|
-
if @serialized_metadata.deserialized == replacement_metadata
|
63
|
-
return self
|
64
|
-
end
|
60
|
+
return self if @serialized_metadata.deserialized == replacement_metadata
|
65
61
|
|
66
62
|
self.class.build do |builder|
|
67
63
|
build_duplicate builder, replacement_metadata
|
@@ -126,7 +122,7 @@ module Synapse
|
|
126
122
|
serializer.serialize object.deserialized, expected_type
|
127
123
|
end
|
128
124
|
end
|
129
|
-
end
|
125
|
+
end # SerializedMessage
|
130
126
|
|
131
127
|
# Serialized representation of an event message
|
132
128
|
class SerializedEventMessage < SerializedMessage
|
@@ -157,7 +153,7 @@ module Synapse
|
|
157
153
|
super
|
158
154
|
builder.timestamp = @timestamp
|
159
155
|
end
|
160
|
-
end
|
156
|
+
end # SerializedEventMessage
|
161
157
|
|
162
158
|
# Serialized representation of a domain event message
|
163
159
|
class SerializedDomainEventMessage < SerializedEventMessage
|
@@ -196,6 +192,6 @@ module Synapse
|
|
196
192
|
builder.aggregate_id = @aggregate_id
|
197
193
|
builder.sequence_number = @sequence_number
|
198
194
|
end
|
199
|
-
end
|
200
|
-
end
|
195
|
+
end # SerializedDomainEventMessage
|
196
|
+
end # Serialization
|
201
197
|
end
|
@@ -22,7 +22,7 @@ module Synapse
|
|
22
22
|
def build
|
23
23
|
SerializedMessage.new @id, @metadata, @payload
|
24
24
|
end
|
25
|
-
end
|
25
|
+
end # SerializedMessageBuilder
|
26
26
|
|
27
27
|
# Message builder capable of producing SerializedEventMessage instances
|
28
28
|
class SerializedEventMessageBuilder < SerializedMessageBuilder
|
@@ -33,7 +33,7 @@ module Synapse
|
|
33
33
|
def build
|
34
34
|
SerializedEventMessage.new @id, @metadata, @payload, @timestamp
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end # SerializedEventMessageBuilder
|
37
37
|
|
38
38
|
# Message builder capable of producing SerializedDomainEventMessage instances
|
39
39
|
class SerializedDomainEventMessageBuilder < SerializedEventMessageBuilder
|
@@ -59,6 +59,6 @@ module Synapse
|
|
59
59
|
def build
|
60
60
|
SerializedDomainEventMessage.new @id, @metadata, @payload, @timestamp, @aggregate_id, @sequence_number
|
61
61
|
end
|
62
|
-
end
|
63
|
-
end
|
62
|
+
end # SerializedDomainEventMessageBuilder
|
63
|
+
end # Serialization
|
64
64
|
end
|
@@ -9,7 +9,7 @@ module Synapse
|
|
9
9
|
# @param [Class] payload_type
|
10
10
|
# @return [String] The revision of the given payload type
|
11
11
|
def revision_of(payload_type); end
|
12
|
-
end
|
12
|
+
end # RevisionResolver
|
13
13
|
|
14
14
|
# Implementation of a revision resolver that returns a fixed value. This could be an
|
15
15
|
# application version number, for example
|
@@ -25,6 +25,6 @@ module Synapse
|
|
25
25
|
def revision_of(payload_type)
|
26
26
|
@revision.to_s
|
27
27
|
end
|
28
|
-
end
|
29
|
-
end
|
28
|
+
end # FixedRevisionResolver
|
29
|
+
end # Serialization
|
30
30
|
end
|