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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9127ef19c571c1eda59fa9962c694c6a416f4d2875d6660091cb72479e09d98
4
- data.tar.gz: 56a1e90355cad04a9834e2a6eafeb76c9633596a9e786ce639af838757c1e87e
3
+ metadata.gz: f95c5c531f0c74143c8fa74417344e1e5b3e400b06f910528541a69ee89f0aaa
4
+ data.tar.gz: fd704b6c9562678541aaaa1cbd98ab997281a529cbfba35f0235466000de0599
5
5
  SHA512:
6
- metadata.gz: e9d94a09139dd75cfc5672aa863e288ed6654fa4953cf00dbbd62a6ec63e63feb60c99208f0aa0dda2ce01ccadd9cd92b3b58d05200be53bb75579e44bf85f9d
7
- data.tar.gz: 6f57a40ce88babd6fcdd176371462c4b6fa40c248da5472ae1cfdcdad685bc17f0a5a3bbf0f152e7de50d48dbc84a18a8443d1ce6ce90bf112278b506e81a839
6
+ metadata.gz: 0c467b40b8114d8ca11a5aa89b91e5d0d3637a287d041e8f2d383f0465798d38e8d20f0248408fa4dbce90ef6eb74ef3bb022f78815fb3d676c07272279892b6
7
+ data.tar.gz: 9fdcecb73e646f43a2143db60a12d01f0cc766ed9ee633a63ca1254cce82c7de5688c1594c518b7adf269aed67a77d8da2c4e25a363372beaf19fa9d91b253c5
@@ -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 rspec spec/
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 rspec spec/
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 rspec spec/
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 rspec spec/
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 rspec spec/
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
- - `notify_locks` - observe database locks even if they don't conflict with a different SQL query
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
- - `notify_blocking` - observe database locks which cause other SQL query to wait from them to release
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 configuring a recurring invocation of the `snapshot!` method, it's recommended to first manually trigger the notification to test the configured channels.
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:
@@ -6,12 +6,13 @@ require "pg"
6
6
  module PgLocksMonitor
7
7
  def self.snapshot!
8
8
  locks = RailsPgExtras.locks(
9
- in_format: :hash, args: {
10
- limit: configuration.locks_limit,
11
- },
9
+ in_format: :hash,
12
10
  ).select do |lock|
13
- (ActiveSupport::Duration.parse(lock.fetch("age")).to_f * 1000) > configuration.locks_min_duration_ms
14
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgLocksMonitor
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  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.1.1
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-08-27 00:00:00.000000000 Z
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
data/spec/smoke_spec.rb DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- describe PgLocksMonitor do
6
- end