cdc-concurrent 0.1.0 → 0.1.1

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.
@@ -2,17 +2,28 @@
2
2
 
3
3
  module CDC
4
4
  module Concurrent
5
- # Routes CDC work items to the correct concurrent pool.
5
+ # Routes CDC work items to the appropriate concurrent execution pool.
6
+ #
7
+ # Router is intentionally small. It keeps Runtime focused on lifecycle while
8
+ # preserving the distinction between individual events, transaction envelopes,
9
+ # and event batches.
6
10
  class Router
7
- # @param processor_pool [ProcessorPool]
8
- # @param transaction_pool [TransactionPool]
11
+ # Builds a router using existing processor and transaction pools.
12
+ #
13
+ # @param processor_pool [ProcessorPool] Pool used for individual ChangeEvent work and event batches.
14
+ # @param transaction_pool [TransactionPool] Pool used for TransactionEnvelope work.
15
+ # @return [void] Does not return a useful value.
9
16
  def initialize(processor_pool:, transaction_pool:)
10
17
  @processor_pool = processor_pool
11
18
  @transaction_pool = transaction_pool
12
19
  end
13
20
 
14
- # @param item [Object]
15
- # @return [Object]
21
+ # Dispatches a supported work item to its matching pool.
22
+ #
23
+ # @param item [CDC::Core::ChangeEvent, CDC::Core::TransactionEnvelope and
24
+ # Array<CDC::Core::ChangeEvent>] Work item to process.
25
+ # @raise [UnsupportedWorkItemError] If the item cannot be routed by cdc-concurrent.
26
+ # @return [CDC::Core::ProcessorResult, Array<CDC::Core::ProcessorResult>] Processing result for the supplied item.
16
27
  def process(item)
17
28
  case item
18
29
  when CDC::Core::ChangeEvent
@@ -3,11 +3,19 @@
3
3
  module CDC
4
4
  module Concurrent
5
5
  # High-level concurrent runtime facade for cdc-core processors.
6
+ #
7
+ # Runtime owns the public lifecycle for cdc-concurrent. It wires together the
8
+ # event processor pool, transaction pool, and router so callers can submit
9
+ # individual events, batches, or transaction envelopes through one object.
6
10
  class Runtime
7
- # @param processor [CDC::Core::Processor]
8
- # @param concurrency [Integer]
9
- # @param timeout [Float, nil]
10
- # @param preserve_order [Boolean]
11
+ # Builds a concurrent runtime for one processor.
12
+ #
13
+ # @param processor [CDC::Core::Processor] Processor instance that declares concurrent_safe!.
14
+ # @param concurrency [Integer] Maximum number of Async tasks allowed to run at once.
15
+ # @param timeout [Float, nil] Optional per-event processing timeout in seconds.
16
+ # @param preserve_order [Boolean] Whether batch results should preserve input order.
17
+ # @raise [UnsafeProcessorError] If the processor does not declare concurrent_safe!.
18
+ # @return [void] Does not return a useful value.
11
19
  def initialize(processor:, concurrency: 100, timeout: nil, preserve_order: true)
12
20
  @processor_pool = ProcessorPool.new(processor:, concurrency:, timeout:, preserve_order:)
13
21
  @transaction_pool = TransactionPool.new(processor:, concurrency:, timeout:, preserve_order:)
@@ -15,27 +23,39 @@ module CDC
15
23
  @shutdown = false
16
24
  end
17
25
 
18
- # @param item [Object]
19
- # @return [Object]
26
+ # Processes a supported work item through the runtime router.
27
+ #
28
+ # @param item [CDC::Core::ChangeEvent, CDC::Core::TransactionEnvelope and
29
+ # Array<CDC::Core::ChangeEvent>] Work item to process.
30
+ # @raise [ShutdownError] If the runtime has already been shut down.
31
+ # @raise [UnsupportedWorkItemError] If the item cannot be routed by cdc-concurrent.
32
+ # @return [CDC::Core::ProcessorResult, Array<CDC::Core::ProcessorResult>] Processing result for the supplied item.
20
33
  def process(item)
21
34
  raise ShutdownError, "runtime has been shut down" if @shutdown
22
35
 
23
36
  @router.process(item)
24
37
  end
25
38
 
