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.
Files changed (69) hide show
  1. data/lib/synapse.rb +3 -0
  2. data/lib/synapse/command/simple_command_bus.rb +2 -2
  3. data/lib/synapse/common/concurrency/identifier_lock.rb +71 -0
  4. data/lib/synapse/common/concurrency/public_lock.rb +96 -0
  5. data/lib/synapse/event_bus/simple_event_bus.rb +1 -1
  6. data/lib/synapse/event_bus/wiring.rb +0 -4
  7. data/lib/synapse/event_sourcing/member.rb +0 -4
  8. data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +2 -2
  9. data/lib/synapse/event_store.rb +1 -9
  10. data/lib/synapse/partitioning.rb +0 -2
  11. data/lib/synapse/process_manager.rb +12 -0
  12. data/lib/synapse/process_manager/lock_manager.rb +22 -0
  13. data/lib/synapse/process_manager/pessimistic_lock_manager.rb +23 -0
  14. data/lib/synapse/process_manager/process.rb +2 -0
  15. data/lib/synapse/process_manager/process_factory.rb +52 -0
  16. data/lib/synapse/process_manager/process_manager.rb +170 -0
  17. data/lib/synapse/process_manager/process_repository.rb +53 -0
  18. data/lib/synapse/process_manager/repository/in_memory.rb +63 -0
  19. data/lib/synapse/process_manager/resource_injector.rb +12 -0
  20. data/lib/synapse/process_manager/simple_process_manager.rb +48 -0
  21. data/lib/synapse/process_manager/wiring/process.rb +27 -0
  22. data/lib/synapse/process_manager/wiring/process_manager.rb +72 -0
  23. data/lib/synapse/repository.rb +1 -0
  24. data/lib/synapse/repository/locking.rb +1 -1
  25. data/lib/synapse/repository/optimistic_lock_manager.rb +128 -0
  26. data/lib/synapse/repository/pessimistic_lock_manager.rb +4 -37
  27. data/lib/synapse/serialization.rb +1 -1
  28. data/lib/synapse/serialization/{converter/factory.rb → converter_factory.rb} +0 -0
  29. data/lib/synapse/serialization/serializer.rb +5 -3
  30. data/lib/synapse/uow/listener_collection.rb +59 -1
  31. data/lib/synapse/version.rb +1 -1
  32. data/lib/synapse/wiring/message_wiring.rb +7 -3
  33. data/lib/synapse/wiring/wire.rb +7 -2
  34. data/test/common/concurrency/identifier_lock_test.rb +36 -0
  35. data/test/common/concurrency/public_lock_test.rb +83 -0
  36. data/test/partitioning/packing/json_test.rb +2 -1
  37. data/test/process_manager/in_memory_test.rb +57 -0
  38. data/test/process_manager/process_factory_test.rb +31 -0
  39. data/test/process_manager/simple_process_manager_test.rb +130 -0
  40. data/test/process_manager/wiring/fixtures.rb +42 -0
  41. data/test/process_manager/wiring/process_manager_test.rb +73 -0
  42. data/test/process_manager/wiring/process_test.rb +35 -0
  43. data/test/repository/optimistic_test.rb +41 -0
  44. data/test/repository/pessimistic_test.rb +20 -0
  45. data/test/serialization/converter/chain_test.rb +31 -0
  46. data/test/serialization/lazy_object_test.rb +1 -1
  47. data/test/serialization/message/serialization_aware_message_test.rb +4 -2
  48. data/test/serialization/message/serialized_message_builder_test.rb +1 -1
  49. data/test/serialization/message/serialized_message_test.rb +3 -2
  50. data/test/serialization/serializer/marshal_test.rb +1 -1
  51. data/test/serialization/serializer/oj_test.rb +1 -1
  52. data/test/serialization/serializer/ox_test.rb +1 -1
  53. data/test/serialization/serializer_test.rb +1 -1
  54. data/test/test_ext.rb +5 -2
  55. data/test/wiring/wire_registry_test.rb +10 -10
  56. data/test/wiring/wire_test.rb +5 -5
  57. metadata +29 -16
  58. data/lib/synapse/event_store/mongo.rb +0 -8
  59. data/lib/synapse/event_store/mongo/cursor_event_stream.rb +0 -63
  60. data/lib/synapse/event_store/mongo/event_store.rb +0 -86
  61. data/lib/synapse/event_store/mongo/per_commit_strategy.rb +0 -253
  62. data/lib/synapse/event_store/mongo/per_event_strategy.rb +0 -143
  63. data/lib/synapse/event_store/mongo/storage_strategy.rb +0 -113
  64. data/lib/synapse/event_store/mongo/template.rb +0 -73
  65. data/lib/synapse/partitioning/amqp.rb +0 -3
  66. data/lib/synapse/partitioning/amqp/amqp_queue_reader.rb +0 -50
  67. data/lib/synapse/partitioning/amqp/amqp_queue_writer.rb +0 -31
  68. data/lib/synapse/partitioning/amqp/key_resolver.rb +0 -26
  69. 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,3 +0,0 @@
1
- require 'synapse/partitioning/amqp/amqp_queue_reader'
2
- require 'synapse/partitioning/amqp/amqp_queue_writer'
3
- require 'synapse/partitioning/amqp/key_resolver'
@@ -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