pgmq-ruby 0.1.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.
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pg'
4
+ require 'connection_pool'
5
+
6
+ module PGMQ
7
+ # Manages database connections for PGMQ
8
+ #
9
+ # Supports multiple connection strategies:
10
+ # - Connection strings
11
+ # - Hash of connection parameters
12
+ # - Callable objects (for Rails ActiveRecord integration)
13
+ #
14
+ # @example With connection string
15
+ # conn = PGMQ::Connection.new("postgres://localhost/mydb")
16
+ #
17
+ # @example With connection hash
18
+ # conn = PGMQ::Connection.new(host: 'localhost', dbname: 'mydb')
19
+ #
20
+ # @example With Rails ActiveRecord (reuses Rails connection pool)
21
+ # conn = PGMQ::Connection.new(-> { ActiveRecord::Base.connection.raw_connection })
22
+ class Connection
23
+ # Default connection pool size
24
+ DEFAULT_POOL_SIZE = 5
25
+
26
+ # Default connection pool timeout in seconds
27
+ DEFAULT_POOL_TIMEOUT = 5
28
+
29
+ # @return [ConnectionPool] the connection pool
30
+ attr_reader :pool
31
+
32
+ # Creates a new connection manager
33
+ #
34
+ # @param conn_params [String, Hash, Proc] connection parameters or callable
35
+ # @param pool_size [Integer] size of the connection pool
36
+ # @param pool_timeout [Integer] connection pool timeout in seconds
37
+ # @param auto_reconnect [Boolean] automatically reconnect on connection errors
38
+ # @raise [PGMQ::Errors::ConfigurationError] if conn_params is nil or invalid
39
+ def initialize(
40
+ conn_params,
41
+ pool_size: DEFAULT_POOL_SIZE,
42
+ pool_timeout: DEFAULT_POOL_TIMEOUT,
43
+ auto_reconnect: true
44
+ )
45
+ if conn_params.nil?
46
+ raise(
47
+ PGMQ::Errors::ConfigurationError,
48
+ 'Connection parameters are required'
49
+ )
50
+ end
51
+
52
+ @conn_params = normalize_connection_params(conn_params)
53
+ @pool_size = pool_size
54
+ @pool_timeout = pool_timeout
55
+ @auto_reconnect = auto_reconnect
56
+ @pool = create_pool
57
+ end
58
+
59
+ # Executes a block with a connection from the pool
60
+ #
61
+ # @yield [PG::Connection] database connection
62
+ # @return [Object] result of the block
63
+ # @raise [PGMQ::Errors::ConnectionError] if connection fails
64
+ def with_connection
65
+ retries = @auto_reconnect ? 1 : 0
66
+ attempts = 0
67
+
68
+ begin
69
+ @pool.with do |conn|
70
+ # Health check: verify connection is alive
71
+ verify_connection!(conn) if @auto_reconnect
72
+
73
+ yield conn
74
+ end
75
+ rescue PG::Error => e
76
+ attempts += 1
77
+
78
+ # If connection error and auto_reconnect enabled, try once more
79
+ retry if attempts <= retries && connection_lost_error?(e)
80
+
81
+ raise PGMQ::Errors::ConnectionError, "Database connection error: #{e.message}"
82
+ rescue ConnectionPool::TimeoutError => e
83
+ raise PGMQ::Errors::ConnectionError, "Connection pool timeout: #{e.message}"
84
+ rescue ConnectionPool::PoolShuttingDownError => e
85
+ raise PGMQ::Errors::ConnectionError, "Connection pool is closed: #{e.message}"
86
+ end
87
+ end
88
+
89
+ # Closes all connections in the pool
90
+ # @return [void]
91
+ def close
92
+ @pool.shutdown { |conn| conn.close unless conn.finished? }
93
+ end
94
+
95
+ # Returns connection pool statistics
96
+ #
97
+ # @return [Hash] statistics about the connection pool
98
+ # @example
99
+ # stats = connection.stats
100
+ # # => { size: 5, available: 3 }
101
+ def stats
102
+ {
103
+ size: @pool_size,
104
+ available: @pool.available
105
+ }
106
+ end
107
+
108
+ private
109
+
110
+ # Checks if the error indicates a lost connection
111
+ # @param error [PG::Error] the error to check
112
+ # @return [Boolean] true if connection was lost
113
+ def connection_lost_error?(error)
114
+ # Common connection lost errors
115
+ lost_connection_messages = [
116
+ 'server closed the connection',
117
+ 'connection not open',
118
+ 'no connection to the server',
119
+ 'terminating connection',
120
+ 'connection to server was lost',
121
+ 'could not receive data from server'
122
+ ]
123
+
124
+ message = error.message.downcase
125
+ lost_connection_messages.any? { |pattern| message.include?(pattern) }
126
+ end
127
+
128
+ # Verifies a connection is alive and working
129
+ # @param conn [PG::Connection] connection to verify
130
+ # @raise [PG::Error] if connection is not working
131
+ def verify_connection!(conn)
132
+ # Quick check - is connection object in bad state?
133
+ return unless conn.finished?
134
+
135
+ # Connection is finished/closed, try to reset it
136
+ conn.reset
137
+ end
138
+
139
+ # Normalizes various connection parameter formats
140
+ # @param params [String, Hash, Proc]
141
+ # @return [Hash, Proc]
142
+ # @raise [PGMQ::Errors::ConfigurationError] if params format is invalid
143
+ def normalize_connection_params(params)
144
+ return params if params.respond_to?(:call) # Callable (e.g., proc for Rails)
145
+ return parse_connection_string(params) if params.is_a?(String)
146
+ return params if params.is_a?(Hash) && !params.empty?
147
+
148
+ raise PGMQ::Errors::ConfigurationError, 'Invalid connection parameters format'
149
+ end
150
+
151
+ # Parses a PostgreSQL connection string
152
+ # @param conn_string [String] connection string (e.g., "postgres://user:pass@host/db")
153
+ # @return [Hash] connection parameters
154
+ def parse_connection_string(conn_string)
155
+ # PG::Connection.conninfo_parse is available in pg >= 0.20
156
+ if PG::Connection.respond_to?(:conninfo_parse)
157
+ PG::Connection.conninfo_parse(conn_string).each_with_object({}) do |info, hash|
158
+ hash[info[:keyword].to_sym] = info[:val] if info[:val]
159
+ end
160
+ else
161
+ # Fallback: pass the string directly and let PG handle it
162
+ { conninfo: conn_string }
163
+ end
164
+ rescue PG::Error => e
165
+ raise PGMQ::Errors::ConfigurationError, "Invalid connection string: #{e.message}"
166
+ end
167
+
168
+ # Creates the connection pool
169
+ # @return [ConnectionPool]
170
+ def create_pool
171
+ params = @conn_params
172
+
173
+ ConnectionPool.new(size: @pool_size, timeout: @pool_timeout) do
174
+ create_connection(params)
175
+ end
176
+ rescue StandardError => e
177
+ raise PGMQ::Errors::ConnectionError, "Failed to create connection pool: #{e.message}"
178
+ end
179
+
180
+ # Creates a single database connection
181
+ # @param params [Hash, Proc] connection parameters or callable
182
+ # @return [PG::Connection]
183
+ def create_connection(params)
184
+ # If we have a callable (e.g., for Rails), call it to get the connection
185
+ return params.call if params.respond_to?(:call)
186
+
187
+ # Create new connection from parameters
188
+ # Low-level library: return all values as strings from PostgreSQL
189
+ # No automatic type conversion - let higher-level frameworks handle parsing
190
+ # conn.type_map_for_results intentionally NOT set
191
+ PG.connect(params[:conninfo] || params)
192
+ rescue PG::Error => e
193
+ raise PGMQ::Errors::ConnectionError, "Failed to connect to database: #{e.message}"
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PGMQ
4
+ # PGMQ errors namespace
5
+ module Errors
6
+ # Base error class for all PGMQ errors
7
+ class BaseError < StandardError; end
8
+
9
+ # Raised when connection to PostgreSQL fails or is lost
10
+ class ConnectionError < BaseError; end
11
+
12
+ # Raised when a queue operation is attempted on a non-existent queue
13
+ class QueueNotFoundError < BaseError; end
14
+
15
+ # Raised when a message cannot be found
16
+ class MessageNotFoundError < BaseError; end
17
+
18
+ # Raised when message serialization fails
19
+ class SerializationError < BaseError; end
20
+
21
+ # Raised when message deserialization fails
22
+ class DeserializationError < BaseError; end
23
+
24
+ # Raised when configuration is invalid
25
+ class ConfigurationError < BaseError; end
26
+
27
+ # Raised when an invalid queue name is provided
28
+ class InvalidQueueNameError < BaseError; end
29
+ end
30
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PGMQ
4
+ # Represents a message read from a PGMQ queue
5
+ #
6
+ # Returns raw values from PostgreSQL without transformation.
7
+ # Higher-level frameworks should handle parsing, deserialization, etc.
8
+ #
9
+ # @example Reading a message (raw values)
10
+ # msg = client.read("my_queue", vt: 30)
11
+ # puts msg.msg_id # => "123" (String from PG)
12
+ # puts msg.read_ct # => "1" (String from PG)
13
+ # puts msg.enqueued_at # => "2025-01-15 10:30:00+00" (String from PG)
14
+ # puts msg.vt # => "2025-01-15 10:30:30+00" (String from PG)
15
+ # puts msg.message # => "{\"order_id\":456}" (Raw JSONB string)
16
+ # puts msg.headers # => "{\"trace_id\":\"abc123\"}" (Raw JSONB string, optional)
17
+ # puts msg.queue_name # => "my_queue" (only present for multi-queue operations)
18
+ class Message < Data.define(
19
+ :msg_id, :read_ct, :enqueued_at, :vt, :message, :headers, :queue_name
20
+ )
21
+ class << self
22
+ # Creates a new Message from a database row
23
+ # @param row [Hash] database row from PG result
24
+ # @return [Message]
25
+ def new(row, **)
26
+ # Return raw values as-is from PostgreSQL
27
+ # No parsing, no deserialization, no transformation
28
+ # The pg gem returns JSONB as String by default
29
+ super(
30
+ msg_id: row['msg_id'],
31
+ read_ct: row['read_ct'],
32
+ enqueued_at: row['enqueued_at'],
33
+ vt: row['vt'],
34
+ message: row['message'],
35
+ headers: row['headers'], # JSONB column for metadata (optional)
36
+ queue_name: row['queue_name'] # nil for single-queue operations
37
+ )
38
+ end
39
+ end
40
+
41
+ # Alias for msg_id (common in messaging systems)
42
+ # @return [String]
43
+ alias id msg_id
44
+ end
45
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module PGMQ
6
+ # Represents metrics for a PGMQ queue
7
+ #
8
+ # @example Getting queue metrics
9
+ # metrics = client.metrics("my_queue")
10
+ # puts metrics.queue_length # => 42
11
+ # puts metrics.oldest_msg_age_sec # => 3600
12
+ class Metrics < Data.define(
13
+ :queue_name,
14
+ :queue_length,
15
+ :newest_msg_age_sec,
16
+ :oldest_msg_age_sec,
17
+ :total_messages,
18
+ :scrape_time
19
+ )
20
+ class << self
21
+ # Creates a new Metrics object from a database row
22
+ # @param row [Hash] database row from PG result
23
+ # @return [Metrics]
24
+ def new(row, **)
25
+ # Return raw values as-is from PostgreSQL
26
+ super(
27
+ queue_name: row['queue_name'],
28
+ queue_length: row['queue_length'],
29
+ newest_msg_age_sec: row['newest_msg_age_sec'],
30
+ oldest_msg_age_sec: row['oldest_msg_age_sec'],
31
+ total_messages: row['total_messages'],
32
+ scrape_time: row['scrape_time']
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module PGMQ
6
+ # Represents metadata about a PGMQ queue
7
+ #
8
+ # @example Listing queues
9
+ # queues = client.list_queues
10
+ # queues.each do |q|
11
+ # puts "#{q.queue_name} (partitioned: #{q.is_partitioned})"
12
+ # end
13
+ class QueueMetadata < Data.define(:queue_name, :created_at, :is_partitioned, :is_unlogged)
14
+ class << self
15
+ # Creates a new QueueMetadata object from a database row
16
+ # @param row [Hash] database row from PG result
17
+ # @return [QueueMetadata]
18
+ def new(row, **)
19
+ # Return raw values as-is from PostgreSQL
20
+ super(
21
+ queue_name: row['queue_name'],
22
+ created_at: row['created_at'],
23
+ is_partitioned: row['is_partitioned'],
24
+ is_unlogged: row['is_unlogged']
25
+ )
26
+ end
27
+ end
28
+
29
+ # Alias for is_partitioned
30
+ # @return [String] 't' or 'f' from PostgreSQL
31
+ alias partitioned? is_partitioned
32
+
33
+ # Alias for is_unlogged
34
+ # @return [String] 't' or 'f' from PostgreSQL
35
+ alias unlogged? is_unlogged
36
+ end
37
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PGMQ
4
+ # Low-level transaction support for PGMQ operations
5
+ #
6
+ # Provides atomic execution of PGMQ operations within PostgreSQL transactions.
7
+ # Transactions are a database primitive - this is a thin wrapper around
8
+ # PostgreSQL's native transaction support.
9
+ #
10
+ # This is analogous to rdkafka-ruby providing Kafka transaction support -
11
+ # it's a protocol/database feature, not a framework abstraction.
12
+ #
13
+ # @example Atomic multi-queue operations
14
+ # client.transaction do |txn|
15
+ # txn.produce("orders", '{"order_id":123}')
16
+ # txn.produce("notifications", '{"type":"order_created"}')
17
+ # end
18
+ #
19
+ # @example Automatic rollback on error
20
+ # client.transaction do |txn|
21
+ # txn.produce("orders", '{"order_id":123}')
22
+ # raise "Error" # Both operations rolled back
23
+ # end
24
+ module Transaction
25
+ # Executes PGMQ operations atomically within a database transaction
26
+ #
27
+ # Obtains a connection from the pool, starts a transaction, and yields
28
+ # a client that uses that transaction for all operations.
29
+ #
30
+ # @yield [PGMQ::Client] transactional client using the same connection
31
+ # @return [Object] result of the block
32
+ # @raise [PGMQ::Errors::ConnectionError] if transaction fails
33
+ #
34
+ # @example
35
+ # client.transaction do |txn|
36
+ # msg_id = txn.produce("queue", '{"data":"test"}')
37
+ # txn.delete("queue", msg_id)
38
+ # end
39
+ def transaction
40
+ @connection.with_connection do |conn|
41
+ conn.transaction do
42
+ yield TransactionalClient.new(self, conn)
43
+ end
44
+ end
45
+ rescue PG::Error, StandardError => e
46
+ raise PGMQ::Errors::ConnectionError, "Transaction failed: #{e.message}"
47
+ end
48
+
49
+ # Minimal wrapper that ensures all operations use the transaction connection
50
+ #
51
+ # @private
52
+ class TransactionalClient
53
+ # @param parent [PGMQ::Client] parent client instance
54
+ # @param conn [PG::Connection] transaction connection
55
+ def initialize(
56
+ parent,
57
+ conn
58
+ )
59
+ @parent = parent
60
+ @conn = conn
61
+ end
62
+
63
+ # Forward all method calls to parent, but use our transaction connection
64
+ # @param method [Symbol] method name
65
+ # @return [Object] result of method call
66
+ def method_missing(method, ...)
67
+ @parent.respond_to?(method, true) ? @parent.__send__(method, ...) : super
68
+ end
69
+
70
+ # Check if method exists on parent
71
+ # @param method [Symbol] method name
72
+ # @param include_private [Boolean] include private methods
73
+ # @return [Boolean] true if method exists
74
+ def respond_to_missing?(
75
+ method,
76
+ include_private = false
77
+ )
78
+ @parent.respond_to?(method, include_private) || super
79
+ end
80
+
81
+ # Inject our transaction connection instead of using the pool
82
+ def with_connection
83
+ yield @conn
84
+ end
85
+
86
+ # Expose parent's connection (for tests/inspection)
87
+ def connection
88
+ @parent.connection
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PGMQ
4
+ # Current version of the pgmq-ruby gem
5
+ VERSION = '0.4.0'
6
+ end
data/lib/pgmq.rb ADDED
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zeitwerk'
4
+ require 'time'
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.inflector.inflect(
8
+ 'pgmq' => 'PGMQ'
9
+ )
10
+ loader.setup
11
+ loader.eager_load
12
+
13
+ # PGMQ - Low-level Ruby client for Postgres Message Queue
14
+ #
15
+ # This is a low-level library providing direct access to PGMQ operations.
16
+ # For higher-level abstractions, job processing, and framework integrations,
17
+ # see pgmq-framework (similar to how rdkafka-ruby relates to Karafka).
18
+ #
19
+ # @example Basic usage
20
+ # require 'pgmq'
21
+ #
22
+ # # Create client with connection parameters
23
+ # client = PGMQ::Client.new(
24
+ # host: 'localhost',
25
+ # port: 5432,
26
+ # dbname: 'mydb',
27
+ # user: 'postgres',
28
+ # password: 'postgres'
29
+ # )
30
+ #
31
+ # # Or with connection string
32
+ # client = PGMQ::Client.new('postgres://localhost/mydb')
33
+ #
34
+ # # Basic queue operations
35
+ # client.create('orders')
36
+ # msg_id = client.produce('orders', '{"order_id":123}')
37
+ # msg = client.read('orders', vt: 30)
38
+ # client.delete('orders', msg.msg_id)
39
+ # client.drop_queue('orders')
40
+ module PGMQ
41
+ class << self
42
+ # Convenience method to create a new client
43
+ #
44
+ # @return [PGMQ::Client] new client instance
45
+ # @see PGMQ::Client#initialize
46
+ #
47
+ # @example
48
+ # client = PGMQ.new('postgres://localhost/mydb')
49
+ def new(*, **)
50
+ Client.new(*, **)
51
+ end
52
+ end
53
+ end
data/pgmq-ruby.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/pgmq/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'pgmq-ruby'
7
+ spec.version = PGMQ::VERSION
8
+ spec.authors = ['Maciej Mensfeld']
9
+ spec.email = ['maciej@mensfeld.pl']
10
+
11
+ spec.summary = 'Ruby client for PGMQ (Postgres Message Queue)'
12
+ spec.description = 'A Ruby driver for PGMQ - a lightweight message queue built on PostgreSQL. ' \
13
+ 'Like AWS SQS and RSMQ, but on Postgres.'
14
+ spec.homepage = 'https://github.com/mensfeld/pgmq-ruby'
15
+ spec.license = 'LGPL-3.0'
16
+ spec.required_ruby_version = '>= 3.2.0'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = 'https://github.com/mensfeld/pgmq-ruby'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/mensfeld/pgmq-ruby/blob/master/CHANGELOG.md'
21
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/mensfeld/pgmq-ruby/issues'
22
+ spec.metadata['documentation_uri'] = 'https://github.com/mensfeld/pgmq-ruby#readme'
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|examples)/}) }
26
+ spec.require_paths = ['lib']
27
+
28
+ # Runtime dependencies
29
+ spec.add_dependency 'connection_pool', '~> 2.4'
30
+ spec.add_dependency 'pg', '~> 1.5'
31
+ spec.add_dependency 'zeitwerk', '~> 2.6'
32
+ end
data/renovate.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:recommended"
5
+ ],
6
+ "minimumReleaseAge": "7 days",
7
+ "github-actions": {
8
+ "enabled": true,
9
+ "pinDigests": true
10
+ }
11
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgmq-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -9,6 +9,20 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: connection_pool
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '2.4'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '2.4'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: pg
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -23,13 +37,60 @@ dependencies:
23
37
  - - "~>"