26
- # @param events [Array<CDC::Core::ChangeEvent>]
27
- # @return [Array<CDC::Core::ProcessorResult>]
39
+ # Processes a batch of change events.
40
+ #
41
+ # @param events [Array<CDC::Core::ChangeEvent>] Events to process through the processor pool.
42
+ # @return [Array<CDC::Core::ProcessorResult>] Frozen array of normalized processor results.
28
43
  def process_many(events)
29
44
  process(events)
30
45
  end
31
46
 
32
- # @param transaction [CDC::Core::TransactionEnvelope]
33
- # @return [CDC::Core::ProcessorResult]
47
+ # Processes a transaction envelope as one logical work item.
48
+ #
49
+ # @param transaction [CDC::Core::TransactionEnvelope] Transaction whose events should be processed together.
50
+ # @return [CDC::Core::ProcessorResult] Success result containing event results
51
+ # or failure result for the first failed event.
34
52
  def process_transaction(transaction)
35
53
  process(transaction)
36
54
  end
37
55
 
38
- # @return [void]
56
+ # Shuts down the runtime and its underlying pools.
57
+ #
58
+ # @return [void] Does not return a useful value.
39
59
  def shutdown
40
60
  return if @shutdown
41
61
 
@@ -2,28 +2,46 @@
2
2
 
3
3
  module CDC
4
4
  module Concurrent
5
- # Processes TransactionEnvelope events as a single ordering-preserving unit.
5
+ # Processes TransactionEnvelope events as one logical unit.
6
+ #
7
+ # TransactionPool delegates the envelope's events to ProcessorPool while
8
+ # preserving the envelope-level success/failure contract. Event work may run
9
+ # concurrently, but the transaction result is returned as a single
10
+ # CDC::Core::ProcessorResult.
6
11
  class TransactionPool
7
- # @param processor [CDC::Core::Processor]
8
- # @param concurrency [Integer]
9
- # @param timeout [Float, nil]
10
- # @param preserve_order [Boolean]
12
+ # Builds a transaction pool backed by an Async processor pool.
13
+ #
14
+ # @param processor [CDC::Core::Processor] Processor instance that declares concurrent_safe!.
15
+ # @param concurrency [Integer] Maximum number of Async tasks allowed to run at once.
16
+ # @param timeout [Float, nil] Optional per-event processing timeout in seconds.
17
+ # @param preserve_order [Boolean] Whether event results should preserve transaction event order.
18
+ # @raise [UnsafeProcessorError] If the processor does not declare concurrent_safe!.
19
+ # @return [void] Does not return a useful value.
11
20
  def initialize(processor:, concurrency: 100, timeout: nil, preserve_order: true)
12
21
  @processor_pool = ProcessorPool.new(processor:, concurrency:, timeout:, preserve_order:)
13
22
  end
14
23
 
15
- # @param transaction [CDC::Core::TransactionEnvelope]
16
- # @return [CDC::Core::ProcessorResult]
24
+ # Processes all events inside a transaction envelope.
25
+ #
26
+ # @param transaction [CDC::Core::TransactionEnvelope] Transaction envelope whose events should be processed.
27
+ # @return [CDC::Core::ProcessorResult] Success result containing event results
28
+ # or failure result for the first failed event.Z
17
29
  def process(transaction)
18
30
  results = @processor_pool.process_many(transaction.events).freeze
19
31
  failure = results.find(&:failure?)
20
32
 
21
- return CDC::Core::ProcessorResult.failure(failure.error, event: results) if failure
33
+ if failure
34
+ error = failure.error || Error.new("transaction event failed without an error")
35
+
36
+ return CDC::Core::ProcessorResult.failure(error, event: results)
37
+ end
22
38
 
23
39
  CDC::Core::ProcessorResult.success(results)
24
40
  end
25
41
 
26
- # @return [void]
42
+ # Shuts down the underlying processor pool.
43
+ #
44
+ # @return [void] Does not return a useful value.
27
45
  def shutdown
28
46
  @processor_pool.shutdown
29
47
  end
@@ -3,6 +3,6 @@
3
3
  module CDC
4
4
  module Concurrent
5
5
  # Current cdc-concurrent version.
6
- VERSION = "0.1.0"
6
+ VERSION = "0.1.1"
7
7
  end
8
8
  end
@@ -1,26 +1,39 @@
1
1
  module CDC
