cdc-parallel 0.2.2 → 0.2.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +59 -21
- data/README.md +54 -48
- data/lib/cdc/parallel/configuration.rb +33 -6
- data/lib/cdc/parallel/errors.rb +59 -5
- data/lib/cdc/parallel/processor_pool.rb +522 -57
- data/lib/cdc/parallel/result_collector.rb +49 -2
- data/lib/cdc/parallel/router.rb +26 -1
- data/lib/cdc/parallel/runtime.rb +135 -7
- data/lib/cdc/parallel/transaction_pool.rb +87 -5
- data/lib/cdc/parallel/version.rb +6 -1
- data/lib/cdc/parallel.rb +39 -1
- data/sig/cdc/parallel/configuration.rbs +14 -2
- data/sig/cdc/parallel/errors.rbs +7 -7
- data/sig/cdc/parallel/processor_pool.rbs +112 -24
- data/sig/cdc/parallel/result_collector.rbs +6 -4
- data/sig/cdc/parallel/router.rbs +7 -4
- data/sig/cdc/parallel/runtime.rbs +43 -12
- data/sig/cdc/parallel/transaction_pool.rbs +15 -5
- data/sig/cdc/parallel/version.rbs +1 -1
- metadata +5 -23
- data/sig/shims/cdc_core.rbs +0 -14
- data/sig/shims/data_define.rbs +0 -0
- data/sig/shims/etc.rbs +0 -3
- data/sig/shims/timeout.rbs +0 -3
|
@@ -2,22 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
module CDC
|
|
4
4
|
module Parallel
|
|
5
|
-
#
|
|
5
|
+
# Converts raw worker responses into `CDC::Core::ProcessorResult` objects.
|
|
6
|
+
#
|
|
7
|
+
# Ractors cannot freely share arbitrary mutable Ruby objects. Worker
|
|
8
|
+
# responses must therefore be normalized into shareable payloads before they
|
|
9
|
+
# cross back to the caller. `ResultCollector` owns that small translation
|
|
10
|
+
# boundary.
|
|
11
|
+
#
|
|
12
|
+
# The worker side uses {worker_success} and {worker_failure}. The caller side
|
|
13
|
+
# uses {normalize} to convert those payloads into the public result contract.
|
|
14
|
+
#
|
|
15
|
+
# @example Normalizing a processor return value
|
|
16
|
+
# response = CDC::Parallel::ResultCollector.worker_success(value)
|
|
17
|
+
# result = CDC::Parallel::ResultCollector.normalize(response)
|
|
18
|
+
#
|
|
19
|
+
# @example Normalizing a worker exception
|
|
20
|
+
# response = CDC::Parallel::ResultCollector.worker_failure(error)
|
|
21
|
+
# result = CDC::Parallel::ResultCollector.normalize(response)
|
|
22
|
+
# result.failure? #=> true
|
|
23
|
+
#
|
|
24
|
+
# @api public
|
|
6
25
|
class ResultCollector
|
|
26
|
+
# Internal marker used to identify serialized worker failures.
|
|
27
|
+
#
|
|
28
|
+
# @return [Symbol]
|
|
7
29
|
FAILURE_MARKER = :__cdc_parallel_failure__
|
|
8
30
|
|
|
9
31
|
# Build a shareable success payload that can safely cross a Ractor boundary.
|
|
10
32
|
#
|
|
33
|
+
# If the processor already returned a `CDC::Core::ProcessorResult`, that
|
|
34
|
+
# result is preserved. Any other shareable value will later be wrapped in a
|
|
35
|
+
# success result by {normalize}.
|
|
36
|
+
#
|
|
11
37
|
# @param value [Object]
|
|
38
|
+
# Processor return value.
|
|
39
|
+
# @raise [Ractor::Error]
|
|
40
|
+
# Raised by Ruby when the value cannot be made shareable.
|
|
12
41
|
# @return [Object]
|
|
42
|
+
# Shareable success payload.
|
|
13
43
|
def self.worker_success(value)
|
|
14
44
|
::Ractor.make_shareable(value)
|
|
15
45
|
end
|
|
16
46
|
|
|
17
47
|
# Build a shareable failure payload that can safely cross a Ractor boundary.
|
|
18
48
|
#
|
|
49
|
+
# Exceptions themselves are not used as the cross-Ractor payload. Instead,
|
|
50
|
+
# the class name, message, and backtrace are serialized into a simple hash
|
|
51
|
+
# that can be reconstructed as a {ProcessorExecutionError} by {normalize}.
|
|
52
|
+
#
|
|
19
53
|
# @param error [Exception]
|
|
54
|
+
# Exception raised inside a worker Ractor.
|
|
20
55
|
# @return [Hash]
|
|
56
|
+
# Shareable serialized failure payload.
|
|
21
57
|
def self.worker_failure(error)
|
|
22
58
|
::Ractor.make_shareable(
|
|
23
59
|
{
|
|
@@ -29,9 +65,14 @@ module CDC
|
|
|
29
65
|
)
|
|
30
66
|
end
|
|
31
67
|
|
|
32
|
-
# Normalize a worker return value into a ProcessorResult
|
|
68
|
+
# Normalize a worker return value into a `CDC::Core::ProcessorResult`.
|
|
69
|
+
#
|
|
70
|
+
# Failure payloads become failed processor results containing a
|
|
71
|
+
# {ProcessorExecutionError}. Existing processor results are returned
|
|
72
|
+
# unchanged. Other values are wrapped in a successful processor result.
|
|
33
73
|
#
|
|
34
74
|
# @param value [Object]
|
|
75
|
+
# Raw worker response.
|
|
35
76
|
# @return [CDC::Core::ProcessorResult]
|
|
36
77
|
def self.normalize(value)
|
|
37
78
|
if worker_failure?(value)
|
|
@@ -49,6 +90,12 @@ module CDC
|
|
|
49
90
|
end
|
|
50
91
|
end
|
|
51
92
|
|
|
93
|
+
# Return whether a value is a serialized worker failure payload.
|
|
94
|
+
#
|
|
95
|
+
# @param value [Object]
|
|
96
|
+
# Raw worker response.
|
|
97
|
+
# @return [Boolean]
|
|
98
|
+
# @api private
|
|
52
99
|
def self.worker_failure?(value)
|
|
53
100
|
value.is_a?(Hash) && value[:type] == FAILURE_MARKER
|
|
54
101
|
end
|
data/lib/cdc/parallel/router.rb
CHANGED
|
@@ -2,10 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
module CDC
|
|
4
4
|
module Parallel
|
|
5
|
-
# Routes
|
|
5
|
+
# Routes normalized `cdc-core` work items to the matching parallel runtime
|
|
6
|
+
# primitive.
|
|
7
|
+
#
|
|
8
|
+
# `Router` is deliberately small. It does not inspect source-specific
|
|
9
|
+
# payloads, apply filters, decode database values, or decide scheduling
|
|
10
|
+
# policy. Its responsibility is only to look at the already-normalized
|
|
11
|
+
# `cdc-core` object shape and forward it to the pool that knows how to
|
|
12
|
+
# process that shape.
|
|
13
|
+
#
|
|
14
|
+
# @example Routing a single event
|
|
15
|
+
# router.process(change_event)
|
|
16
|
+
#
|
|
17
|
+
# @example Routing a transaction envelope
|
|
18
|
+
# router.process(transaction_envelope)
|
|
19
|
+
#
|
|
20
|
+
# @see CDC::Parallel::ProcessorPool
|
|
21
|
+
# @see CDC::Parallel::TransactionPool
|
|
22
|
+
# @api public
|
|
6
23
|
class Router
|
|
24
|
+
# Create a router for event and transaction work items.
|
|
25
|
+
#
|
|
7
26
|
# @param processor_pool [ProcessorPool]
|
|
27
|
+
# Pool used for individual `CDC::Core::ChangeEvent` objects.
|
|
8
28
|
# @param transaction_pool [TransactionPool]
|
|
29
|
+
# Pool used for `CDC::Core::TransactionEnvelope` objects.
|
|
30
|
+
# @return [void]
|
|
9
31
|
def initialize(processor_pool:, transaction_pool:)
|
|
10
32
|
@processor_pool = processor_pool
|
|
11
33
|
@transaction_pool = transaction_pool
|
|
@@ -14,6 +36,9 @@ module CDC
|
|
|
14
36
|
# Process a supported CDC work item.
|
|
15
37
|
#
|
|
16
38
|
# @param item [CDC::Core::ChangeEvent, CDC::Core::TransactionEnvelope]
|
|
39
|
+
# Normalized CDC work item.
|
|
40
|
+
# @raise [UnsupportedWorkItemError]
|
|
41
|
+
# Raised when the item is not a supported `cdc-core` work item shape.
|
|
17
42
|
# @return [CDC::Core::ProcessorResult]
|
|
18
43
|
def process(item)
|
|
19
44
|
case item
|
data/lib/cdc/parallel/runtime.rb
CHANGED
|
@@ -2,22 +2,101 @@
|
|
|
2
2
|
|
|
3
3
|
module CDC
|
|
4
4
|
module Parallel
|
|
5
|
-
# High-level Ractor runtime facade for cdc-core processors.
|
|
5
|
+
# High-level Ractor runtime facade for `cdc-core` processors.
|
|
6
|
+
#
|
|
7
|
+
# `Runtime` is the primary public entry point for applications that want to
|
|
8
|
+
# execute normalized CDC work items with `cdc-parallel`. It wires together a
|
|
9
|
+
# {ProcessorPool}, a {TransactionPool}, and a {Router} so callers can submit
|
|
10
|
+
# either a single `CDC::Core::ChangeEvent` or a
|
|
11
|
+
# `CDC::Core::TransactionEnvelope` through one object.
|
|
12
|
+
#
|
|
13
|
+
# Use this class when you want the default cdc-parallel behavior:
|
|
14
|
+
#
|
|
15
|
+
# * validate that the processor declared `ractor_safe!`
|
|
16
|
+
# * boot a fixed set of worker Ractors
|
|
17
|
+
# * route events and transaction envelopes to the right pool
|
|
18
|
+
# * return `CDC::Core::ProcessorResult` objects
|
|
19
|
+
# * shut down all worker resources together
|
|
20
|
+
#
|
|
21
|
+
# @example Processing a change event
|
|
22
|
+
# runtime = CDC::Parallel::Runtime.new(
|
|
23
|
+
# processor: AnalyticsProcessor.new,
|
|
24
|
+
# size: 4,
|
|
25
|
+
# timeout: 5
|
|
26
|
+
# )
|
|
27
|
+
#
|
|
28
|
+
# result = runtime.process(change_event)
|
|
29
|
+
# result.success? #=> true
|
|
30
|
+
#
|
|
31
|
+
# runtime.shutdown
|
|
32
|
+
#
|
|
33
|
+
# @example Processing a transaction envelope
|
|
34
|
+
# result = runtime.process_transaction(transaction)
|
|
35
|
+
#
|
|
36
|
+
# @note `Runtime` is an execution facade, not a source adapter. It expects
|
|
37
|
+
# work that has already been normalized into `cdc-core` primitives.
|
|
38
|
+
# @see CDC::Parallel::ProcessorPool
|
|
39
|
+
# @see CDC::Parallel::TransactionPool
|
|
40
|
+
# @see CDC::Parallel::Router
|
|
41
|
+
# @api public
|
|
6
42
|
class Runtime
|
|
43
|
+
# Create a runtime with event and transaction pools.
|
|
44
|
+
#
|
|
7
45
|
# @param processor [CDC::Core::Processor]
|
|
46
|
+
# Ractor-safe processor used for both event and transaction processing.
|
|
8
47
|
# @param size [Integer]
|
|
9
|
-
#
|
|
48
|
+
# Number of worker Ractors per internal pool.
|
|
49
|
+
# @param timeout [Numeric, nil]
|
|
50
|
+
# Optional timeout in seconds for result collection and shutdown waits.
|
|
51
|
+
# @param supervision [Boolean]
|
|
52
|
+
# Whether worker Ractors should be respawned after unexpected death.
|
|
53
|
+
# @param max_respawns [Integer]
|
|
54
|
+
# Maximum crash count inside `respawn_window` before a worker slot enters
|
|
55
|
+
# cooldown.
|
|
56
|
+
# @param respawn_window [Numeric]
|
|
57
|
+
# Time window, in seconds, used by the crash-loop circuit breaker.
|
|
58
|
+
# @param respawn_cooldown [Numeric]
|
|
59
|
+
# Cooldown, in seconds, before a crash-looping slot is revived again.
|
|
60
|
+
# @raise [UnsafeProcessorError]
|
|
61
|
+
# Raised when the processor class has not declared `ractor_safe!`.
|
|
62
|
+
# @raise [ArgumentError]
|
|
63
|
+
# Raised when size or timeout is invalid.
|
|
10
64
|
# @return [void]
|
|
11
|
-
def initialize(
|
|
12
|
-
|
|
13
|
-
|
|
65
|
+
def initialize(
|
|
66
|
+
processor:,
|
|
67
|
+
size: Etc.nprocessors,
|
|
68
|
+
timeout: nil,
|
|
69
|
+
supervision: true,
|
|
70
|
+
max_respawns: 3,
|
|
71
|
+
respawn_window: 60,
|
|
72
|
+
respawn_cooldown: 5
|
|
73
|
+
)
|
|
74
|
+
@processor = processor
|
|
75
|
+
@processor.start
|
|
76
|
+
|
|
77
|
+
pool_options = build_pool_options(
|
|
78
|
+
processor:, size:, timeout:, supervision:,
|
|
79
|
+
max_respawns:, respawn_window:, respawn_cooldown:
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
@processor_pool = ProcessorPool.new(**pool_options)
|
|
83
|
+
@transaction_pool = TransactionPool.new(**pool_options)
|
|
14
84
|
@router = Router.new(processor_pool: @processor_pool, transaction_pool: @transaction_pool)
|
|
15
85
|
@shutdown = false
|
|
16
86
|
end
|
|
17
87
|
|
|
18
|
-
# Process a
|
|
88
|
+
# Process a supported normalized CDC work item.
|
|
89
|
+
#
|
|
90
|
+
# Supported items are `CDC::Core::ChangeEvent` and
|
|
91
|
+
# `CDC::Core::TransactionEnvelope`. Unsupported objects raise
|
|
92
|
+
# {UnsupportedWorkItemError} from the router.
|
|
19
93
|
#
|
|
20
94
|
# @param item [CDC::Core::ChangeEvent, CDC::Core::TransactionEnvelope]
|
|
95
|
+
# Normalized CDC work item.
|
|
96
|
+
# @raise [ShutdownError]
|
|
97
|
+
# Raised when called after {#shutdown}.
|
|
98
|
+
# @raise [UnsupportedWorkItemError]
|
|
99
|
+
# Raised for objects that are not supported CDC work item shapes.
|
|
21
100
|
# @return [CDC::Core::ProcessorResult]
|
|
22
101
|
def process(item)
|
|
23
102
|
raise ShutdownError, "runtime has been shut down" if @shutdown
|
|
@@ -25,7 +104,11 @@ module CDC
|
|
|
25
104
|
@router.process(item)
|
|
26
105
|
end
|
|
27
106
|
|
|
28
|
-
#
|
|
107
|
+
# Process a transaction envelope.
|
|
108
|
+
#
|
|
109
|
+
# This method is a readability alias for transaction-oriented call sites.
|
|
110
|
+
# It delegates to {#process}, so it has the same validation, shutdown, and
|
|
111
|
+
# result behavior.
|
|
29
112
|
#
|
|
30
113
|
# @param transaction [CDC::Core::TransactionEnvelope]
|
|
31
114
|
# @return [CDC::Core::ProcessorResult]
|
|
@@ -35,6 +118,11 @@ module CDC
|
|
|
35
118
|
|
|
36
119
|
# Shut down all runtime resources.
|
|
37
120
|
#
|
|
121
|
+
# Shutdown is idempotent and cascades to the internal event and transaction
|
|
122
|
+
# pools. The processor's `flush` and `stop` lifecycle hooks are called once
|
|
123
|
+
# after all pools have been drained. After shutdown, {#process} raises
|
|
124
|
+
# {ShutdownError}.
|
|
125
|
+
#
|
|
38
126
|
# @return [void]
|
|
39
127
|
def shutdown
|
|
40
128
|
return if @shutdown
|
|
@@ -42,6 +130,46 @@ module CDC
|
|
|
42
130
|
@shutdown = true
|
|
43
131
|
@processor_pool.shutdown
|
|
44
132
|
@transaction_pool.shutdown
|
|
133
|
+
@processor.flush
|
|
134
|
+
@processor.stop
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
# Build keyword arguments shared by the event and transaction pools.
|
|
140
|
+
#
|
|
141
|
+
# The runtime owns the processor lifecycle, so internal pools receive
|
|
142
|
+
# `manage_lifecycle: false` to avoid duplicate `start`, `flush`, or `stop`
|
|
143
|
+
# calls for the same processor instance.
|
|
144
|
+
#
|
|
145
|
+
# @param processor [CDC::Core::Processor]
|
|
146
|
+
# @param size [Integer]
|
|
147
|
+
# @param timeout [Numeric, nil]
|
|
148
|
+
# @param supervision [Boolean]
|
|
149
|
+
# @param max_respawns [Integer]
|
|
150
|
+
# @param respawn_window [Numeric]
|
|
151
|
+
# @param respawn_cooldown [Numeric]
|
|
152
|
+
# @return [Hash]
|
|
153
|
+
# @api private
|
|
154
|
+
def build_pool_options(
|
|
155
|
+
processor:,
|
|
156
|
+
size:,
|
|
157
|
+
timeout:,
|
|
158
|
+
supervision:,
|
|
159
|
+
max_respawns:,
|
|
160
|
+
respawn_window:,
|
|
161
|
+
respawn_cooldown:
|
|
162
|
+
)
|
|
163
|
+
{
|
|
164
|
+
processor:,
|
|
165
|
+
size:,
|
|
166
|
+
timeout:,
|
|
167
|
+
supervision:,
|
|
168
|
+
max_respawns:,
|
|
169
|
+
respawn_window:,
|
|
170
|
+
respawn_cooldown:,
|
|
171
|
+
manage_lifecycle: false
|
|
172
|
+
}
|
|
45
173
|
end
|
|
46
174
|
end
|
|
47
175
|
end
|
|
@@ -2,30 +2,112 @@
|
|
|
2
2
|
|
|
3
3
|
module CDC
|
|
4
4
|
module Parallel
|
|
5
|
-
# Processes a TransactionEnvelope as
|
|
5
|
+
# Processes a `CDC::Core::TransactionEnvelope` as one transaction-oriented
|
|
6
|
+
# work unit.
|
|
7
|
+
#
|
|
8
|
+
# `TransactionPool` uses {ProcessorPool} to process the events inside an
|
|
9
|
+
# envelope and then collapses the event-level results into one
|
|
10
|
+
# `CDC::Core::ProcessorResult` for the whole transaction.
|
|
11
|
+
#
|
|
12
|
+
# This class preserves the transaction boundary at the API level: callers
|
|
13
|
+
# submit a transaction envelope and receive a single success or failure
|
|
14
|
+
# result. Event results inside the transaction are still produced by the
|
|
15
|
+
# configured processor and are returned as the success value when every event
|
|
16
|
+
# succeeds.
|
|
17
|
+
#
|
|
18
|
+
# @example Processing a transaction envelope
|
|
19
|
+
# pool = CDC::Parallel::TransactionPool.new(
|
|
20
|
+
# processor: AuditProcessor.new,
|
|
21
|
+
# size: 4
|
|
22
|
+
# )
|
|
23
|
+
#
|
|
24
|
+
# result = pool.process(transaction)
|
|
25
|
+
# result.success? #=> true
|
|
26
|
+
#
|
|
27
|
+
# @note This class preserves the transaction as a result boundary. More
|
|
28
|
+
# advanced ordering, checkpointing, retry, and atomic sink semantics belong
|
|
29
|
+
# to higher-level runtime/sink contracts.
|
|
30
|
+
# @see CDC::Parallel::ProcessorPool
|
|
31
|
+
# @api public
|
|
6
32
|
class TransactionPool
|
|
33
|
+
# Create a transaction pool.
|
|
34
|
+
#
|
|
7
35
|
# @param processor [CDC::Core::Processor]
|
|
36
|
+
# Ractor-safe processor used for each event inside the transaction.
|
|
8
37
|
# @param size [Integer]
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
38
|
+
# Number of worker Ractors in the underlying processor pool.
|
|
39
|
+
# @param timeout [Numeric, nil]
|
|
40
|
+
# Optional timeout in seconds for result collection and shutdown waits.
|
|
41
|
+
# @param supervision [Boolean]
|
|
42
|
+
# Whether worker Ractors should be respawned after unexpected death.
|
|
43
|
+
# @param max_respawns [Integer]
|
|
44
|
+
# Maximum crash count inside `respawn_window` before a worker slot enters
|
|
45
|
+
# cooldown.
|
|
46
|
+
# @param respawn_window [Numeric]
|
|
47
|
+
# Time window, in seconds, used by the crash-loop circuit breaker.
|
|
48
|
+
# @param respawn_cooldown [Numeric]
|
|
49
|
+
# Cooldown, in seconds, before a crash-looping slot is revived again.
|
|
50
|
+
# @param manage_lifecycle [Boolean]
|
|
51
|
+
# When `true` (default), the pool calls `processor.start` during
|
|
52
|
+
# initialization and `processor.flush` + `processor.stop` during shutdown.
|
|
53
|
+
# Set to `false` when a higher-level runtime owns the processor lifecycle.
|
|
54
|
+
# @raise [UnsafeProcessorError]
|
|
55
|
+
# Raised when the processor class has not declared `ractor_safe!`.
|
|
56
|
+
# @return [void]
|
|
57
|
+
def initialize(
|
|
58
|
+
processor:,
|
|
59
|
+
size: Etc.nprocessors,
|
|
60
|
+
timeout: nil,
|
|
61
|
+
supervision: true,
|
|
62
|
+
max_respawns: 3,
|
|
63
|
+
respawn_window: 60,
|
|
64
|
+
respawn_cooldown: 5,
|
|
65
|
+
manage_lifecycle: true
|
|
66
|
+
)
|
|
67
|
+
@processor_pool = ProcessorPool.new(
|
|
68
|
+
processor:,
|
|
69
|
+
size:,
|
|
70
|
+
timeout:,
|
|
71
|
+
supervision:,
|
|
72
|
+
max_respawns:,
|
|
73
|
+
respawn_window:,
|
|
74
|
+
respawn_cooldown:,
|
|
75
|
+
manage_lifecycle:
|
|
76
|
+
)
|
|
12
77
|
end
|
|
13
78
|
|
|
14
79
|
# Process all events inside a transaction envelope.
|
|
15
80
|
#
|
|
81
|
+
# The returned result is successful only when every event result succeeds.
|
|
82
|
+
# If any event fails, the transaction result is a failure using the first
|
|
83
|
+
# failure error and the complete event-result list as context.
|
|
84
|
+
#
|
|
16
85
|
# @param transaction [CDC::Core::TransactionEnvelope]
|
|
86
|
+
# Transaction envelope whose `events` will be processed.
|
|
17
87
|
# @return [CDC::Core::ProcessorResult]
|
|
88
|
+
# Success containing the ordered event results, or failure containing the
|
|
89
|
+
# first event error.
|
|
18
90
|
def process(transaction)
|
|
19
91
|
results = @processor_pool.process_many(transaction.events).freeze
|
|
20
92
|
failure = results.find(&:failure?)
|
|
21
93
|
|
|
22
|
-
|
|
94
|
+
if failure
|
|
95
|
+
error = failure.error || ProcessorExecutionError.new(
|
|
96
|
+
original_class: "CDC::Core::ProcessorResult",
|
|
97
|
+
original_message: "failed processor result did not include an error"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
return CDC::Core::ProcessorResult.failure(error, event: results)
|
|
101
|
+
end
|
|
23
102
|
|
|
24
103
|
CDC::Core::ProcessorResult.success(results)
|
|
25
104
|
end
|
|
26
105
|
|
|
27
106
|
# Shut down worker resources.
|
|
28
107
|
#
|
|
108
|
+
# Delegates to the underlying {ProcessorPool}. Shutdown is idempotent
|
|
109
|
+
# because the underlying pool is idempotent.
|
|
110
|
+
#
|
|
29
111
|
# @return [void]
|
|
30
112
|
def shutdown
|
|
31
113
|
@processor_pool.shutdown
|
data/lib/cdc/parallel/version.rb
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
module CDC
|
|
4
4
|
module Parallel
|
|
5
5
|
# Current cdc-parallel version.
|
|
6
|
-
|
|
6
|
+
#
|
|
7
|
+
# This constant is used by RubyGems and by applications that need to inspect
|
|
8
|
+
# the loaded runtime version at boot time.
|
|
9
|
+
#
|
|
10
|
+
# @return [String]
|
|
11
|
+
VERSION = "0.2.4"
|
|
7
12
|
end
|
|
8
13
|
end
|
data/lib/cdc/parallel.rb
CHANGED
|
@@ -12,8 +12,46 @@ require_relative "parallel/transaction_pool"
|
|
|
12
12
|
require_relative "parallel/router"
|
|
13
13
|
require_relative "parallel/runtime"
|
|
14
14
|
|
|
15
|
+
# Namespace for Change Data Capture ecosystem components.
|
|
16
|
+
#
|
|
17
|
+
# The `cdc-parallel` gem adds the {CDC::Parallel} runtime namespace under
|
|
18
|
+
# this shared ecosystem root.
|
|
19
|
+
#
|
|
20
|
+
# @api public
|
|
15
21
|
module CDC
|
|
16
|
-
# Optional parallel Change Data Capture runtime for cdc-core processors.
|
|
22
|
+
# Optional parallel Change Data Capture runtime for `cdc-core` processors.
|
|
23
|
+
#
|
|
24
|
+
# `CDC::Parallel` is the CPU-bound execution layer of the CDC Ecosystem. It
|
|
25
|
+
# consumes work items that have already been normalized into `cdc-core`
|
|
26
|
+
# vocabulary objects and executes Ractor-safe processors across pre-warmed
|
|
27
|
+
# worker Ractors.
|
|
28
|
+
#
|
|
29
|
+
# The namespace intentionally avoids `CDC::Ractor` so it does not collide with
|
|
30
|
+
# Ruby's core `::Ractor` constant.
|
|
31
|
+
#
|
|
32
|
+
# ## Boundary
|
|
33
|
+
#
|
|
34
|
+
# `cdc-parallel` does not connect to PostgreSQL, parse `pgoutput`, decode
|
|
35
|
+
# values, normalize source payloads, or persist sink data. Those concerns live
|
|
36
|
+
# upstream in `pgoutput-*` libraries, source adapters, and downstream sinks.
|
|
37
|
+
#
|
|
38
|
+
# ## Main entry points
|
|
39
|
+
#
|
|
40
|
+
# * {CDC::Parallel::Runtime} - high-level facade for events and transactions
|
|
41
|
+
# * {CDC::Parallel::ProcessorPool} - low-level Ractor worker pool
|
|
42
|
+
# * {CDC::Parallel::TransactionPool} - transaction-envelope wrapper
|
|
43
|
+
# * {CDC::Parallel::Router} - work item router
|
|
44
|
+
#
|
|
45
|
+
# @example
|
|
46
|
+
# runtime = CDC::Parallel::Runtime.new(
|
|
47
|
+
# processor: AnalyticsProcessor.new,
|
|
48
|
+
# size: 4
|
|
49
|
+
# )
|
|
50
|
+
#
|
|
51
|
+
# result = runtime.process(change_event)
|
|
52
|
+
# runtime.shutdown
|
|
53
|
+
#
|
|
54
|
+
# @api public
|
|
17
55
|
module Parallel
|
|
18
56
|
end
|
|
19
57
|
end
|
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
module CDC
|
|
2
2
|
module Parallel
|
|
3
|
+
# Private Data superclass used to keep YARD documentation stable for Configuration.
|
|
4
|
+
class ConfigurationData < Data
|
|
5
|
+
attr_reader size: Integer
|
|
6
|
+
attr_reader timeout: Numeric?
|
|
7
|
+
end
|
|
8
|
+
|
|
3
9
|
# Immutable configuration for Ractor runtimes.
|
|
4
|
-
class Configuration
|
|
5
|
-
|
|
10
|
+
class Configuration < ConfigurationData
|
|
11
|
+
attr_reader size: Integer
|
|
12
|
+
|
|
13
|
+
attr_reader timeout: Numeric?
|
|
14
|
+
|
|
15
|
+
def self.new: (?size: Integer, ?timeout: Numeric?) -> instance
|
|
16
|
+
|
|
17
|
+
def initialize: (?size: Integer, ?timeout: Numeric?) -> void
|
|
6
18
|
end
|
|
7
19
|
end
|
|
8
20
|
end
|
data/sig/cdc/parallel/errors.rbs
CHANGED
|
@@ -18,19 +18,19 @@ module CDC
|
|
|
18
18
|
|
|
19
19
|
# Raised when processor execution fails inside a worker Ractor.
|
|
20
20
|
class ProcessorExecutionError < Error
|
|
21
|
-
@original_class:
|
|
21
|
+
@original_class: String
|
|
22
22
|
|
|
23
|
-
@original_message:
|
|
23
|
+
@original_message: String
|
|
24
24
|
|
|
25
|
-
@original_backtrace:
|
|
25
|
+
@original_backtrace: Array[String]
|
|
26
26
|
|
|
27
|
-
attr_reader original_class:
|
|
27
|
+
attr_reader original_class: String
|
|
28
28
|
|
|
29
|
-
attr_reader original_message:
|
|
29
|
+
attr_reader original_message: String
|
|
30
30
|
|
|
31
|
-
attr_reader original_backtrace:
|
|
31
|
+
attr_reader original_backtrace: Array[String]
|
|
32
32
|
|
|
33
|
-
def initialize: (original_class:
|
|
33
|
+
def initialize: (original_class: String?, original_message: String, ?original_backtrace: Array[String]) -> void
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
# Raised when a worker does not return a result before timeout.
|