synapse-core 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/synapse.rb +3 -0
- data/lib/synapse/command/simple_command_bus.rb +2 -2
- data/lib/synapse/common/concurrency/identifier_lock.rb +71 -0
- data/lib/synapse/common/concurrency/public_lock.rb +96 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +1 -1
- data/lib/synapse/event_bus/wiring.rb +0 -4
- data/lib/synapse/event_sourcing/member.rb +0 -4
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +2 -2
- data/lib/synapse/event_store.rb +1 -9
- data/lib/synapse/partitioning.rb +0 -2
- data/lib/synapse/process_manager.rb +12 -0
- data/lib/synapse/process_manager/lock_manager.rb +22 -0
- data/lib/synapse/process_manager/pessimistic_lock_manager.rb +23 -0
- data/lib/synapse/process_manager/process.rb +2 -0
- data/lib/synapse/process_manager/process_factory.rb +52 -0
- data/lib/synapse/process_manager/process_manager.rb +170 -0
- data/lib/synapse/process_manager/process_repository.rb +53 -0
- data/lib/synapse/process_manager/repository/in_memory.rb +63 -0
- data/lib/synapse/process_manager/resource_injector.rb +12 -0
- data/lib/synapse/process_manager/simple_process_manager.rb +48 -0
- data/lib/synapse/process_manager/wiring/process.rb +27 -0
- data/lib/synapse/process_manager/wiring/process_manager.rb +72 -0
- data/lib/synapse/repository.rb +1 -0
- data/lib/synapse/repository/locking.rb +1 -1
- data/lib/synapse/repository/optimistic_lock_manager.rb +128 -0
- data/lib/synapse/repository/pessimistic_lock_manager.rb +4 -37
- data/lib/synapse/serialization.rb +1 -1
- data/lib/synapse/serialization/{converter/factory.rb → converter_factory.rb} +0 -0
- data/lib/synapse/serialization/serializer.rb +5 -3
- data/lib/synapse/uow/listener_collection.rb +59 -1
- data/lib/synapse/version.rb +1 -1
- data/lib/synapse/wiring/message_wiring.rb +7 -3
- data/lib/synapse/wiring/wire.rb +7 -2
- data/test/common/concurrency/identifier_lock_test.rb +36 -0
- data/test/common/concurrency/public_lock_test.rb +83 -0
- data/test/partitioning/packing/json_test.rb +2 -1
- data/test/process_manager/in_memory_test.rb +57 -0
- data/test/process_manager/process_factory_test.rb +31 -0
- data/test/process_manager/simple_process_manager_test.rb +130 -0
- data/test/process_manager/wiring/fixtures.rb +42 -0
- data/test/process_manager/wiring/process_manager_test.rb +73 -0
- data/test/process_manager/wiring/process_test.rb +35 -0
- data/test/repository/optimistic_test.rb +41 -0
- data/test/repository/pessimistic_test.rb +20 -0
- data/test/serialization/converter/chain_test.rb +31 -0
- data/test/serialization/lazy_object_test.rb +1 -1
- data/test/serialization/message/serialization_aware_message_test.rb +4 -2
- data/test/serialization/message/serialized_message_builder_test.rb +1 -1
- data/test/serialization/message/serialized_message_test.rb +3 -2
- data/test/serialization/serializer/marshal_test.rb +1 -1
- data/test/serialization/serializer/oj_test.rb +1 -1
- data/test/serialization/serializer/ox_test.rb +1 -1
- data/test/serialization/serializer_test.rb +1 -1
- data/test/test_ext.rb +5 -2
- data/test/wiring/wire_registry_test.rb +10 -10
- data/test/wiring/wire_test.rb +5 -5
- metadata +29 -16
- data/lib/synapse/event_store/mongo.rb +0 -8
- data/lib/synapse/event_store/mongo/cursor_event_stream.rb +0 -63
- data/lib/synapse/event_store/mongo/event_store.rb +0 -86
- data/lib/synapse/event_store/mongo/per_commit_strategy.rb +0 -253
- data/lib/synapse/event_store/mongo/per_event_strategy.rb +0 -143
- data/lib/synapse/event_store/mongo/storage_strategy.rb +0 -113
- data/lib/synapse/event_store/mongo/template.rb +0 -73
- data/lib/synapse/partitioning/amqp.rb +0 -3
- data/lib/synapse/partitioning/amqp/amqp_queue_reader.rb +0 -50
- data/lib/synapse/partitioning/amqp/amqp_queue_writer.rb +0 -31
- data/lib/synapse/partitioning/amqp/key_resolver.rb +0 -26
- data/lib/synapse/serialization/converter/bson.rb +0 -28
@@ -1,113 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module EventStore
|
3
|
-
module Mongo
|
4
|
-
# Represents a mechanism used to structure how events are stored in the database
|
5
|
-
# @abstract
|
6
|
-
class StorageStrategy
|
7
|
-
# @param [MongoTemplate] template
|
8
|
-
# @param [Serializer] serializer
|
9
|
-
# @param [UpcasterChain] upcaster_chain
|
10
|
-
# @return [undefined]
|
11
|
-
def initialize(template, serializer, upcaster_chain)
|
12
|
-
@template = template
|
13
|
-
@serializer = Serialization::MessageSerializer.new serializer
|
14
|
-
@upcaster_chain = upcaster_chain
|
15
|
-
end
|
16
|
-
|
17
|
-
# Creates documents that will represent the events being committed to the event store
|
18
|
-
#
|
19
|
-
# @abstract
|
20
|
-
# @param [String] type_identifier Type identifier for the aggregate
|
21
|
-
# @param [Array] events Domain events to be committed
|
22
|
-
# @return [Array]
|
23
|
-
def create_documents(type_identifier, events); end
|
24
|
-
|
25
|
-
# Extracts individual event messages from the given document
|
26
|
-
#
|
27
|
-
# The given aggregate identifier is passed so that event messages can have the actual
|
28
|
-
# identifier object instead of the serialized aggregate identifier.
|
29
|
-
#
|
30
|
-
# @abstract
|
31
|
-
# @param [Hash] document
|
32
|
-
# @param [Object] aggregate_id
|
33
|
-
# @return [Array]
|
34
|
-
def extract_events(document, aggregate_id); end
|
35
|
-
|
36
|
-
# Aliases of the Mongo constants for ascending and descending
|
37
|
-
ASCENDING = ::Mongo::ASCENDING
|
38
|
-
DESCENDING = ::Mongo::DESCENDING
|
39
|
-
|
40
|
-
# Provides a cursor for accessing all events for an aggregate with the given identifier
|
41
|
-
# and type identifier, with a sequence number equal to or greater than the given first
|
42
|
-
# sequence number
|
43
|
-
#
|
44
|
-
# The returned documents should be ordered chronologically, typically by using the
|
45
|
-
# sequence number.
|
46
|
-
#
|
47
|
-
# @param [String] type_identifier
|
48
|
-
# @param [Object] aggregate_id
|
49
|
-
# @param [Integer] first_sequence_number
|
50
|
-
# @return [Mongo::Cursor]
|
51
|
-
def fetch_events(type_identifier, aggregate_id, first_sequence_number)
|
52
|
-
filter = {
|
53
|
-
aggregate_id: aggregate_id,
|
54
|
-
aggregate_type: type_identifier,
|
55
|
-
sequence_number: {
|
56
|
-
'$gte' => first_sequence_number
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
sort = {
|
61
|
-
sequence_number: ASCENDING
|
62
|
-
}
|
63
|
-
|
64
|
-
@template.event_collection.find(filter).sort(sort)
|
65
|
-
end
|
66
|
-
|
67
|
-
# Finds the document containing the most recent snapshot event for an aggregate with the
|
68
|
-
# given identifier and type identifier
|
69
|
-
#
|
70
|
-
# @param [String] type_identifier
|
71
|
-
# @param [Object] aggregate_id
|
72
|
-
# @return [Mongo::Cursor]
|
73
|
-
def fetch_last_snapshot(type_identifier, aggregate_id)
|
74
|
-
filter = {
|
75
|
-
aggregate_id: aggregate_id,
|
76
|
-
aggregate_type: type_identifier
|
77
|
-
}
|
78
|
-
|
79
|
-
sort = {
|
80
|
-
sequence_number: DESCENDING
|
81
|
-
}
|
82
|
-
|
83
|
-
@template.snapshot_collection.find(filter).sort(sort).limit(1)
|
84
|
-
end
|
85
|
-
|
86
|
-
# Ensures that the correct indexes are in place
|
87
|
-
# @return [undefined]
|
88
|
-
def ensure_indexes
|
89
|
-
options = {
|
90
|
-
name: 'unique_aggregate_index',
|
91
|
-
unique: true
|
92
|
-
}
|
93
|
-
|
94
|
-
spec = {
|
95
|
-
aggregate_id: ASCENDING,
|
96
|
-
aggregate_type: ASCENDING,
|
97
|
-
sequence_number: ASCENDING
|
98
|
-
}
|
99
|
-
|
100
|
-
@template.event_collection.ensure_index spec, options
|
101
|
-
|
102
|
-
spec = {
|
103
|
-
aggregate_id: ASCENDING,
|
104
|
-
aggregate_type: ASCENDING,
|
105
|
-
sequence_number: DESCENDING
|
106
|
-
}
|
107
|
-
|
108
|
-
@template.snapshot_collection.ensure_index spec, options
|
109
|
-
end
|
110
|
-
end # StorageStrategy
|
111
|
-
end # Mongo
|
112
|
-
end # EventStore
|
113
|
-
end # Synapse
|
@@ -1,73 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module EventStore
|
3
|
-
module Mongo
|
4
|
-
# Represents a mechanism for accessing collections required by the Mongo event store
|
5
|
-
# @abstract
|
6
|
-
class MongoTemplate
|
7
|
-
# Returns a reference to the collection containing domain events
|
8
|
-
#
|
9
|
-
# @abstract
|
10
|
-
# @return [Mongo::Collection]
|
11
|
-
def event_collection; end
|
12
|
-
|
13
|
-
# Returns a reference to the collection containing snapshot events
|
14
|
-
#
|
15
|
-
# @abstract
|
16
|
-
# @return [Mongo::Collection]
|
17
|
-
def snapshot_collection; end
|
18
|
-
end
|
19
|
-
|
20
|
-
class DefaultMongoTemplate
|
21
|
-
# @return [String] Name of the database to use
|
22
|
-
attr_accessor :database_name
|
23
|
-
|
24
|
-
# @return [String] Username to authenticate with (optional)
|
25
|
-
attr_accessor :username
|
26
|
-
|
27
|
-
# @return [String] Password to authenticate with (optional)
|
28
|
-
attr_accessor :password
|
29
|
-
|
30
|
-
# @return [String] Name of the collection containing domain events
|
31
|
-
attr_accessor :event_collection
|
32
|
-
|
33
|
-
# @return [String] Name of the collection containing snapshot events
|
34
|
-
attr_accessor :snapshot_collection
|
35
|
-
|
36
|
-
# @param [Mongo::MongoClient] client
|
37
|
-
# @return [undefined]
|
38
|
-
def initialize(client)
|
39
|
-
@client = client
|
40
|
-
|
41
|
-
@database_name = 'synapse'
|
42
|
-
@event_collection_name = 'domain_events'
|
43
|
-
@snapshot_collection_name = 'snapshot_events'
|
44
|
-
end
|
45
|
-
|
46
|
-
# @return [Mongo::Collection]
|
47
|
-
def event_collection
|
48
|
-
database.collection @event_collection_name
|
49
|
-
end
|
50
|
-
|
51
|
-
# @return [Mongo::Collection]
|
52
|
-
def snapshot_collection
|
53
|
-
database.collection @snapshot_collection_name
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
# @return [Mongo::DB]
|
59
|
-
def database
|
60
|
-
unless @database
|
61
|
-
@database = @client.db @database_name
|
62
|
-
|
63
|
-
if @username and @password
|
64
|
-
@database.authenticate @username, @password
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
@database
|
69
|
-
end
|
70
|
-
end # DefaultMongoTemplate
|
71
|
-
end # Mongo
|
72
|
-
end # EventStore
|
73
|
-
end # Synapse
|
@@ -1,50 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Partitioning
|
3
|
-
module AMQP
|
4
|
-
# Implementation of a queue reader that subscribes to an AMQP queue
|
5
|
-
class AMQPQueueReader < QueueReader
|
6
|
-
# The behavior when a message is not acknowledged by a message handler
|
7
|
-
#
|
8
|
-
# When a message is explicitly rejected, this usually indicates that there was an
|
9
|
-
# error while processing the message. When the message is rejected, it can either be
|
10
|
-
# put back on the queue so that it can be retried later, or it can be routed as a dead
|
11
|
-
# letter if using RabbitMQ.
|
12
|
-
#
|
13
|
-
# @see http://www.rabbitmq.com/dlx.html
|
14
|
-
# @return [Boolean] Default value is true
|
15
|
-
attr_accessor :requeue_on_nack
|
16
|
-
|
17
|
-
# @param [AMQP::Queue] queue
|
18
|
-
# @param [AMQP::Channel] channel
|
19
|
-
# @param [MessageUnpacker] unpacker
|
20
|
-
# @return [undefined]
|
21
|
-
def initialize(queue, channel, unpacker)
|
22
|
-
@queue = queue
|
23
|
-
@channel = channel
|
24
|
-
@requeue_on_nack = true
|
25
|
-
end
|
26
|
-
|
27
|
-
# @yield [MessageReceipt] Receipt of the message taken off the queue
|
28
|
-
# @return [undefined]
|
29
|
-
def subscribe(&handler)
|
30
|
-
@queue.subscribe do |headers, packed|
|
31
|
-
receipt = MessageReceipt.new headers.delivery_tag, packed, @queue.name
|
32
|
-
handler.call receipt
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# @param [MessageReceipt] receipt
|
37
|
-
# @return [undefined]
|
38
|
-
def ack_message(receipt)
|
39
|
-
@channel.acknowledge receipt.tag
|
40
|
-
end
|
41
|
-
|
42
|
-
# @param [MessageReceipt] receipt
|
43
|
-
# @return [undefined]
|
44
|
-
def nack_message(receipt)
|
45
|
-
@channel.reject receipt.tag, @requeue_on_nack
|
46
|
-
end
|
47
|
-
end # AMQPQueueReader
|
48
|
-
end # AMQP
|
49
|
-
end # Partitioning
|
50
|
-
end # Synapse
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Partitioning
|
3
|
-
module AMQP
|
4
|
-
# Implementation of a queue writer that publishes packed messages to an AMQP exchange
|
5
|
-
class AMQPQueueWriter < QueueWriter
|
6
|
-
# @return [Hash] Additional options that will be used when publishing messages
|
7
|
-
attr_accessor :publish_options
|
8
|
-
|
9
|
-
# @param [AMQP::Exchange] exchange
|
10
|
-
# @param [RoutingKeyResolver] key_resolver
|
11
|
-
# @return [undefined]
|
12
|
-
def initialize(exchange, key_resolver)
|
13
|
-
@exchange = exchange
|
14
|
-
@key_resolver = key_resolver
|
15
|
-
@publish_options = Hash.new
|
16
|
-
end
|
17
|
-
|
18
|
-
# @param [Object] packed
|
19
|
-
# @param [Message] unpacked
|
20
|
-
# @return [undefined]
|
21
|
-
def put_message(packed, unpacked)
|
22
|
-
publish_options = {
|
23
|
-
routing_key: @key_resolver.resolve_key(unpacked)
|
24
|
-
}
|
25
|
-
|
26
|
-
@exchange.publish(packed, @publish_options.merge(publish_options))
|
27
|
-
end
|
28
|
-
end # AMQPQueueWriter
|
29
|
-
end # AMQP
|
30
|
-
end # Partitioning
|
31
|
-
end # Synapse
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Partitioning
|
3
|
-
module AMQP
|
4
|
-
# Represents a mechanism for determining the routing key to use when publishing a message
|
5
|
-
class RoutingKeyResolver
|
6
|
-
# Returns the routing key to use when publishing the given message
|
7
|
-
#
|
8
|
-
# @param [Message] message
|
9
|
-
# @return [String]
|
10
|
-
def resolve_key(message); end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Implementation of a routing key resolver that uses the message payload's module name
|
14
|
-
class ModuleRoutingKeyResolver
|
15
|
-
# @param [Message] message
|
16
|
-
# @return [String]
|
17
|
-
def resolve_key(message)
|
18
|
-
type = message.payload_type.to_s
|
19
|
-
type.deconstantize.underscore.tap do |key|
|
20
|
-
key.tr! '/', '.'
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end # AMQP
|
25
|
-
end # Partitioning
|
26
|
-
end # Synapse
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'bson'
|
2
|
-
|
3
|
-
module Synapse
|
4
|
-
module Serialization
|
5
|
-
# Converter that converts an ordered hash from BSON into a regular Ruby hash
|
6
|
-
class OrderedHashToHashConverter
|
7
|
-
include Converter
|
8
|
-
|
9
|
-
converts BSON::OrderedHash, Hash
|
10
|
-
|
11
|
-
# @param [Object] original
|
12
|
-
# @return [Object]
|
13
|
-
def convert_content(original)
|
14
|
-
converted = Hash.new
|
15
|
-
|
16
|
-
original.each do |key, value|
|
17
|
-
if value.is_a? BSON::OrderedHash
|
18
|
-
value = convert_content value
|
19
|
-
end
|
20
|
-
|
21
|
-
converted[key] = value
|
22
|
-
end
|
23
|
-
|
24
|
-
converted
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|