pigeon-rb 0.1.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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +343 -0
  3. data/lib/pigeon/active_job_integration.rb +32 -0
  4. data/lib/pigeon/api.rb +200 -0
  5. data/lib/pigeon/configuration.rb +161 -0
  6. data/lib/pigeon/core.rb +104 -0
  7. data/lib/pigeon/encryption.rb +213 -0
  8. data/lib/pigeon/generators/hanami/migration_generator.rb +89 -0
  9. data/lib/pigeon/generators/rails/install_generator.rb +32 -0
  10. data/lib/pigeon/generators/rails/migration_generator.rb +20 -0
  11. data/lib/pigeon/generators/rails/templates/create_outbox_messages.rb.erb +34 -0
  12. data/lib/pigeon/generators/rails/templates/initializer.rb.erb +88 -0
  13. data/lib/pigeon/hanami_integration.rb +78 -0
  14. data/lib/pigeon/health_check/kafka.rb +37 -0
  15. data/lib/pigeon/health_check/processor.rb +70 -0
  16. data/lib/pigeon/health_check/queue.rb +69 -0
  17. data/lib/pigeon/health_check.rb +63 -0
  18. data/lib/pigeon/logging/structured_logger.rb +181 -0
  19. data/lib/pigeon/metrics/collector.rb +200 -0
  20. data/lib/pigeon/mock_producer.rb +18 -0
  21. data/lib/pigeon/models/adapters/active_record_adapter.rb +133 -0
  22. data/lib/pigeon/models/adapters/rom_adapter.rb +150 -0
  23. data/lib/pigeon/models/outbox_message.rb +182 -0
  24. data/lib/pigeon/monitoring.rb +113 -0
  25. data/lib/pigeon/outbox.rb +61 -0
  26. data/lib/pigeon/processor/background_processor.rb +109 -0
  27. data/lib/pigeon/processor.rb +798 -0
  28. data/lib/pigeon/publisher.rb +524 -0
  29. data/lib/pigeon/railtie.rb +29 -0
  30. data/lib/pigeon/schema.rb +35 -0
  31. data/lib/pigeon/security.rb +30 -0
  32. data/lib/pigeon/serializer.rb +77 -0
  33. data/lib/pigeon/tasks/pigeon.rake +64 -0
  34. data/lib/pigeon/trace_api.rb +37 -0
  35. data/lib/pigeon/tracing/core.rb +119 -0
  36. data/lib/pigeon/tracing/messaging.rb +144 -0
  37. data/lib/pigeon/tracing.rb +107 -0
  38. data/lib/pigeon/version.rb +5 -0
  39. data/lib/pigeon.rb +52 -0
  40. metadata +127 -0
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :pigeon do # rubocop:disable Metrics/BlockLength
4
+ desc "Process pending outbox messages"
5
+ task process: :environment do
6
+ batch_size = ENV.fetch("BATCH_SIZE", 100).to_i
7
+ puts "Processing pending outbox messages (batch size: #{batch_size})..."
8
+ stats = Pigeon.processor.process_pending(batch_size: batch_size)
9
+ puts "Processed #{stats[:processed]} messages: #{stats[:succeeded]} succeeded, #{stats[:failed]} failed"
10
+ end
11
+
12
+ desc "Start background processing of outbox messages"
13
+ task start: :environment do
14
+ batch_size = ENV.fetch("BATCH_SIZE", 100).to_i
15
+ interval = ENV.fetch("INTERVAL", 5).to_i
16
+ thread_count = ENV.fetch("THREAD_COUNT", 2).to_i
17
+
18
+ puts "Starting background processing of outbox messages..."
19
+ puts "Batch size: #{batch_size}, Interval: #{interval}s, Threads: #{thread_count}"
20
+
21
+ processor = Pigeon.processor
22
+ if processor.start_processing(batch_size: batch_size, interval: interval, thread_count: thread_count)
23
+ puts "Background processing started successfully"
24
+
25
+ # Keep the process running
26
+ trap("INT") do
27
+ processor.stop_processing
28
+ puts "\nStopped processing"
29
+ exit
30
+ end
31
+ trap("TERM") do
32
+ processor.stop_processing
33
+ puts "\nStopped processing"
34
+ exit
35
+ end
36
+
37
+ # Sleep indefinitely
38
+ loop { sleep }
39
+ else
40
+ puts "Failed to start background processing"
41
+ exit 1
42
+ end
43
+ end
44
+
45
+ desc "Clean up processed outbox messages"
46
+ task cleanup: :environment do
47
+ older_than = ENV.fetch("OLDER_THAN", 7).to_i
48
+ puts "Cleaning up processed outbox messages older than #{older_than} days..."
49
+ count = Pigeon.processor.cleanup_processed(older_than: older_than)
50
+ puts "Cleaned up #{count} messages"
51
+ end
52
+
53
+ desc "Generate outbox message migration for Rails"
54
+ task :install, [:framework] do |_t, args|
55
+ if args[:framework] == "rails"
56
+ system "rails generate pigeon:rails:install"
57
+ elsif args[:framework] == "hanami"
58
+ system "hanami generate pigeon:rails:install"
59
+ else
60
+ puts "Invalid framework: #{args[:framework]}. Valid frameworks are: rails, hanami"
61
+ exit 1
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pigeon
4
+ # Tracing API for Pigeon
5
+ module TraceAPI
6
+ # Initialize OpenTelemetry tracing
7
+ # @param service_name [String] Service name for traces
8
+ # @param exporter [OpenTelemetry::Exporter::OTLP::Exporter, nil] Optional custom exporter
9
+ # @return [Boolean] Whether initialization was successful
10
+ def self.init_tracing(service_name: "pigeon", exporter: nil)
11
+ Tracing.init(service_name: service_name, exporter: exporter)
12
+ end
13
+
14
+ # Check if OpenTelemetry tracing is available
15
+ # @return [Boolean] Whether OpenTelemetry is available
16
+ def self.tracing_available?
17
+ Tracing.available?
18
+ end
19
+
20
+ # Get the OpenTelemetry tracer
21
+ # @param name [String] Tracer name
22
+ # @return [OpenTelemetry::Tracer, nil] Tracer or nil if OpenTelemetry is not available
23
+ def self.tracer(name = "pigeon")
24
+ Tracing.tracer(name)
25
+ end
26
+
27
+ # Create a span for a block of code
28
+ # @param name [String] Span name
29
+ # @param attributes [Hash] Span attributes
30
+ # @param kind [Symbol] Span kind (:internal, :server, :client, :producer, :consumer)
31
+ # @yield Block to execute within the span
32
+ # @return [Object] Result of the block
33
+ def self.with_span(name, attributes: {}, kind: :internal, &)
34
+ Tracing.with_span(name, attributes: attributes, kind: kind, &)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pigeon
4
+ module Tracing
5
+ # Core tracing functionality
6
+ module Core
7
+ # Check if OpenTelemetry is available
8
+ # @return [Boolean] Whether OpenTelemetry is available
9
+ def self.available?
10
+ defined?(OpenTelemetry)
11
+ end
12
+
13
+ # Initialize OpenTelemetry tracing
14
+ # @param service_name [String] Service name for traces
15
+ # @param exporter [OpenTelemetry::Exporter::OTLP::Exporter, nil] Optional custom exporter
16
+ # @return [Boolean] Whether initialization was successful
17
+ def self.init(service_name: "pigeon", exporter: nil)
18
+ return false unless available?
19
+
20
+ begin
21
+ # Configure the SDK with default exporters
22
+ OpenTelemetry::SDK.configure do |c|
23
+ c.service_name = service_name
24
+ c.use_all # Use all available instrumentation
25
+ c.add_span_processor(
26
+ OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
27
+ exporter || OpenTelemetry::Exporter::OTLP::Exporter.new
28
+ )
29
+ )
30
+ end
31
+
32
+ true
33
+ rescue StandardError => e
34
+ Pigeon.config.logger.error("Failed to initialize OpenTelemetry: #{e.message}")
35
+ false
36
+ end
37
+ end
38
+
39
+ # Get the OpenTelemetry tracer
40
+ # @param name [String] Tracer name
41
+ # @return [OpenTelemetry::Tracer, nil] Tracer or nil if OpenTelemetry is not available
42
+ def self.tracer(name = "pigeon")
43
+ return nil unless available?
44
+
45
+ OpenTelemetry.tracer_provider.tracer(name)
46
+ end
47
+
48
+ # Create a span for a block of code
49
+ # @param name [String] Span name
50
+ # @param attributes [Hash] Span attributes
51
+ # @param kind [Symbol] Span kind (:internal, :server, :client, :producer, :consumer)
52
+ # @param parent_context [OpenTelemetry::Context, nil] Optional parent context
53
+ # @yield Block to execute within the span
54
+ # @return [Object] Result of the block
55
+ def self.with_span(name, attributes: {}, kind: :internal, parent_context: nil, &)
56
+ return yield unless available?
57
+
58
+ tracer = self.tracer
59
+ return yield unless tracer
60
+
61
+ parent_context ||= OpenTelemetry::Context.current
62
+ span_kind = span_kind_from_symbol(kind)
63
+
64
+ tracer.in_span(name, attributes: attributes, kind: span_kind, with_parent: parent_context, &)
65
+ end
66
+
67
+ # Extract trace context from headers
68
+ # @param headers [Hash] Headers containing trace context
69
+ # @return [OpenTelemetry::Context, nil] Extracted context or nil if not available
70
+ def self.extract_context(headers)
71
+ return nil unless available?
72
+ return nil unless headers
73
+
74
+ # Convert header keys to lowercase for case-insensitive matching
75
+ normalized_headers = {}
76
+ headers.each do |k, v|
77
+ normalized_headers[k.to_s.downcase] = v
78
+ end
79
+
80
+ carrier = OpenTelemetry::Context::Propagation::Rack::HeadersGetter.new(normalized_headers)
81
+ OpenTelemetry.propagation.extract(carrier)
82
+ end
83
+
84
+ # Inject trace context into headers
85
+ # @param headers [Hash] Headers to inject trace context into
86
+ # @param context [OpenTelemetry::Context, nil] Context to inject (defaults to current)
87
+ # @return [Hash] Headers with injected trace context
88
+ def self.inject_context(headers = {}, context = nil)
89
+ return headers unless available?
90
+
91
+ headers ||= {}
92
+ context ||= OpenTelemetry::Context.current
93
+ carrier = OpenTelemetry::Context::Propagation::Rack::HeadersSetter.new(headers)
94
+ OpenTelemetry.propagation.inject(carrier, context: context)
95
+ headers
96
+ end
97
+
98
+ # Convert a symbol to an OpenTelemetry span kind
99
+ # @param kind [Symbol] Span kind symbol
100
+ # @return [Integer] OpenTelemetry span kind
101
+ def self.span_kind_from_symbol(kind)
102
+ return OpenTelemetry::Trace::SpanKind::INTERNAL unless available?
103
+
104
+ case kind
105
+ when :server
106
+ OpenTelemetry::Trace::SpanKind::SERVER
107
+ when :client
108
+ OpenTelemetry::Trace::SpanKind::CLIENT
109
+ when :producer
110
+ OpenTelemetry::Trace::SpanKind::PRODUCER
111
+ when :consumer
112
+ OpenTelemetry::Trace::SpanKind::CONSUMER
113
+ else
114
+ OpenTelemetry::Trace::SpanKind::INTERNAL
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pigeon
4
+ module Tracing
5
+ # Messaging-specific tracing functionality
6
+ module Messaging
7
+ # Create a span for publishing a message
8
+ # @param topic [String] Kafka topic
9
+ # @param payload [Hash, String] Message payload
10
+ # @param key [String, nil] Optional message key
11
+ # @param headers [Hash, nil] Optional message headers
12
+ # @param correlation_id [String, nil] Optional correlation ID
13
+ # @yield [span, context, headers] Block to execute within the span
14
+ # @yieldparam span [OpenTelemetry::Span] Active span
15
+ # @yieldparam context [OpenTelemetry::Context] Span context
16
+ # @yieldparam headers [Hash] Headers with injected trace context
17
+ # @return [Object] Result of the block
18
+ def self.trace_publish(topic:, payload:, key: nil, headers: nil, correlation_id: nil)
19
+ return yield(nil, nil, headers || {}) unless Core.available?
20
+
21
+ # Create span attributes
22
+ attributes = publish_span_attributes(topic, payload, key, correlation_id)
23
+
24
+ # Create the span
25
+ Core.with_span("publish_message", attributes: attributes, kind: :producer) do |span|
26
+ # Get the current context with the span
27
+ context = OpenTelemetry::Context.current
28
+
29
+ # Inject trace context into headers
30
+ trace_headers = headers ? headers.dup : {}
31
+ Core.inject_context(trace_headers, context)
32
+
33
+ # Add correlation ID to span
34
+ span.add_attributes("messaging.correlation_id" => correlation_id) if correlation_id
35
+
36
+ # Yield to the block with the span, context, and headers
37
+ yield span, context, trace_headers
38
+ end
39
+ end
40
+
41
+ # Create span attributes for publishing
42
+ # @param topic [String] Kafka topic
43
+ # @param payload [Hash, String] Message payload
44
+ # @param key [String, nil] Optional message key
45
+ # @param correlation_id [String, nil] Optional correlation ID
46
+ # @return [Hash] Span attributes
47
+ def self.publish_span_attributes(topic, payload, key, correlation_id)
48
+ attributes = {
49
+ "messaging.system" => "kafka",
50
+ "messaging.destination" => topic,
51
+ "messaging.destination_kind" => "topic",
52
+ "messaging.operation" => "publish"
53
+ }
54
+
55
+ # Add optional attributes
56
+ attributes["messaging.message_id"] = correlation_id if correlation_id
57
+ attributes["messaging.kafka.key"] = key if key
58
+ attributes["messaging.message_payload_size_bytes"] = payload.bytesize if payload.respond_to?(:bytesize)
59
+
60
+ attributes
61
+ end
62
+
63
+ # Create a span for processing a message
64
+ # @param message [Pigeon::Models::OutboxMessage] Message to process
65
+ # @yield [span] Block to execute within the span
66
+ # @yieldparam span [OpenTelemetry::Span] Active span
67
+ # @return [Object] Result of the block
68
+ def self.trace_process(message)
69
+ return yield(nil) unless Core.available?
70
+
71
+ # Extract trace context from message headers if available
72
+ parent_context = message.headers ? Core.extract_context(message.headers) : nil
73
+
74
+ # Create span attributes
75
+ attributes = process_span_attributes(message)
76
+
77
+ # Create the span
78
+ Core.with_span(
79
+ "process_message",
80
+ attributes: attributes,
81
+ kind: :consumer,
82
+ parent_context: parent_context
83
+ ) do |span|
84
+ # Add additional attributes
85
+ add_process_span_attributes(span, message)
86
+
87
+ # Yield to the block with the span
88
+ yield span
89
+ end
90
+ end
91
+
92
+ # Create span attributes for processing
93
+ # @param message [Pigeon::Models::OutboxMessage] Message to process
94
+ # @return [Hash] Span attributes
95
+ def self.process_span_attributes(message)
96
+ attributes = {
97
+ "messaging.system" => "kafka",
98
+ "messaging.destination" => message.topic,
99
+ "messaging.destination_kind" => "topic",
100
+ "messaging.operation" => "process",
101
+ "messaging.kafka.key" => message.key,
102
+ "messaging.message_id" => message.id.to_s
103
+ }
104
+
105
+ # Add correlation ID if available
106
+ attributes["messaging.correlation_id"] = message.correlation_id if message.correlation_id
107
+
108
+ attributes
109
+ end
110
+
111
+ # Add additional attributes to a process span
112
+ # @param span [OpenTelemetry::Span] Span to add attributes to
113
+ # @param message [Pigeon::Models::OutboxMessage] Message being processed
114
+ # @return [void]
115
+ def self.add_process_span_attributes(span, message)
116
+ return unless span && message.partition
117
+
118
+ span.add_attributes({
119
+ "messaging.kafka.partition" => message.partition,
120
+ "messaging.kafka.message.retry_count" => message.retry_count
121
+ })
122
+ end
123
+
124
+ # Create a span for batch processing
125
+ # @param batch_size [Integer] Number of messages to process
126
+ # @yield [span] Block to execute within the span
127
+ # @yieldparam span [OpenTelemetry::Span] Active span
128
+ # @return [Object] Result of the block
129
+ def self.trace_batch_process(batch_size, &)
130
+ return yield(nil) unless Core.available?
131
+
132
+ # Create span attributes
133
+ attributes = {
134
+ "messaging.system" => "kafka",
135
+ "messaging.operation" => "batch_process",
136
+ "messaging.batch.size" => batch_size
137
+ }
138
+
139
+ # Create the span
140
+ Core.with_span("process_batch", attributes: attributes, &)
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "opentelemetry"
5
+ require "opentelemetry/sdk"
6
+ require "opentelemetry/exporter/otlp"
7
+ require "opentelemetry/instrumentation/all"
8
+ rescue LoadError
9
+ # OpenTelemetry is optional, so we can continue without it
10
+ end
11
+
12
+ require_relative "tracing/core"
13
+ require_relative "tracing/messaging"
14
+
15
+ module Pigeon
16
+ # Tracing module for Pigeon using OpenTelemetry
17
+ module Tracing
18
+ class << self
19
+ # Check if OpenTelemetry is available
20
+ # @return [Boolean] Whether OpenTelemetry is available
21
+ def available?
22
+ Core.available?
23
+ end
24
+
25
+ # Initialize OpenTelemetry tracing
26
+ # @param service_name [String] Service name for traces
27
+ # @param exporter [OpenTelemetry::Exporter::OTLP::Exporter, nil] Optional custom exporter
28
+ # @return [Boolean] Whether initialization was successful
29
+ def init(service_name: "pigeon", exporter: nil)
30
+ Core.init(service_name: service_name, exporter: exporter)
31
+ end
32
+
33
+ # Get the OpenTelemetry tracer
34
+ # @param name [String] Tracer name
35
+ # @return [OpenTelemetry::Tracer, nil] Tracer or nil if OpenTelemetry is not available
36
+ def tracer(name = "pigeon")
37
+ Core.tracer(name)
38
+ end
39
+
40
+ # Create a span for a block of code
41
+ # @param name [String] Span name
42
+ # @param attributes [Hash] Span attributes
43
+ # @param kind [Symbol] Span kind (:internal, :server, :client, :producer, :consumer)
44
+ # @param parent_context [OpenTelemetry::Context, nil] Optional parent context
45
+ # @yield Block to execute within the span
46
+ # @return [Object] Result of the block
47
+ def with_span(name, attributes: {}, kind: :internal, parent_context: nil, &)
48
+ Core.with_span(name, attributes: attributes, kind: kind, parent_context: parent_context, &)
49
+ end
50
+
51
+ # Extract trace context from headers
52
+ # @param headers [Hash] Headers containing trace context
53
+ # @return [OpenTelemetry::Context, nil] Extracted context or nil if not available
54
+ def extract_context(headers)
55
+ Core.extract_context(headers)
56
+ end
57
+
58
+ # Inject trace context into headers
59
+ # @param headers [Hash] Headers to inject trace context into
60
+ # @param context [OpenTelemetry::Context, nil] Context to inject (defaults to current)
61
+ # @return [Hash] Headers with injected trace context
62
+ def inject_context(headers = {}, context = nil)
63
+ Core.inject_context(headers, context)
64
+ end
65
+
66
+ # Create a span for publishing a message
67
+ # @param topic [String] Kafka topic
68
+ # @param payload [Hash, String] Message payload
69
+ # @param key [String, nil] Optional message key
70
+ # @param headers [Hash, nil] Optional message headers
71
+ # @param correlation_id [String, nil] Optional correlation ID
72
+ # @yield [span, context, headers] Block to execute within the span
73
+ # @yieldparam span [OpenTelemetry::Span] Active span
74
+ # @yieldparam context [OpenTelemetry::Context] Span context
75
+ # @yieldparam headers [Hash] Headers with injected trace context
76
+ # @return [Object] Result of the block
77
+ def trace_publish(topic:, payload:, key: nil, headers: nil, correlation_id: nil, &)
78
+ Messaging.trace_publish(
79
+ topic: topic,
80
+ payload: payload,
81
+ key: key,
82
+ headers: headers,
83
+ correlation_id: correlation_id,
84
+ &
85
+ )
86
+ end
87
+
88
+ # Create a span for processing a message
89
+ # @param message [Pigeon::Models::OutboxMessage] Message to process
90
+ # @yield [span] Block to execute within the span
91
+ # @yieldparam span [OpenTelemetry::Span] Active span
92
+ # @return [Object] Result of the block
93
+ def trace_process(message, &)
94
+ Messaging.trace_process(message, &)
95
+ end
96
+
97
+ # Create a span for batch processing
98
+ # @param batch_size [Integer] Number of messages to process
99
+ # @yield [span] Block to execute within the span
100
+ # @yieldparam span [OpenTelemetry::Span] Active span
101
+ # @return [Object] Result of the block
102
+ def trace_batch_process(batch_size, &)
103
+ Messaging.trace_batch_process(batch_size, &)
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pigeon
4
+ VERSION = "0.1.0"
5
+ end
data/lib/pigeon.rb ADDED
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pigeon/version"
4
+ require "pigeon/logging/structured_logger"
5
+ require "pigeon/configuration"
6
+ require "pigeon/models/outbox_message"
7
+ require "pigeon/models/adapters/active_record_adapter"
8
+ require "pigeon/models/adapters/rom_adapter"
9
+ require "pigeon/serializer"
10
+ require "pigeon/encryption"
11
+ require "pigeon/tracing"
12
+ require "pigeon/publisher"
13
+ require "pigeon/processor"
14
+ require "pigeon/health_check"
15
+ require "karafka"
16
+
17
+ # Load Rails integration if Rails is defined
18
+ require "pigeon/railtie" if defined?(Rails)
19
+
20
+ # Load Hanami integration if Hanami is defined
21
+ require "pigeon/hanami_integration" if defined?(Hanami)
22
+
23
+ # Load generators if Rails is defined
24
+ if defined?(Rails)
25
+ require "pigeon/generators/rails/migration_generator"
26
+ require "pigeon/generators/rails/install_generator"
27
+ end
28
+
29
+ # Load internal modules
30
+ require_relative "pigeon/mock_producer"
31
+ require_relative "pigeon/core"
32
+ require_relative "pigeon/schema"
33
+ require_relative "pigeon/security"
34
+ require_relative "pigeon/outbox"
35
+ require_relative "pigeon/monitoring"
36
+ require_relative "pigeon/trace_api"
37
+ require_relative "pigeon/api"
38
+
39
+ # Main module for the Pigeon gem
40
+ module Pigeon
41
+ class Error < StandardError; end
42
+
43
+ # Include API modules
44
+ class << self
45
+ include API::CoreAPI
46
+ include API::SchemaAPI
47
+ include API::SecurityAPI
48
+ include API::OutboxAPI
49
+ include API::MonitoringAPI
50
+ include API::TracingAPI
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pigeon-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Khai Le
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-07-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-configurable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: karafka
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ description: A Ruby gem that implements the outbox pattern for Kafka message publishing
56
+ to ensure message durability and delivery reliability
57
+ email:
58
+ - khaile.to@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - lib/pigeon.rb
65
+ - lib/pigeon/active_job_integration.rb
66
+ - lib/pigeon/api.rb
67
+ - lib/pigeon/configuration.rb
68
+ - lib/pigeon/core.rb
69
+ - lib/pigeon/encryption.rb
70
+ - lib/pigeon/generators/hanami/migration_generator.rb
71
+ - lib/pigeon/generators/rails/install_generator.rb
72
+ - lib/pigeon/generators/rails/migration_generator.rb
73
+ - lib/pigeon/generators/rails/templates/create_outbox_messages.rb.erb
74
+ - lib/pigeon/generators/rails/templates/initializer.rb.erb
75
+ - lib/pigeon/hanami_integration.rb
76
+ - lib/pigeon/health_check.rb
77
+ - lib/pigeon/health_check/kafka.rb
78
+ - lib/pigeon/health_check/processor.rb
79
+ - lib/pigeon/health_check/queue.rb
80
+ - lib/pigeon/logging/structured_logger.rb
81
+ - lib/pigeon/metrics/collector.rb
82
+ - lib/pigeon/mock_producer.rb
83
+ - lib/pigeon/models/adapters/active_record_adapter.rb
84
+ - lib/pigeon/models/adapters/rom_adapter.rb
85
+ - lib/pigeon/models/outbox_message.rb
86
+ - lib/pigeon/monitoring.rb
87
+ - lib/pigeon/outbox.rb
88
+ - lib/pigeon/processor.rb
89
+ - lib/pigeon/processor/background_processor.rb
90
+ - lib/pigeon/publisher.rb
91
+ - lib/pigeon/railtie.rb
92
+ - lib/pigeon/schema.rb
93
+ - lib/pigeon/security.rb
94
+ - lib/pigeon/serializer.rb
95
+ - lib/pigeon/tasks/pigeon.rake
96
+ - lib/pigeon/trace_api.rb
97
+ - lib/pigeon/tracing.rb
98
+ - lib/pigeon/tracing/core.rb
99
+ - lib/pigeon/tracing/messaging.rb
100
+ - lib/pigeon/version.rb
101
+ homepage: https://github.com/khaile/pigeon
102
+ licenses:
103
+ - MIT
104
+ metadata:
105
+ homepage_uri: https://github.com/khaile/pigeon
106
+ changelog_uri: https://github.com/khaile/pigeon/blob/main/CHANGELOG.md
107
+ rubygems_mfa_required: 'false'
108
+ post_install_message:
109
+ rdoc_options: []
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 3.3.8
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubygems_version: 3.5.22
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Kafka outbox pattern implementation for Ruby applications
127
+ test_files: []