24
38
  - !ruby/object:Gem::Version
25
39
  version: '1.5'
26
- description: A Ruby driver for PGMQ - a lightweight message queue built on PostgreSQL
40
+ - !ruby/object:Gem::Dependency
41
+ name: zeitwerk
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.6'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.6'
54
+ description: A Ruby driver for PGMQ - a lightweight message queue built on PostgreSQL.
55
+ Like AWS SQS and RSMQ, but on Postgres.
27
56
  email:
28
- - contact@karafka.io
57
+ - maciej@mensfeld.pl
29
58
  executables: []
30
59
  extensions: []
31
60
  extra_rdoc_files: []
32
- files: []
61
+ files:
62
+ - ".coditsu/ci.yml"
63
+ - ".github/workflows/ci.yml"
64
+ - ".github/workflows/push.yml"
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".ruby-version"
68
+ - ".yard-lint.yml"
69
+ - CHANGELOG.md
70
+ - Gemfile
71
+ - Gemfile.lock
72
+ - LICENSE
73
+ - README.md
74
+ - Rakefile
75
+ - docker-compose.yml
76
+ - lib/pgmq.rb
77
+ - lib/pgmq/client.rb
78
+ - lib/pgmq/client/consumer.rb
79
+ - lib/pgmq/client/maintenance.rb
80
+ - lib/pgmq/client/message_lifecycle.rb
81
+ - lib/pgmq/client/metrics.rb
82
+ - lib/pgmq/client/multi_queue.rb
83
+ - lib/pgmq/client/producer.rb
84
+ - lib/pgmq/client/queue_management.rb
85
+ - lib/pgmq/connection.rb
86
+ - lib/pgmq/errors.rb
87
+ - lib/pgmq/message.rb
88
+ - lib/pgmq/metrics.rb
89
+ - lib/pgmq/queue_metadata.rb
90
+ - lib/pgmq/transaction.rb
91
+ - lib/pgmq/version.rb
92
+ - pgmq-ruby.gemspec
93
+ - renovate.json
33
94
  homepage: https://github.com/mensfeld/pgmq-ruby
34
95
  licenses:
35
96
  - LGPL-3.0
@@ -38,6 +99,7 @@ metadata:
38
99
  source_code_uri: https://github.com/mensfeld/pgmq-ruby
39
100
  changelog_uri: https://github.com/mensfeld/pgmq-ruby/blob/master/CHANGELOG.md
40
101
  bug_tracker_uri: https://github.com/mensfeld/pgmq-ruby/issues
102
+ documentation_uri: https://github.com/mensfeld/pgmq-ruby#readme
41
103
  rubygems_mfa_required: 'true'
42
104
  rdoc_options: []
43
105
  require_paths:
@@ -53,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
115
  - !ruby/object:Gem::Version
54
116
  version: '0'
55
117
  requirements: []
56
- rubygems_version: 3.6.9
118
+ rubygems_version: 4.0.3
57
119
  specification_version: 4
58
120
  summary: Ruby client for PGMQ (Postgres Message Queue)
59
121
  test_files: []