pg-locks-monitor 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -5
- data/README.md +42 -6
- data/lib/pg-locks-monitor.rb +8 -6
- data/lib/pg_locks_monitor/configuration.rb +5 -0
- data/lib/pg_locks_monitor/version.rb +1 -1
- metadata +2 -4
- data/spec/smoke_spec.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f95c5c531f0c74143c8fa74417344e1e5b3e400b06f910528541a69ee89f0aaa
|
4
|
+
data.tar.gz: fd704b6c9562678541aaaa1cbd98ab997281a529cbfba35f0235466000de0599
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c467b40b8114d8ca11a5aa89b91e5d0d3637a287d041e8f2d383f0465798d38e8d20f0248408fa4dbce90ef6eb74ef3bb022f78815fb3d676c07272279892b6
|
7
|
+
data.tar.gz: 9fdcecb73e646f43a2143db60a12d01f0cc766ed9ee633a63ca1254cce82c7de5688c1594c518b7adf269aed67a77d8da2c4e25a363372beaf19fa9d91b253c5
|
data/.github/workflows/ci.yml
CHANGED
@@ -83,7 +83,7 @@ jobs:
|
|
83
83
|
POSTGRES_PASSWORD: secret
|
84
84
|
DATABASE_URL: postgresql://postgres:secret@localhost:5432/pg-locks-monitor-test
|
85
85
|
run: |
|
86
|
-
bundle exec
|
86
|
+
bundle exec rake test_all
|
87
87
|
- name: Run tests for PG 12
|
88
88
|
env:
|
89
89
|
PG_VERSION: 12
|
@@ -93,7 +93,7 @@ jobs:
|
|
93
93
|
POSTGRES_PASSWORD: secret
|
94
94
|
DATABASE_URL: postgresql://postgres:secret@localhost:5433/pg-locks-monitor-test
|
95
95
|
run: |
|
96
|
-
bundle exec
|
96
|
+
bundle exec rake test_all
|
97
97
|
- name: Run tests for PG 13
|
98
98
|
env:
|
99
99
|
PG_VERSION: 13
|
@@ -103,7 +103,7 @@ jobs:
|
|
103
103
|
POSTGRES_PASSWORD: secret
|
104
104
|
DATABASE_URL: postgresql://postgres:secret@localhost:5434/pg-locks-monitor-test
|
105
105
|
run: |
|
106
|
-
bundle exec
|
106
|
+
bundle exec rake test_all
|
107
107
|
- name: Run tests for PG 14
|
108
108
|
env:
|
109
109
|
PG_VERSION: 14
|
@@ -113,7 +113,7 @@ jobs:
|
|
113
113
|
POSTGRES_PASSWORD: secret
|
114
114
|
DATABASE_URL: postgresql://postgres:secret@localhost:5435/pg-locks-monitor-test
|
115
115
|
run: |
|
116
|
-
bundle exec
|
116
|
+
bundle exec rake test_all
|
117
117
|
- name: Run tests for PG 15
|
118
118
|
env:
|
119
119
|
PG_VERSION: 15
|
@@ -123,5 +123,5 @@ jobs:
|
|
123
123
|
POSTGRES_PASSWORD: secret
|
124
124
|
DATABASE_URL: postgresql://postgres:secret@localhost:5436/pg-locks-monitor-test
|
125
125
|
run: |
|
126
|
-
bundle exec
|
126
|
+
bundle exec rake test_all
|
127
127
|
|
data/README.md
CHANGED
@@ -2,6 +2,10 @@
|
|
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
4
|
|
5
|
+
You can read [this blogpost](https://pawelurbanek.com/rails-postgresql-locks) for more detailed info on database locks in the Rails apps.
|
6
|
+
|
7
|
+
**Shameless plug:** pg-locks-monitor is just one of the tools that I use when conducting [Rails performance audits](https://pawelurbanek.com/). Check out my offer if you need help with optimizing your application.
|
8
|
+
|
5
9
|
## Usage
|
6
10
|
|
7
11
|
`PgLocksMonitor` class provides a `snapshot!` method, which notifies selected channels about database locks that match configured criteria.
|
@@ -32,24 +36,28 @@ PgLocksMonitor.configure do |config|
|
|
32
36
|
config.slack_channel = ""
|
33
37
|
|
34
38
|
config.notifier_class = PgLocksMonitor::DefaultNotifier
|
39
|
+
|
40
|
+
config.locks_filter_proc = ->(lock) { true }
|
41
|
+
config.blocking_filter_proc = ->(lock) { true }
|
35
42
|
end
|
36
43
|
```
|
37
44
|
|
38
45
|
- `locks_limit` - specify the max number of locks to report in a single notification
|
39
|
-
- `
|
46
|
+
- `monitor_locks` - observe database locks even if they don't conflict with a different SQL query
|
40
47
|
- `locks_min_duration_ms` - notify about locks that execeed this duration threshold in milliseconds
|
41
|
-
- `
|
48
|
+
- `monitor_blocking` - observe database locks which cause other SQL query to wait from them to release
|
42
49
|
- `blocking_min_duration_ms` - notify about blocking locks that execeed this duration threshold in milliseconds
|
43
50
|
- `notify_logs` - send notifications about detected locks using `Rails.logger.info` method
|
44
51
|
- `notify_slack` - send notifications about detected locks to the configured Slack channel
|
45
52
|
- `slack_webhook_url` - webhook necessary for Slack notification to work
|
46
53
|
- `slack_channel` - the name of the target Slack channel
|
47
54
|
- `notifier_class` - customizable notifier class
|
48
|
-
|
55
|
+
- `locks_filter_proc` - configurable filter to exclude locks based on any custom logic
|
56
|
+
- `blocking_filter_proc` - configurable filter to exclude blocking locks based on any custom logic
|
49
57
|
|
50
58
|
## Testing the notification channels
|
51
59
|
|
52
|
-
Before
|
60
|
+
Before enabling a recurring invocation of the `snapshot!` method, it's recommended to first manually trigger the notification to test the configured channels.
|
53
61
|
|
54
62
|
You can generate an _"artificial"_ blocking lock and observe it by running the following code in the Rails console:
|
55
63
|
|
@@ -136,8 +144,6 @@ Here's a sample lock notification:
|
|
136
144
|
},
|
137
145
|
```
|
138
146
|
|
139
|
-
You can read [this blogpost](https://pawelurbanek.com/rails-postgresql-locks) for more detailed info on locks in the Rails apps.
|
140
|
-
|
141
147
|
## Background job config
|
142
148
|
|
143
149
|
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:
|
@@ -175,6 +181,36 @@ A background job that schedules itself is not the cleanest pattern. So alternati
|
|
175
181
|
|
176
182
|
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
183
|
|
184
|
+
## Filter procs
|
185
|
+
|
186
|
+
You can modify `locks_filter_proc` and `blocking_filter_proc` to exclude locks from getting reported. For example, here's how you can report only locks that originated from the Puma server process:
|
187
|
+
|
188
|
+
`config/initializers/pg_locks_monitor.rb`
|
189
|
+
```ruby
|
190
|
+
PgLocksMonitor.configure do |config|
|
191
|
+
# ...
|
192
|
+
|
193
|
+
config.locks_filter_proc = -> (lock) {
|
194
|
+
lock.fetch("application").downcase.include?("puma")
|
195
|
+
}
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
or exclude blocking locks which are affecting only the Sidekiq process:
|
200
|
+
|
201
|
+
`config/initializers/pg_locks_monitor.rb`
|
202
|
+
```ruby
|
203
|
+
PgLocksMonitor.configure do |config|
|
204
|
+
# ...
|
205
|
+
|
206
|
+
config.blocking_filter_proc = -> (lock) {
|
207
|
+
lock.fetch("blocked_sql_app").downcase.include?("sidekiq")
|
208
|
+
}
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
Please beware that configuring these procs does not overwrite the min duration settings, i.e., `locks_min_duration_ms` and `blocking_min_duration_ms`.
|
213
|
+
|
178
214
|
## Custom notifier class
|
179
215
|
|
180
216
|
`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:
|
data/lib/pg-locks-monitor.rb
CHANGED
@@ -6,12 +6,13 @@ require "pg"
|
|
6
6
|
module PgLocksMonitor
|
7
7
|
def self.snapshot!
|
8
8
|
locks = RailsPgExtras.locks(
|
9
|
-
in_format: :hash,
|
10
|
-
limit: configuration.locks_limit,
|
11
|
-
},
|
9
|
+
in_format: :hash,
|
12
10
|
).select do |lock|
|
13
|
-
(
|
14
|
-
|
11
|
+
if (age = lock.fetch("age"))
|
12
|
+
(ActiveSupport::Duration.parse(age).to_f * 1000) > configuration.locks_min_duration_ms
|
13
|
+
end
|
14
|
+
end.select(&configuration.locks_filter_proc)
|
15
|
+
.first(configuration.locks_limit)
|
15
16
|
|
16
17
|
if locks.present? && configuration.monitor_locks
|
17
18
|
configuration.notifier_class.call(locks)
|
@@ -19,7 +20,8 @@ module PgLocksMonitor
|
|
19
20
|
|
20
21
|
blocking = RailsPgExtras.blocking(in_format: :hash).select do |block|
|
21
22
|
(ActiveSupport::Duration.parse(block.fetch("blocking_duration")).to_f * 1000) > configuration.blocking_min_duration_ms
|
22
|
-
end
|
23
|
+
end.select(&configuration.blocking_filter_proc)
|
24
|
+
.first(configuration.locks_limit)
|
23
25
|
|
24
26
|
if blocking.present? && configuration.monitor_blocking
|
25
27
|
configuration.notifier_class.call(blocking)
|
@@ -13,6 +13,8 @@ module PgLocksMonitor
|
|
13
13
|
slack_webhook_url: nil,
|
14
14
|
slack_channel: nil,
|
15
15
|
notifier_class: PgLocksMonitor::DefaultNotifier,
|
16
|
+
locks_filter_proc: ->(lock) { true },
|
17
|
+
blocking_filter_proc: ->(lock) { true },
|
16
18
|
}
|
17
19
|
|
18
20
|
attr_accessor *DEFAULT.keys
|
@@ -43,6 +45,9 @@ PgLocksMonitor.configure do |config|
|
|
43
45
|
config.slack_channel = "#{DEFAULT[:slack_channel]}"
|
44
46
|
|
45
47
|
config.notifier_class = #{DEFAULT[:notifier_class]}
|
48
|
+
|
49
|
+
config.locks_filter_proc = ->(lock) { true }
|
50
|
+
config.blocking_filter_proc = ->(lock) { true }
|
46
51
|
end
|
47
52
|
CONFIG
|
48
53
|
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.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pawurb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-pg-extras
|
@@ -105,7 +105,6 @@ files:
|
|
105
105
|
- pg-locks-monitor.gemspec
|
106
106
|
- spec/configuration_spec.rb
|
107
107
|
- spec/default_notifier_spec.rb
|
108
|
-
- spec/smoke_spec.rb
|
109
108
|
- spec/spec_helper.rb
|
110
109
|
homepage: http://github.com/pawurb/pg-locks-monitor
|
111
110
|
licenses:
|
@@ -134,5 +133,4 @@ summary: Observe PostgreSQL database locks obtained by a Rails application.
|
|
134
133
|
test_files:
|
135
134
|
- spec/configuration_spec.rb
|
136
135
|
- spec/default_notifier_spec.rb
|
137
|
-
- spec/smoke_spec.rb
|
138
136
|
- spec/spec_helper.rb
|