2
+ module Core
3
+ class Processor
4
+ # Mark this processor class as safe for cdc-concurrent execution.
5
+ def self.concurrent_safe!: () -> true
6
+
7
+ # Whether this processor class declared concurrent safety.
8
+ def self.concurrent_safe?: () -> bool
9
+
10
+ # Whether this processor instance is concurrent-safe.
11
+ def concurrent_safe?: () -> bool
12
+ end
13
+ end
14
+
2
15
  # Optional concurrent runtime adapter for cdc-core processors.
3
16
  module Concurrent
4
17
  # Adds concurrent-safe declarations to CDC::Core::Processor subclasses.
5
18
  module ProcessorExtensions
6
19
  # Class methods added to CDC::Core::Processor.
7
20
  module ClassMethods
8
- @concurrent_safe: untyped
21
+ @concurrent_safe: bool?
9
22
 
10
23
  # Declare this processor safe for concurrent execution.
11
- def concurrent_safe!: () -> untyped
24
+ def concurrent_safe!: () -> true
12
25
 
13
26
  # @return [Boolean] whether instances are concurrent-safe.
14
- def concurrent_safe?: () -> untyped
27
+ def concurrent_safe?: () -> bool
15
28
  end
16
29
 
17
30
  # @return [Boolean] whether this processor instance is concurrent-safe.
18
- def concurrent_safe?: () -> untyped
31
+ def concurrent_safe?: () -> bool
19
32
  end
20
33
 
21
34
  # Installs concurrent-safe declarations on CDC::Core::Processor.
22
35
  #
23
36
  # @return [void]
24
- def self.install_processor_extensions!: () -> untyped
37
+ def self.install_processor_extensions!: () -> void
25
38
  end
26
39
  end
@@ -2,42 +2,42 @@ module CDC
2
2
  module Concurrent
3
3
  # Executes one concurrent-safe processor using Async tasks.
4
4
  class ProcessorPool
5
- @processor: untyped
5
+ @processor: processor
6
6
 
7
- @configuration: untyped
7
+ @configuration: Configuration
8
8
 
9
- @shutdown: untyped
9
+ @shutdown: bool
10
10
 
11
11
  # @param processor [CDC::Core::Processor]
12
12
  # @param concurrency [Integer]
13
13
  # @param timeout [Float, nil]
14
14
  # @param preserve_order [Boolean]
15
- def initialize: (processor: untyped, ?concurrency: ::Integer, ?timeout: untyped?, ?preserve_order: bool) -> void
15
+ def initialize: (processor: processor, ?concurrency: ::Integer, ?timeout: ::Float?, ?preserve_order: bool) -> void
16
16
 
17
17
  # @param event [CDC::Core::ChangeEvent]
18
18
  # @return [CDC::Core::ProcessorResult]
19
- def process: (untyped event) -> untyped
19
+ def process: (change_event event) -> processor_result
20
20
 
21
21
  # @param events [Array<CDC::Core::ChangeEvent>]
22
22
  # @return [Array<CDC::Core::ProcessorResult>]
23
- def process_many: (untyped events) -> (::Array[untyped] | untyped)
23
+ def process_many: (::Array[change_event] events) -> processor_results
24
24
 
25
25
  # @return [void]
26
- def shutdown: () -> untyped
26
+ def shutdown: () -> void
27
27
 
28
28
  private
29
29
 
30
- def validate_processor!: (untyped processor) -> (nil | untyped)
30
+ def validate_processor!: (processor processor) -> nil
31
31
 
32
- def empty_results: () -> ::Array[untyped]
32
+ def empty_results: () -> processor_results
33
33
 
34
- def process_batch: (untyped events, untyped indexed_results) -> untyped
34
+ def process_batch: (::Array[change_event] events, ::Array[[::Integer, processor_result]] indexed_results) -> untyped
35
35
 
36
- def process_one: (untyped event) -> untyped
36
+ def process_one: (change_event event) -> untyped
37
37
 
38
- def process_with_task: (untyped task, untyped event) -> untyped
38
+ def process_with_task: (untyped task, change_event event) -> processor_result
39
39
 
40
- def call_processor: (untyped task, untyped event) -> untyped
40
+ def call_processor: (untyped task, change_event event) -> untyped
41
41
  end
42
42
  end
43
43
  end
@@ -4,11 +4,11 @@ module CDC
4
4
  class ResultCollector
5
5
  # @param value [Object]
6
6
  # @return [CDC::Core::ProcessorResult]
