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.
- 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
data/lib/synapse.rb
CHANGED
@@ -10,6 +10,9 @@ require 'synapse/common/identifier'
|
|
10
10
|
require 'synapse/common/message'
|
11
11
|
require 'synapse/common/message_builder'
|
12
12
|
|
13
|
+
require 'synapse/common/concurrency/identifier_lock'
|
14
|
+
require 'synapse/common/concurrency/public_lock'
|
15
|
+
|
13
16
|
module Synapse
|
14
17
|
extend ActiveSupport::Autoload
|
15
18
|
|
@@ -18,7 +18,7 @@ module Synapse
|
|
18
18
|
@handlers = Hash.new
|
19
19
|
@filters = Array.new
|
20
20
|
@interceptors = Array.new
|
21
|
-
@logger = Logging.logger
|
21
|
+
@logger = Logging.logger[self.class]
|
22
22
|
@rollback_policy = RollbackOnAnyExceptionPolicy.new
|
23
23
|
@unit_factory = unit_factory
|
24
24
|
end
|
@@ -100,7 +100,7 @@ module Synapse
|
|
100
100
|
chain = InterceptorChain.new unit, @interceptors, handler
|
101
101
|
|
102
102
|
begin
|
103
|
-
@logger.
|
103
|
+
@logger.info 'Dispatching command [%s] [%s] to handler [%s]' %
|
104
104
|
[command.id, command.payload_type, handler.class]
|
105
105
|
|
106
106
|
result = chain.proceed command
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Synapse
|
2
|
+
# @todo Deadlock detection
|
3
|
+
class IdentifierLock
|
4
|
+
# @return [undefined]
|
5
|
+
def initialize
|
6
|
+
@identifiers = Hash.new
|
7
|
+
@lock = Mutex.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns true if the calling thread holds the lock for the given identifier
|
11
|
+
#
|
12
|
+
# @param [Object] identifier
|
13
|
+
# @return [Boolean]
|
14
|
+
def owned?(identifier)
|
15
|
+
lock_available?(identifier) and lock_for(identifier).owned?
|
16
|
+
end
|
17
|
+
|
18
|
+
# Obtains a lock for the given identifier, blocking until the lock is obtained
|
19
|
+
#
|
20
|
+
# @param [Object] identifier
|
21
|
+
# @return [undefined]
|
22
|
+
def obtain_lock(identifier)
|
23
|
+
lock_for(identifier).lock
|
24
|
+
end
|
25
|
+
|
26
|
+
# Releases a lock for the given identifier
|
27
|
+
#
|
28
|
+
# @raise [ThreadError] If no lock was ever obtained for the identifier
|
29
|
+
# @param [Object] identifier
|
30
|
+
# @return [undefined]
|
31
|
+
def release_lock(identifier)
|
32
|
+
unless lock_available? identifier
|
33
|
+
raise ThreadError, 'No lock for this identifier was ever obtained'
|
34
|
+
end
|
35
|
+
|
36
|
+
lock_for(identifier).unlock
|
37
|
+
dispose_if_unused(identifier)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def lock_for(identifier)
|
43
|
+
@lock.synchronize do
|
44
|
+
if @identifiers.has_key? identifier
|
45
|
+
@identifiers[identifier]
|
46
|
+
else
|
47
|
+
@identifiers[identifier] = PublicLock.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def lock_available?(identifier)
|
53
|
+
@identifiers.has_key? identifier
|
54
|
+
end
|
55
|
+
|
56
|
+
# Disposes of the lock for the given identifier if it has no threads waiting for it
|
57
|
+
#
|
58
|
+
# @param [String] identifier
|
59
|
+
# @return [undefined]
|
60
|
+
def dispose_if_unused(identifier)
|
61
|
+
lock = lock_for identifier
|
62
|
+
if lock.try_lock
|
63
|
+
@lock.synchronize do
|
64
|
+
@identifiers.delete identifier
|
65
|
+
end
|
66
|
+
|
67
|
+
lock.unlock
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end # IdentifierLock
|
71
|
+
end # Synapse
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
module Synapse
|
4
|
+
class PublicLock
|
5
|
+
# @return [Thread] The current owner of the thread, if any
|
6
|
+
attr_reader :owner
|
7
|
+
|
8
|
+
# @return [Array] The list of threads waiting for this lock
|
9
|
+
attr_reader :waiting
|
10
|
+
|
11
|
+
# @return [undefined]
|
12
|
+
def initialize
|
13
|
+
@mutex = Mutex.new
|
14
|
+
@condition = ConditionVariable.new
|
15
|
+
@waiting = Array.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns true if the calling thread owns this lock
|
19
|
+
#
|
20
|
+
# @see Mutex#owned?
|
21
|
+
# @return [Boolean]
|
22
|
+
def owned?
|
23
|
+
@owner == Thread.current
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if the given thread owns this lock
|
27
|
+
# @return [Boolean]
|
28
|
+
def owned_by?(thread)
|
29
|
+
@owner == thread
|
30
|
+
end
|
31
|
+
|
32
|
+
# @see Mutex#synchronize
|
33
|
+
# @return [undefined]
|
34
|
+
def synchronize
|
35
|
+
lock
|
36
|
+
|
37
|
+
begin
|
38
|
+
yield
|
39
|
+
ensure
|
40
|
+
unlock rescue nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @see Mutex#lock
|
45
|
+
# @return [undefined]
|
46
|
+
def lock
|
47
|
+
@mutex.synchronize do
|
48
|
+
if @owner == Thread.current
|
49
|
+
raise ThreadError, 'Lock is already owned by the current thread'
|
50
|
+
end
|
51
|
+
|
52
|
+
while @owner
|
53
|
+
begin
|
54
|
+
@waiting.push Thread.current
|
55
|
+
@condition.wait @mutex
|
56
|
+
ensure
|
57
|
+
@waiting.delete Thread.current
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
@owner = Thread.current
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @see Mutex#unlock
|
66
|
+
# @return [undefined]
|
67
|
+
def unlock
|
68
|
+
@mutex.synchronize do
|
69
|
+
if @owner == Thread.current
|
70
|
+
@owner = nil
|
71
|
+
@condition.signal
|
72
|
+
else
|
73
|
+
raise ThreadError, 'Lock is not owned by the current thread'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @see Mutex#try_lock
|
79
|
+
# @return [Boolean]]
|
80
|
+
def try_lock
|
81
|
+
@mutex.synchronize do
|
82
|
+
if @owner == Thread.current
|
83
|
+
raise ThreadError, 'Lock is already owned by the current thread'
|
84
|
+
end
|
85
|
+
|
86
|
+
if @owner
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
|
90
|
+
@owner = Thread.current
|
91
|
+
end
|
92
|
+
|
93
|
+
true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -24,7 +24,7 @@ module Synapse
|
|
24
24
|
def initialize(snapshot_taker, unit_provider)
|
25
25
|
@counters = Hash.new
|
26
26
|
@lock = Mutex.new
|
27
|
-
@logger = Logging.logger
|
27
|
+
@logger = Logging.logger[self.class]
|
28
28
|
@threshold = DEFAULT_THRESHOLD
|
29
29
|
|
30
30
|
@snapshot_taker = snapshot_taker
|
@@ -40,7 +40,7 @@ module Synapse
|
|
40
40
|
# @return [undefined]
|
41
41
|
def trigger_snapshot(type_identifier, aggregate_id, counter)
|
42
42
|
if counter.value > @threshold
|
43
|
-
@logger.
|
43
|
+
@logger.info 'Snapshot threshold reached for [%s] [%s]' % [type_identifier, aggregate_id]
|
44
44
|
|
45
45
|
@snapshot_taker.schedule_snapshot type_identifier, aggregate_id
|
46
46
|
counter.value = 1
|
data/lib/synapse/event_store.rb
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
module Synapse
|
2
|
-
module EventStore
|
3
|
-
extend ActiveSupport::Autoload
|
4
|
-
|
5
|
-
autoload :InMemoryEventStore, 'synapse/event_store/in_memory'
|
6
|
-
autoload :Mongo
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
1
|
require 'synapse/event_store/errors'
|
11
2
|
require 'synapse/event_store/event_store'
|
3
|
+
require 'synapse/event_store/in_memory'
|
data/lib/synapse/partitioning.rb
CHANGED
@@ -1,4 +1,16 @@
|
|
1
1
|
require 'synapse/process_manager/correlation'
|
2
2
|
require 'synapse/process_manager/correlation_resolver'
|
3
3
|
require 'synapse/process_manager/correlation_set'
|
4
|
+
require 'synapse/process_manager/lock_manager'
|
5
|
+
require 'synapse/process_manager/pessimistic_lock_manager'
|
4
6
|
require 'synapse/process_manager/process'
|
7
|
+
require 'synapse/process_manager/process_factory'
|
8
|
+
require 'synapse/process_manager/process_manager'
|
9
|
+
require 'synapse/process_manager/process_repository'
|
10
|
+
require 'synapse/process_manager/resource_injector'
|
11
|
+
require 'synapse/process_manager/simple_process_manager'
|
12
|
+
|
13
|
+
require 'synapse/process_manager/wiring/process'
|
14
|
+
require 'synapse/process_manager/wiring/process_manager'
|
15
|
+
|
16
|
+
require 'synapse/process_manager/repository/in_memory'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Synapse
|
2
|
+
module ProcessManager
|
3
|
+
# Represents a mechanism for synchronizing access to processes
|
4
|
+
#
|
5
|
+
# This base implementation does no locking; it can be used if processes are thread safe
|
6
|
+
# and don't need any additional synchronization.
|
7
|
+
class LockManager
|
8
|
+
# Obtains a lock for a process with the given identifier, blocking if necessary
|
9
|
+
#
|
10
|
+
# @param [String] process_id
|
11
|
+
# @return [undefined]
|
12
|
+
def obtain_lock(process_id); end
|
13
|
+
|
14
|
+
# Releases the lock for a process with the given identifier
|
15
|
+
#
|
16
|
+
# @raise [ThreadError] If thread didn't previously hold the lock
|
17
|
+
# @param [String] process_id
|
18
|
+
# @return [undefined]
|
19
|
+
def release_lock(process_id); end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Synapse
|
2
|
+
module ProcessManager
|
3
|
+
# Lock manager that does pessimistic locking for processes
|
4
|
+
class PessimisticLockManager
|
5
|
+
def initialize
|
6
|
+
@lock = IdentifierLock.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# @param [String] process_id
|
10
|
+
# @return [undefined]
|
11
|
+
def obtain_lock(process_id)
|
12
|
+
@lock.obtain_lock process_id
|
13
|
+
end
|
14
|
+
|
15
|
+
# @raise [ThreadError] If thread didn't previously hold the lock
|
16
|
+
# @param [String] process_id
|
17
|
+
# @return [undefined]
|
18
|
+
def release_lock(process_id)
|
19
|
+
@lock.release_lock process_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Synapse
|
2
2
|
module ProcessManager
|
3
|
+
# Processes are used to maintain the state of long-running business transactions
|
4
|
+
#
|
3
5
|
# The term process is used in Enterprise Integration Patterns to describe a mechanism used to
|
4
6
|
# "maintain the state of the sequence and determine the next processing step based on
|
5
7
|
# intermediate results" (Hohpe 279). Processes are also called sagas in some CQRS frameworks.
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Synapse
|
2
|
+
module ProcessManager
|
3
|
+
# Represents a mechanism for create instances of processes
|
4
|
+
# @abstract
|
5
|
+
class ProcessFactory
|
6
|
+
# Creates a new instance of a process of a given type
|
7
|
+
#
|
8
|
+
# The returned process will be fully initialized and any resources required will be
|
9
|
+
# provided through dependency injection.
|
10
|
+
#
|
11
|
+
# @abstract
|
12
|
+
# @param [Class] process_type
|
13
|
+
# @return [Process]
|
14
|
+
def create(process_type); end
|
15
|
+
|
16
|
+
# Returns true if processes of the given type can be created by this factory
|
17
|
+
#
|
18
|
+
# @abstract
|
19
|
+
# @param [Class] process_type
|
20
|
+
# @return [Boolean]
|
21
|
+
def supports(process_type); end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generic implementation of a process factory that supports any process implementations that
|
25
|
+
# have a no-argument constructor
|
26
|
+
class GenericProcessFactory < ProcessFactory
|
27
|
+
# @return [ResourceInjector]
|
28
|
+
attr_accessor :resource_injector
|
29
|
+
|
30
|
+
# @return [undefined]
|
31
|
+
def initialize
|
32
|
+
@resource_injector = ResourceInjector.new
|
33
|
+
end
|
34
|
+
|
35
|
+
# @param [Class] process_type
|
36
|
+
# @return [Process]
|
37
|
+
def create(process_type)
|
38
|
+
process = process_type.new
|
39
|
+
process.tap do
|
40
|
+
@resource_injector.inject_resources process
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Class] process_type
|
45
|
+
# @return [Boolean]
|
46
|
+
def supports(process_type)
|
47
|
+
ctor = process_type.instance_method :initialize
|
48
|
+
ctor.arity <= 0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module Synapse
|
2
|
+
module ProcessManager
|
3
|
+
# Represents a mechanism for managing the lifeycle and notification of process instances
|
4
|
+
# @abstract
|
5
|
+
class ProcessManager
|
6
|
+
include EventBus::EventListener
|
7
|
+
|
8
|
+
# @return [Boolean] Returns true if exceptions will be logged silently
|
9
|
+
attr_accessor :suppress_exceptions
|
10
|
+
|
11
|
+
# @param [ProcessRepository] repository
|
12
|
+
# @param [ProcessFactory] factory
|
13
|
+
# @param [LockManager] lock_manager
|
14
|
+
# @param [Class...] process_types
|
15
|
+
# @return [undefined]
|
16
|
+
def initialize(repository, factory, lock_manager, *process_types)
|
17
|
+
@repository = repository
|
18
|
+
@factory = factory
|
19
|
+
@lock_manager = lock_manager
|
20
|
+
@process_types = process_types.flatten
|
21
|
+
|
22
|
+
@logger = Logging.logger[self.class]
|
23
|
+
@suppress_exceptions = true
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [EventMessage] event
|
27
|
+
# @return [undefined]
|
28
|
+
def notify(event)
|
29
|
+
@process_types.each do |process_type|
|
30
|
+
correlation = extract_correlation process_type, event
|
31
|
+
if correlation
|
32
|
+
current = notify_current_processes process_type, event, correlation
|
33
|
+
if should_start_new_process process_type, event, current
|
34
|
+
start_new_process process_type, event, correlation
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# @abstract
|
43
|
+
# @param [Class] process_type
|
44
|
+
# @param [EventMessage] event
|
45
|
+
# @return [Symbol]
|
46
|
+
def creation_policy_for(process_type, event); end
|
47
|
+
|
48
|
+
# @abstract
|
49
|
+
# @param [Class] process_type
|
50
|
+
# @param [EventMessage] event
|
51
|
+
# @return [Correlation] Returns nil if no correlation could be extracted
|
52
|
+
def extract_correlation(process_type, event); end
|
53
|
+
|
54
|
+
# Determines whether or not a new process should be started, based off of existing processes
|
55
|
+
# and the creation policy for the event and process
|
56
|
+
#
|
57
|
+
# @param [Class] process_type
|
58
|
+
# @param [EventMessage] event
|
59
|
+
# @param [Boolean] current_processes True if there are existing processes
|
60
|
+
# @return [Boolean]
|
61
|
+
def should_start_new_process(process_type, event, current_processes)
|
62
|
+
creation_policy = creation_policy_for process_type, event
|
63
|
+
|
64
|
+
if :always == creation_policy
|
65
|
+
true
|
66
|
+
elsif :if_none_found == creation_policy
|
67
|
+
!current_processes
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Notifies existing processes of the given type and correlation of the given event
|
74
|
+
#
|
75
|
+
# @param [Class] process_type
|
76
|
+
# @param [EventMessage] event
|
77
|
+
# @param [Correlation] correlation
|
78
|
+
# @return [Boolean] Returns true if any current processes were found and notified
|
79
|
+
def notify_current_processes(process_type, event, correlation)
|
80
|
+
processes = @repository.find process_type, correlation
|
81
|
+
|
82
|
+
process_invoked = false
|
83
|
+
processes.each do |process_id|
|
84
|
+
@lock_manager.obtain_lock process_id
|
85
|
+
begin
|
86
|
+
loaded_process = notify_current_process process_id, event, correlation
|
87
|
+
if loaded_process
|
88
|
+
process_invoked = true
|
89
|
+
end
|
90
|
+
ensure
|
91
|
+
@lock_manager.release_lock process_id
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
process_invoked
|
96
|
+
end
|
97
|
+
|
98
|
+
# Loads and notifies the process with the given identifier of the given event
|
99
|
+
#
|
100
|
+
# @param [String] process_id
|
101
|
+
# @param [EventMessage] event
|
102
|
+
# @param [Correlation] correlation
|
103
|
+
# @return [Process]
|
104
|
+
def notify_current_process(process_id, event, correlation)
|
105
|
+
process = @repository.load process_id
|
106
|
+
|
107
|
+
unless process and process.active and process.correlations.include? correlation
|
108
|
+
# Process has changed or was deleted between the time of the selection query and the
|
109
|
+
# actual loading and locking of the process
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
notify_process process, event
|
115
|
+
ensure
|
116
|
+
@repository.commit process
|
117
|
+
end
|
118
|
+
|
119
|
+
process
|
120
|
+
end
|
121
|
+
|
122
|
+
# Creates a new process of the given type with the given correlation
|
123
|
+
#
|
124
|
+
# After the process has been created, it is notified of the given event and then is
|
125
|
+
# committed to the process repository.
|
126
|
+
#
|
127
|
+
# @param [Class] process_type
|
128
|
+
# @param [EventMessage] event
|
129
|
+
# @param [Correlation] correlation
|
130
|
+
# @return [undefined]
|
131
|
+
def start_new_process(process_type, event, correlation)
|
132
|
+
process = @factory.create process_type
|
133
|
+
process.correlations.add correlation
|
134
|
+
|
135
|
+
@lock_manager.obtain_lock process.id
|
136
|
+
|
137
|
+
begin
|
138
|
+
notify_process process, event
|
139
|
+
ensure
|
140
|
+
begin
|
141
|
+
@repository.add process
|
142
|
+
ensure
|
143
|
+
@lock_manager.release_lock process.id
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Notifies the given process with of the given event
|
149
|
+
#
|
150
|
+
# @raise [Exception] If an error occurs while notifying the process and exception
|
151
|
+
# suppression is disabled
|
152
|
+
# @param [Process] process
|
153
|
+
# @param [EventMessage] event
|
154
|
+
# @return [undefined]
|
155
|
+
def notify_process(process, event)
|
156
|
+
begin
|
157
|
+
process.handle event
|
158
|
+
rescue => exception
|
159
|
+
if @suppress_exceptions
|
160
|
+
backtrace = exception.backtrace.join $/
|
161
|
+
@logger.error 'Exception occured while invoking process [%s] [%s] with [%s]: %s %s' %
|
162
|
+
[process.class, process.id, event.payload_type, exception.inspect, backtrace]
|
163
|
+
else
|
164
|
+
raise
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end # ProcessManager
|
169
|
+
end # ProcessManager
|
170
|
+
end
|