pg-locks-monitor 0.0.1 → 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.
- checksums.yaml +4 -4
- data/README.md +198 -1
- data/lib/pg-locks-monitor.rb +33 -0
- data/lib/pg_locks_monitor/configuration.rb +49 -0
- data/lib/pg_locks_monitor/default_notifier.rb +32 -0
- data/lib/pg_locks_monitor/railtie.rb +7 -0
- data/lib/pg_locks_monitor/tasks/all.rake +22 -0
- data/lib/pg_locks_monitor/version.rb +1 -1
- data/pg-locks-monitor.gemspec +2 -1
- data/spec/configuration_spec.rb +22 -0
- data/spec/default_notifier_spec.rb +37 -0
- metadata +25 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9127ef19c571c1eda59fa9962c694c6a416f4d2875d6660091cb72479e09d98
|
4
|
+
data.tar.gz: 56a1e90355cad04a9834e2a6eafeb76c9633596a9e786ce639af838757c1e87e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9d94a09139dd75cfc5672aa863e288ed6654fa4953cf00dbbd62a6ec63e63feb60c99208f0aa0dda2ce01ccadd9cd92b3b58d05200be53bb75579e44bf85f9d
|
7
|
+
data.tar.gz: 6f57a40ce88babd6fcdd176371462c4b6fa40c248da5472ae1cfdcdad685bc17f0a5a3bbf0f152e7de50d48dbc84a18a8443d1ce6ce90bf112278b506e81a839
|
data/README.md
CHANGED
@@ -1,3 +1,200 @@
|
|
1
1
|
# PG Locks Monitor [](https://badge.fury.io/rb/pg-locks-monitor) [](https://github.com/pawurb/pg-locks-monitor/actions)
|
2
2
|
|
3
|
-
|
3
|
+
This gem allows to observe database locks generated by a Rails application. By default, locks data is not persisted anywhere in the PostgreSQL logs, so the only way to monitor it is via analyzing the transient state of the `pg_locks` metadata table. `pg-locks-monitor` is a simple tool that makes this process quick to implement and adjust to each app's individual requirements.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
`PgLocksMonitor` class provides a `snapshot!` method, which notifies selected channels about database locks that match configured criteria.
|
8
|
+
|
9
|
+
Start by adding the gem to your Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem "pg-locks-monitor"
|
13
|
+
```
|
14
|
+
|
15
|
+
Then run `bundle install` and `rake pg_locks_monitor:init`. It creates a default configuration file with the following settings:
|
16
|
+
|
17
|
+
`config/initializers/pg_locks_monitor.rb`
|
18
|
+
```ruby
|
19
|
+
PgLocksMonitor.configure do |config|
|
20
|
+
config.locks_limit = 5
|
21
|
+
|
22
|
+
config.monitor_locks = true
|
23
|
+
config.locks_min_duration_ms = 200
|
24
|
+
|
25
|
+
config.monitor_blocking = true
|
26
|
+
config.blocking_min_duration_ms = 100
|
27
|
+
|
28
|
+
config.notify_logs = true
|
29
|
+
|
30
|
+
config.notify_slack = false
|
31
|
+
config.slack_webhook_url = ""
|
32
|
+
config.slack_channel = ""
|
33
|
+
|
34
|
+
config.notifier_class = PgLocksMonitor::DefaultNotifier
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
- `locks_limit` - specify the max number of locks to report in a single notification
|
39
|
+
- `notify_locks` - observe database locks even if they don't conflict with a different SQL query
|
40
|
+
- `locks_min_duration_ms` - notify about locks that execeed this duration threshold in milliseconds
|
41
|
+
- `notify_blocking` - observe database locks which cause other SQL query to wait from them to release
|
42
|
+
- `blocking_min_duration_ms` - notify about blocking locks that execeed this duration threshold in milliseconds
|
43
|
+
- `notify_logs` - send notifications about detected locks using `Rails.logger.info` method
|
44
|
+
- `notify_slack` - send notifications about detected locks to the configured Slack channel
|
45
|
+
- `slack_webhook_url` - webhook necessary for Slack notification to work
|
46
|
+
- `slack_channel` - the name of the target Slack channel
|
47
|
+
- `notifier_class` - customizable notifier class
|
48
|
+
|
49
|
+
|
50
|
+
## Testing the notification channels
|
51
|
+
|
52
|
+
Before configuring a recurring invocation of the `snapshot!` method, it's recommended to first manually trigger the notification to test the configured channels.
|
53
|
+
|
54
|
+
You can generate an _"artificial"_ blocking lock and observe it by running the following code in the Rails console:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
user = User.last
|
58
|
+
|
59
|
+
Thread.new do
|
60
|
+
User.transaction do
|
61
|
+
user.update(email: "email-#{SecureRandom.hex(2)}@example.com")
|
62
|
+
sleep 5
|
63
|
+
raise ActiveRecord::Rollback
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Thread.new do
|
68
|
+
User.transaction do
|
69
|
+
user.update(email: "email-#{SecureRandom.hex(2)}@example.com")
|
70
|
+
sleep 5
|
71
|
+
raise ActiveRecord::Rollback
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
sleep 0.5
|
76
|
+
PgLocksMonitor.snapshot!
|
77
|
+
```
|
78
|
+
|
79
|
+
Please remember to adjust the update operation to match your app's schema.
|
80
|
+
|
81
|
+
As a result of running the above snippet, you should receive a notification about the acquired blocking database lock.
|
82
|
+
|
83
|
+
### Sample notification
|
84
|
+
|
85
|
+
Received notifications contain data helpful in debugging the cause of long lasting-locks.
|
86
|
+
|
87
|
+
And here's a sample blocking lock notification:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
[
|
91
|
+
{
|
92
|
+
# PID of the process which was blocking another query
|
93
|
+
"blocking_pid": 29,
|
94
|
+
# SQL query blocking other SQL query
|
95
|
+
"blocking_statement": "UPDATE \"users\" SET \"updated_at\" = $1 WHERE \"users\".\"id\" = $2 from/sidekiq_job:UserUpdater/",
|
96
|
+
# the duration of blocking SQL query
|
97
|
+
"blocking_duration": "PT0.972116S",
|
98
|
+
# app that triggered the blocking SQL query
|
99
|
+
"blocking_sql_app": "bin/sidekiq",
|
100
|
+
|
101
|
+
# PID of the process which was blocked by another query
|
102
|
+
"blocked_pid": 30,
|
103
|
+
# SQL query blocked by other SQL query
|
104
|
+
"blocked_statement": "UPDATE \"users\" SET \"last_active_at\" = $1 WHERE \"users\".\"id\" = $2 from/controller_with_namespace:UsersController,action:update/",
|
105
|
+
# the duration of the blocked SQL query
|
106
|
+
"blocked_duration": "PT0.483309S",
|
107
|
+
# app that triggered the blocked SQL query
|
108
|
+
"blocked_sql_app": "bin/puma"
|
109
|
+
}
|
110
|
+
]
|
111
|
+
```
|
112
|
+
|
113
|
+
This sample blocking notification shows than a query originating from the `UserUpdater` Sidekiq job is blocking an update operation on the same user for the `UsersController#update` action. Remember to configure the [marginalia gem](https://github.com/basecamp/marginalia) to enable these helpful query source annotations.
|
114
|
+
|
115
|
+
Here's a sample lock notification:
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
[
|
119
|
+
{
|
120
|
+
# PID of the process which acquired the lock
|
121
|
+
"pid": 50,
|
122
|
+
# name of affected table/index
|
123
|
+
"relname": "users",
|
124
|
+
# ID of the source transaction
|
125
|
+
"transactionid": null,
|
126
|
+
# bool indicating if the lock is already granted
|
127
|
+
"granted": true,
|
128
|
+
# type of the acquired lock
|
129
|
+
"mode": "RowExclusiveLock",
|
130
|
+
# SQL query which acquired the lock
|
131
|
+
"query_snippet": "UPDATE \"users\" SET \"updated_at\" = $1 WHERE \"users\".\"id\" = $2 from/sidekiq_job:UserUpdater/",
|
132
|
+
# age of the lock
|
133
|
+
"age": "PT0.94945S",
|
134
|
+
# app that acquired the lock
|
135
|
+
"application": "bin/sidekiq"
|
136
|
+
},
|
137
|
+
```
|
138
|
+
|
139
|
+
You can read [this blogpost](https://pawelurbanek.com/rails-postgresql-locks) for more detailed info on locks in the Rails apps.
|
140
|
+
|
141
|
+
## Background job config
|
142
|
+
|
143
|
+
This gem is intended to be used via a recurring background job, but it is agnostic to the background job provider. Here's a sample Sidekiq implementation:
|
144
|
+
|
145
|
+
`app/jobs/pg_locks_monitor_job.rb`
|
146
|
+
```ruby
|
147
|
+
require 'pg-locks-monitor'
|
148
|
+
|
149
|
+
class PgLocksMonitoringJob
|
150
|
+
include Sidekiq::Worker
|
151
|
+
sidekiq_options retry: false
|
152
|
+
|
153
|
+
def perform
|
154
|
+
PgLocksMonitor.snapshot!
|
155
|
+
ensure
|
156
|
+
if ENV["PG_LOCKS_MONITOR_ENABLED"]
|
157
|
+
PgLocksMonitoringJob.perform_in(1.minute)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
```
|
162
|
+
|
163
|
+
Remember to schedule this job when your app starts:
|
164
|
+
`config/pg_locks_monitor.rb`
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
#...
|
168
|
+
|
169
|
+
if ENV["PG_LOCKS_MONITOR_ENABLED"]
|
170
|
+
PgLocksMonitoringJob.perform
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
A background job that schedules itself is not the cleanest pattern. So alternatively you can use [sidekiq-cron](https://github.com/sidekiq-cron/sidekiq-cron), [whenever](https://github.com/javan/whenever) or [clockwork](https://github.com/adamwiggins/clockwork) gems to trigger the `PgLocksMonitor.snapshot!` invocation periodically.
|
175
|
+
|
176
|
+
A recommended frequency of invocation depends on your app's traffic. From my experience, even 1 minute apart snapshots can provide a lot of valuable data, but it all depends on how often the locks are occurring in your Rails application.
|
177
|
+
|
178
|
+
## Custom notifier class
|
179
|
+
|
180
|
+
`PgLocksMonitor::DefaultNotifier` supports sending lock notifications with `Rails.logger` or to a Slack channel. If you want to use different notification channels you can define your custom notifier like that:
|
181
|
+
|
182
|
+
`config/initializers/pg_locks_monitor.rb`
|
183
|
+
```ruby
|
184
|
+
class PgLocksEmailNotifier
|
185
|
+
def self.call(locks_data)
|
186
|
+
LocksMailer.with(locks_data: locks_data).notification.deliver_now
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
PgLocksMonitor.configure do |config|
|
191
|
+
# ...
|
192
|
+
|
193
|
+
config.notifier_class = PgLocksEmailNotifier
|
194
|
+
end
|
195
|
+
|
196
|
+
```
|
197
|
+
|
198
|
+
## Contributions
|
199
|
+
|
200
|
+
This gem is in a very early stage of development so feedback and PRs are welcome.
|
data/lib/pg-locks-monitor.rb
CHANGED
@@ -4,4 +4,37 @@ require "uri"
|
|
4
4
|
require "pg"
|
5
5
|
|
6
6
|
module PgLocksMonitor
|
7
|
+
def self.snapshot!
|
8
|
+
locks = RailsPgExtras.locks(
|
9
|
+
in_format: :hash, args: {
|
10
|
+
limit: configuration.locks_limit,
|
11
|
+
},
|
12
|
+
).select do |lock|
|
13
|
+
(ActiveSupport::Duration.parse(lock.fetch("age")).to_f * 1000) > configuration.locks_min_duration_ms
|
14
|
+
end
|
15
|
+
|
16
|
+
if locks.present? && configuration.monitor_locks
|
17
|
+
configuration.notifier_class.call(locks)
|
18
|
+
end
|
19
|
+
|
20
|
+
blocking = RailsPgExtras.blocking(in_format: :hash).select do |block|
|
21
|
+
(ActiveSupport::Duration.parse(block.fetch("blocking_duration")).to_f * 1000) > configuration.blocking_min_duration_ms
|
22
|
+
end
|
23
|
+
|
24
|
+
if blocking.present? && configuration.monitor_blocking
|
25
|
+
configuration.notifier_class.call(blocking)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.configuration
|
30
|
+
@configuration ||= Configuration.new(Configuration::DEFAULT)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.configure
|
34
|
+
yield(configuration)
|
35
|
+
end
|
7
36
|
end
|
37
|
+
|
38
|
+
require "pg_locks_monitor/default_notifier"
|
39
|
+
require "pg_locks_monitor/configuration"
|
40
|
+
require "pg_locks_monitor/railtie" if defined?(Rails)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PgLocksMonitor
|
4
|
+
class Configuration
|
5
|
+
DEFAULT = {
|
6
|
+
locks_limit: 5,
|
7
|
+
monitor_locks: true,
|
8
|
+
monitor_blocking: true,
|
9
|
+
locks_min_duration_ms: 200,
|
10
|
+
blocking_min_duration_ms: 100,
|
11
|
+
notify_logs: true,
|
12
|
+
notify_slack: false,
|
13
|
+
slack_webhook_url: nil,
|
14
|
+
slack_channel: nil,
|
15
|
+
notifier_class: PgLocksMonitor::DefaultNotifier,
|
16
|
+
}
|
17
|
+
|
18
|
+
attr_accessor *DEFAULT.keys
|
19
|
+
|
20
|
+
def initialize(attrs)
|
21
|
+
DEFAULT.keys.each do |key|
|
22
|
+
value = attrs.fetch(key) { DEFAULT.fetch(key) }
|
23
|
+
public_send("#{key}=", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULT_CONFIG_FILE = <<-CONFIG
|
28
|
+
# Configuration for pg-locks-monitor
|
29
|
+
|
30
|
+
PgLocksMonitor.configure do |config|
|
31
|
+
config.locks_limit = #{DEFAULT[:locks_limit]}
|
32
|
+
|
33
|
+
config.monitor_locks = #{DEFAULT[:monitor_locks]}
|
34
|
+
config.monitor_blocking = #{DEFAULT[:monitor_blocking]}
|
35
|
+
|
36
|
+
config.locks_min_duration_ms = #{DEFAULT[:locks_min_duration_ms]}
|
37
|
+
config.blocking_min_duration_ms = #{DEFAULT[:blocking_min_duration_ms]}
|
38
|
+
|
39
|
+
config.notify_logs = #{DEFAULT[:notify_logs]}
|
40
|
+
|
41
|
+
config.notify_slack = #{DEFAULT[:notify_slack]}
|
42
|
+
config.slack_webhook_url = "#{DEFAULT[:slack_webhook_url]}"
|
43
|
+
config.slack_channel = "#{DEFAULT[:slack_channel]}"
|
44
|
+
|
45
|
+
config.notifier_class = #{DEFAULT[:notifier_class]}
|
46
|
+
end
|
47
|
+
CONFIG
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "slack-notifier"
|
4
|
+
|
5
|
+
module PgLocksMonitor
|
6
|
+
class DefaultNotifier
|
7
|
+
def self.call(locks_data)
|
8
|
+
config = PgLocksMonitor.configuration
|
9
|
+
|
10
|
+
if config.notify_logs && defined?(Rails)
|
11
|
+
Rails.logger.info locks_data.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
if config.notify_slack
|
15
|
+
slack_webhook_url = config.slack_webhook_url
|
16
|
+
if slack_webhook_url.nil? || slack_webhook_url.strip.length == 0
|
17
|
+
raise "Missing pg-locks-monitor slack_webhook_url config"
|
18
|
+
end
|
19
|
+
|
20
|
+
slack_channel = config.slack_channel
|
21
|
+
if slack_channel.nil? || slack_channel.strip.length == 0
|
22
|
+
raise "Missing pg-locks-monitor slack_channel config"
|
23
|
+
end
|
24
|
+
|
25
|
+
Slack::Notifier.new(
|
26
|
+
slack_webhook_url,
|
27
|
+
channel: slack_channel,
|
28
|
+
).ping JSON.pretty_generate(locks_data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pg-locks-monitor"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
namespace :pg_locks_monitor do
|
7
|
+
desc "Initialize a config file"
|
8
|
+
task :init do
|
9
|
+
file_path = "config/initializers/pg_locks_monitor.rb"
|
10
|
+
if File.exist?(file_path)
|
11
|
+
puts "#{file_path} config file has already been initialized!"
|
12
|
+
else
|
13
|
+
File.write(file_path, PgLocksMonitor::Configuration::DEFAULT_CONFIG_FILE)
|
14
|
+
puts "Config file created at #{file_path}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Check for currently active locks"
|
19
|
+
task snapshot: :environment do
|
20
|
+
PgLocksMonitor.snapshot!
|
21
|
+
end
|
22
|
+
end
|
data/pg-locks-monitor.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.version = PgLocksMonitor::VERSION
|
9
9
|
s.authors = ["pawurb"]
|
10
10
|
s.email = ["contact@pawelurbanek.com"]
|
11
|
-
s.summary = %q{ Observe PostgreSQL database locks obtained by
|
11
|
+
s.summary = %q{ Observe PostgreSQL database locks obtained by a Rails application. }
|
12
12
|
s.description = %q{ This gem allows to monitor and notify about PostgreSQL database locks which meet certain criteria. You can report locks which are held for a certain amount of time, or locks which are held by a certain query. }
|
13
13
|
s.homepage = "http://github.com/pawurb/pg-locks-monitor"
|
14
14
|
s.files = `git ls-files`.split("\n")
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.license = "MIT"
|
18
18
|
s.add_dependency "ruby-pg-extras"
|
19
|
+
s.add_dependency "slack-notifier"
|
19
20
|
s.add_development_dependency "rake"
|
20
21
|
s.add_development_dependency "rspec"
|
21
22
|
s.add_development_dependency "rufo"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "PgLocksMonitor::Configuration" do
|
6
|
+
it "has a default configuration" do
|
7
|
+
config = PgLocksMonitor.configuration
|
8
|
+
expect(config.monitor_locks).to eq true
|
9
|
+
expect(config.monitor_blocking).to eq true
|
10
|
+
expect(config.locks_min_duration_ms).to eq 200
|
11
|
+
expect(config.blocking_min_duration_ms).to eq 100
|
12
|
+
expect(config.notifier_class).to eq PgLocksMonitor::DefaultNotifier
|
13
|
+
end
|
14
|
+
|
15
|
+
it "can be configured" do
|
16
|
+
PgLocksMonitor.configure do |config|
|
17
|
+
config.monitor_locks = false
|
18
|
+
end
|
19
|
+
|
20
|
+
expect(PgLocksMonitor.configuration.monitor_locks).to eq false
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe PgLocksMonitor::DefaultNotifier do
|
6
|
+
before do
|
7
|
+
# Mock Rails and its logger
|
8
|
+
Rails = nil
|
9
|
+
logger_double = double("Logger")
|
10
|
+
allow(logger_double).to receive(:info)
|
11
|
+
allow(Rails).to receive(:logger).and_return(logger_double)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "requires correct config if Slack notifications enabled" do
|
15
|
+
expect {
|
16
|
+
PgLocksMonitor::DefaultNotifier.call({})
|
17
|
+
}.not_to raise_error
|
18
|
+
PgLocksMonitor.configure do |config|
|
19
|
+
config.notify_slack = true
|
20
|
+
end
|
21
|
+
|
22
|
+
expect {
|
23
|
+
PgLocksMonitor::DefaultNotifier.call({})
|
24
|
+
}.to raise_error(RuntimeError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sends the Slack notification if enabled" do
|
28
|
+
PgLocksMonitor.configure do |config|
|
29
|
+
config.notify_slack = true
|
30
|
+
config.slack_webhook_url = "https://hooks.slack.com/services/123456789/123456789/123456789"
|
31
|
+
config.slack_channel = "pg-locks-monitor"
|
32
|
+
end
|
33
|
+
|
34
|
+
expect_any_instance_of(Slack::Notifier).to receive(:ping)
|
35
|
+
PgLocksMonitor::DefaultNotifier.call({ locks: "data" })
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg-locks-monitor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pawurb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-pg-extras
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: slack-notifier
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,8 +97,14 @@ files:
|
|
83
97
|
- Rakefile
|
84
98
|
- docker-compose.yml.sample
|
85
99
|
- lib/pg-locks-monitor.rb
|
100
|
+
- lib/pg_locks_monitor/configuration.rb
|
101
|
+
- lib/pg_locks_monitor/default_notifier.rb
|
102
|
+
- lib/pg_locks_monitor/railtie.rb
|
103
|
+
- lib/pg_locks_monitor/tasks/all.rake
|
86
104
|
- lib/pg_locks_monitor/version.rb
|
87
105
|
- pg-locks-monitor.gemspec
|
106
|
+
- spec/configuration_spec.rb
|
107
|
+
- spec/default_notifier_spec.rb
|
88
108
|
- spec/smoke_spec.rb
|
89
109
|
- spec/spec_helper.rb
|
90
110
|
homepage: http://github.com/pawurb/pg-locks-monitor
|
@@ -110,7 +130,9 @@ requirements: []
|
|
110
130
|
rubygems_version: 3.5.4
|
111
131
|
signing_key:
|
112
132
|
specification_version: 4
|
113
|
-
summary: Observe PostgreSQL database locks obtained by
|
133
|
+
summary: Observe PostgreSQL database locks obtained by a Rails application.
|
114
134
|
test_files:
|
135
|
+
- spec/configuration_spec.rb
|
136
|
+
- spec/default_notifier_spec.rb
|
115
137
|
- spec/smoke_spec.rb
|
116
138
|
- spec/spec_helper.rb
|