synapse-core 0.2.0 → 0.4.0

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.
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