7
- def self.normalize: (untyped value) -> untyped
7
+ def self.normalize: (untyped value) -> processor_result
8
8
 
9
9
  # @param error [Exception]
10
10
  # @return [CDC::Core::ProcessorResult]
11
- def self.failure: (untyped error) -> untyped
11
+ def self.failure: (::Exception error) -> processor_result
12
12
  end
13
13
  end
14
14
  end
@@ -2,17 +2,20 @@ module CDC
2
2
  module Concurrent
3
3
  # Routes CDC work items to the correct concurrent pool.
4
4
  class Router
5
- @processor_pool: untyped
5
+ @processor_pool: ProcessorPool
6
6
 
7
- @transaction_pool: untyped
7
+ @transaction_pool: TransactionPool
8
8
 
9
9
  # @param processor_pool [ProcessorPool]
10
10
  # @param transaction_pool [TransactionPool]
11
- def initialize: (processor_pool: untyped, transaction_pool: untyped) -> void
11
+ def initialize: (processor_pool: ProcessorPool, transaction_pool: TransactionPool) -> void
12
12
 
13
13
  # @param item [Object]
14
14
  # @return [Object]
15
- def process: (untyped item) -> untyped
15
+ def process: (change_event item) -> processor_result
16
+ | (transaction_envelope item) -> processor_result
17
+ | (::Array[change_event] item) -> processor_results
18
+ | (work_item item) -> work_result
16
19
  end
17
20
  end
18
21
  end
@@ -2,34 +2,36 @@ module CDC
2
2
  module Concurrent
3
3
  # High-level concurrent runtime facade for cdc-core processors.
4
4
  class Runtime
5
- @processor_pool: untyped
5
+ @processor_pool: ProcessorPool
6
6
 
7
- @transaction_pool: untyped
7
+ @transaction_pool: TransactionPool
8
8
 
9
- @router: untyped
9
+ @router: Router
10
10
 
11
- @shutdown: untyped
11
+ @shutdown: bool
12
12
 
13
13
  # @param processor [CDC::Core::Processor]
14
14
  # @param concurrency [Integer]
15
15
  # @param timeout [Float, nil]
16
16
  # @param preserve_order [Boolean]
17
- def initialize: (processor: untyped, ?concurrency: ::Integer, ?timeout: untyped?, ?preserve_order: bool) -> void
17
+ def initialize: (processor: processor, ?concurrency: ::Integer, ?timeout: ::Float?, ?preserve_order: bool) -> void
18
18
 
19
19
  # @param item [Object]
20
20
  # @return [Object]
21
- def process: (untyped item) -> untyped
21
+ def process: (change_event item) -> processor_result
22
+ | (transaction_envelope item) -> processor_result
23
+ | (::Array[change_event] item) -> processor_results
22
24
 
23
25
  # @param events [Array<CDC::Core::ChangeEvent>]
24
26
  # @return [Array<CDC::Core::ProcessorResult>]
25
- def process_many: (untyped events) -> untyped
27
+ def process_many: (::Array[change_event] events) -> processor_results
26
28
 
27
29
  # @param transaction [CDC::Core::TransactionEnvelope]
28
30
  # @return [CDC::Core::ProcessorResult]
29
- def process_transaction: (untyped transaction) -> untyped
31
+ def process_transaction: (transaction_envelope transaction) -> processor_result
30
32
 
31
33
  # @return [void]
32
- def shutdown: () -> (nil | untyped)
34
+ def shutdown: () -> void
33
35
  end
34
36
  end
35
37
  end
@@ -2,20 +2,20 @@ module CDC
2
2
  module Concurrent
3
3
  # Processes TransactionEnvelope events as a single ordering-preserving unit.
4
4
  class TransactionPool
5
- @processor_pool: untyped
5
+ @processor_pool: ProcessorPool
6
6
 
7
7
  # @param processor [CDC::Core::Processor]
8
8
  # @param concurrency [Integer]
9
9
  # @param timeout [Float, nil]
10
10
  # @param preserve_order [Boolean]
11
- def initialize: (processor: untyped, ?concurrency: ::Integer, ?timeout: untyped?, ?preserve_order: bool) -> void
11
+ def initialize: (processor: processor, ?concurrency: ::Integer, ?timeout: ::Float?, ?preserve_order: bool) -> void
12
12
 
13
13
  # @param transaction [CDC::Core::TransactionEnvelope]
