synapse-core 0.4.0 → 0.5.1
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 +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
|