14
14
  # @return [CDC::Core::ProcessorResult]
15
- def process: (untyped transaction) -> untyped
15
+ def process: (transaction_envelope transaction) -> processor_result
16
16
 
17
17
  # @return [void]
18
- def shutdown: () -> untyped
18
+ def shutdown: () -> void
19
19
  end
20
20
  end
21
21
  end
@@ -1,6 +1,6 @@
1
1
  module CDC
2
2
  module Concurrent
3
3
  # Current cdc-concurrent version.
4
- VERSION: "0.1.0"
4
+ VERSION: "0.1.1"
5
5
  end
6
6
  end
@@ -1,5 +1,12 @@
1
1
  module CDC
2
2
  # Optional concurrent runtime adapter for cdc-core processors.
3
3
  module Concurrent
4
+ type change_event = ::CDC::Core::ChangeEvent
5
+ type processor = ::CDC::Core::Processor
6
+ type processor_result = ::CDC::Core::ProcessorResult
7
+ type processor_results = ::Array[processor_result]
8
+ type transaction_envelope = ::CDC::Core::TransactionEnvelope
9
+ type work_item = change_event | transaction_envelope | ::Array[change_event]
10
+ type work_result = processor_result | processor_results
4
11
  end
5
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cdc-concurrent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken C. Demanawa
@@ -30,6 +30,9 @@ dependencies:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '0.1'
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 0.1.3
33
36
  type: :runtime
34
37
  prerelease: false
35
38
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,6 +40,9 @@ dependencies:
37
40
  - - "~>"
38
41
  - !ruby/object:Gem::Version
39
42
  version: '0.1'
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 0.1.3
40
46
  description: |
41
47
  cdc-concurrent provides optional Async-backed I/O-concurrent execution for
42
48
  cdc-core. It accelerates I/O-bound PostgreSQL Change Data Capture (CDC)
@@ -50,6 +56,8 @@ files:
50
56
  - CHANGELOG.md
51
57
  - LICENSE.txt
52
58
  - README.md
59
+ - benchmark/README.md
60
+ - benchmark/processor_pool_benchmark.rb
53
61
  - lib/cdc/concurrent.rb
54
62
  - lib/cdc/concurrent/configuration.rb
55
63
  - lib/cdc/concurrent/errors.rb
@@ -72,8 +80,6 @@ files:
72
80
  - sig/cdc/concurrent/transaction_pool.rbs
73
81
  - sig/cdc/concurrent/version.rbs
74
82
  - sig/cdc_concurrent.rbs
75
- - sig/shims/async.rbs
76
- - sig/shims/cdc_core.rbs
77
83
  homepage: https://kanutocd.github.io/cdc-concurrent
78
84
  licenses:
79
85
  - MIT
data/sig/shims/async.rbs DELETED
@@ -1,20 +0,0 @@
1
- module Kernel
2
- private
3
-
4
- def Async: () { (Async::Task) -> untyped } -> Async::Task
5
- end
6
-
7
- module Async
8
- class Task
9
- def with_timeout: (untyped timeout) { () -> untyped } -> untyped
10
- def wait: () -> untyped
11
- end
12
-
13
- class Semaphore
14
- def initialize: (Integer limit, parent: Task) -> void
15
- def async: () { (Task) -> untyped } -> Task
16
- end
17
-
18
- class TimeoutError < StandardError
19
- end
20
- end
@@ -1,31 +0,0 @@
1
- module CDC
2
- module Core
3
- class Processor
4
- def self.extend: (Module mod) -> self
5
- def self.include: (Module mod) -> self
6
-
7
- def process: (untyped event) -> untyped
8
- end
9
-
10
- class ProcessorResult
11
- attr_reader status: Symbol
12
- attr_reader event: untyped
13
- attr_reader error: untyped
14
- attr_reader metadata: untyped
15
-
16
- def self.success: (?untyped event, ?metadata: untyped) -> ProcessorResult
17
- def self.failure: (untyped error, ?event: untyped, ?metadata: untyped) -> ProcessorResult
18
-
19
- def success?: () -> bool
20
- def failure?: () -> bool
21
- def skipped?: () -> bool
22
- end
23
-
24
- class ChangeEvent
25
- end
26
-
27
- class TransactionEnvelope
28
- attr_reader events: Array[ChangeEvent]
29
- end
30
- end
31
- end