pg-locks-monitor 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c15914dcf0512070ba0f629249a9743c04aad078d6f7dcd23a96acda248284f4
4
- data.tar.gz: bbf242ededb3f441489be230e5e013d362c85b0964f34667a89b9ffe12589aa0
3
+ metadata.gz: a3bd2f4561c83a6d10a0120670bb89f8140f01f3afad7434fbea969e113cc542
4
+ data.tar.gz: 2fdb6e38890f1b085a32e72fee4d32eeb4e77e6a1f865737b2f3541d76d333ad
5
5
  SHA512:
6
- metadata.gz: c17edd2b3419837fd7e6f909ba8f7bf2878a28df97f0f80f0a2a12e5534188895d44f3897372445267ff8d524f1b1825d09c4a77b29ad8a991dedd4b71ba4dfb
7
- data.tar.gz: a876c3894b680a8cc20bb29070d1e9dc8af6678cd09ed6293501ede52eecae134ddfb48b37d7441676f9a9f4499f8b0f2eba46108b963da19ebf8f6ef78992ee
6
+ metadata.gz: 1396e94b66ae62db3ee552855cfe8b2e7d10c5efdf87f323bc889c8fb17530cf9076e6239f2dc9713907f28ddbb5de602f4baa507b38621419534be545be83c6
7
+ data.tar.gz: a9bafef4918812b931737a0096cd2096181512e6eb5b35585b4e5caf50d7230f1dca4b8b2a37eeac7b521968577cf915cd97bff1f79b757dc909b5d1a4eb4f18
@@ -48,7 +48,15 @@ jobs:
48
48
  docker run --env POSTGRES_USER=postgres \
49
49
  --env POSTGRES_DB=pg-locks-monitor-test \
50
50
  --env POSTGRES_PASSWORD=secret \
51
- -d -p 5436:5432 postgres:15.1-alpine \
51
+ -d -p 5436:5432 postgres:15.8-alpine \
52
+ postgres -c shared_preload_libraries=pg_stat_statements
53
+ sleep 15
54
+ - name: Run PostgreSQL 16
55
+ run: |
56
+ docker run --env POSTGRES_USER=postgres \
57
+ --env POSTGRES_DB=pg-locks-monitor-test \
58
+ --env POSTGRES_PASSWORD=secret \
59
+ -d -p 5437:5432 postgres:16.4-alpine \
52
60
  postgres -c shared_preload_libraries=pg_stat_statements
53
61
  sleep 15
54
62
  - name: Set up Ruby ${{ matrix.ruby-version }}
@@ -73,17 +81,7 @@ jobs:
73
81
  POSTGRES_PASSWORD: secret
74
82
  DATABASE_URL: postgresql://postgres:secret@localhost:5432/pg-locks-monitor-test
75
83
  run: |
76
- bundle exec rspec spec/
77
- - name: Run tests for PG 11
78
- env:
79
- PG_VERSION: 11
80
- POSTGRES_HOST: localhost
81
- POSTGRES_USER: postgres
82
- POSTGRES_DB: pg-locks-monitor-test
83
- POSTGRES_PASSWORD: secret
84
- DATABASE_URL: postgresql://postgres:secret@localhost:5432/pg-locks-monitor-test
85
- run: |
86
- bundle exec rake test_all
84
+ bundle exec rspec spec
87
85
  - name: Run tests for PG 12
88
86
  env:
89
87
  PG_VERSION: 12
@@ -93,7 +91,7 @@ jobs:
93
91
  POSTGRES_PASSWORD: secret
94
92
  DATABASE_URL: postgresql://postgres:secret@localhost:5433/pg-locks-monitor-test
95
93
  run: |
96
- bundle exec rake test_all
94
+ bundle exec rspec spec
97
95
  - name: Run tests for PG 13
98
96
  env:
99
97
  PG_VERSION: 13
@@ -103,7 +101,7 @@ jobs:
103
101
  POSTGRES_PASSWORD: secret
104
102
  DATABASE_URL: postgresql://postgres:secret@localhost:5434/pg-locks-monitor-test
105
103
  run: |
106
- bundle exec rake test_all
104
+ bundle exec rspec spec
107
105
  - name: Run tests for PG 14
108
106
  env:
109
107
  PG_VERSION: 14
@@ -113,7 +111,7 @@ jobs:
113
111
  POSTGRES_PASSWORD: secret
114
112
  DATABASE_URL: postgresql://postgres:secret@localhost:5435/pg-locks-monitor-test
115
113
  run: |
116
- bundle exec rake test_all
114
+ bundle exec rspec spec
117
115
  - name: Run tests for PG 15
118
116
  env:
119
117
  PG_VERSION: 15
@@ -123,5 +121,17 @@ jobs:
123
121
  POSTGRES_PASSWORD: secret
124
122
  DATABASE_URL: postgresql://postgres:secret@localhost:5436/pg-locks-monitor-test
125
123
  run: |
126
- bundle exec rake test_all
124
+ bundle exec rspec spec
125
+ - name: Run tests for PG 16
126
+ env:
127
+ PG_VERSION: 15
128
+ POSTGRES_HOST: localhost
129
+ POSTGRES_USER: postgres
130
+ POSTGRES_DB: pg-locks-monitor-test
131
+ POSTGRES_PASSWORD: secret
132
+ DATABASE_URL: postgresql://postgres:secret@localhost:5437/pg-locks-monitor-test
133
+ run: |
134
+ bundle exec rspec spec
135
+
136
+
127
137
 
data/Rakefile CHANGED
@@ -5,5 +5,5 @@ RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  desc "Test all PG versions"
7
7
  task :test_all do
8
- system("PG_VERSION=11 bundle exec rspec spec/ && PG_VERSION=12 bundle exec rspec spec/ && PG_VERSION=13 bundle exec rspec spec/ && PG_VERSION=14 bundle exec rspec spec/")
8
+ system("PG_VERSION=11 bundle exec rspec spec && PG_VERSION=12 bundle exec rspec spec && PG_VERSION=13 bundle exec rspec spec && PG_VERSION=14 bundle exec rspec spec && PG_VERSION=16 bundle exec rspec spec && PG_VERSION=16 bundle exec rspec spec")
9
9
  end
@@ -1,5 +1,3 @@
1
- version: '3'
2
-
3
1
  services:
4
2
  postgres11:
5
3
  image: postgres:11.16-alpine
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "uri"
4
4
  require "pg"
5
+ require "ruby-pg-extras"
5
6
 
6
7
  module PgLocksMonitor
7
8
  def self.snapshot!
@@ -9,23 +10,28 @@ module PgLocksMonitor
9
10
  in_format: :hash,
10
11
  ).select do |lock|
11
12
  if (age = lock.fetch("age"))
12
- (ActiveSupport::Duration.parse(age).to_f * 1000) > configuration.locks_min_duration_ms
13
+ DurationHelper.parse_to_ms(age) > configuration.locks_min_duration_ms
13
14
  end
14
15
  end.select(&configuration.locks_filter_proc)
15
16
  .first(configuration.locks_limit)
16
17
 
17
- if locks.present? && configuration.monitor_locks
18
+ if locks.count > 0 && configuration.monitor_locks
18
19
  configuration.notifier_class.call(locks)
19
20
  end
20
21
 
21
22
  blocking = RubyPgExtras.blocking(in_format: :hash).select do |block|
22
- (ActiveSupport::Duration.parse(block.fetch("blocking_duration")).to_f * 1000) > configuration.blocking_min_duration_ms
23
+ DurationHelper.parse_to_ms(block.fetch("blocking_duration")) > configuration.blocking_min_duration_ms
23
24
  end.select(&configuration.blocking_filter_proc)
24
25
  .first(configuration.locks_limit)
25
26
 
26
- if blocking.present? && configuration.monitor_blocking
27
+ if blocking.count > 0 && configuration.monitor_blocking
27
28
  configuration.notifier_class.call(blocking)
28
29
  end
30
+
31
+ {
32
+ locks: locks,
33
+ blocking: blocking,
34
+ }
29
35
  end
30
36
 
31
37
  def self.configuration
@@ -35,6 +41,22 @@ module PgLocksMonitor
35
41
  def self.configure
36
42
  yield(configuration)
37
43
  end
44
+
45
+ class DurationHelper
46
+ require "date"
47
+
48
+ def self.parse_to_ms(duration_str)
49
+ time = DateTime.strptime(duration_str, "%H:%M:%S.%N")
50
+ hours = time.hour
51
+ minutes = time.minute
52
+ seconds = time.second
53
+ nanoseconds = time.second_fraction * (10 ** 9)
54
+
55
+ total_ms = (hours * 3600 * 1000) + (minutes * 60 * 1000) + (seconds * 1000) + (nanoseconds / 1_000_000).to_i
56
+
57
+ total_ms
58
+ end
59
+ end
38
60
  end
39
61
 
40
62
  require "pg_locks_monitor/default_notifier"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgLocksMonitor
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  end
@@ -3,14 +3,6 @@
3
3
  require "spec_helper"
4
4
 
5
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
6
  it "requires correct config if Slack notifications enabled" do
15
7
  expect {
16
8
  PgLocksMonitor::DefaultNotifier.call({})
@@ -24,14 +16,26 @@ describe PgLocksMonitor::DefaultNotifier do
24
16
  }.to raise_error(RuntimeError)
25
17
  end
26
18
 
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"
19
+ describe "Slack notification enabled" do
20
+ before do
21
+ PgLocksMonitor.configure do |config|
22
+ config.notify_slack = true
23
+ config.slack_webhook_url = "https://hooks.slack.com/services/123456789/123456789/123456789"
24
+ config.slack_channel = "pg-locks-monitor"
25
+ end
32
26
  end
33
27
 
34
- expect_any_instance_of(Slack::Notifier).to receive(:ping)
35
- PgLocksMonitor::DefaultNotifier.call({ locks: "data" })
28
+ after do
29
+ PgLocksMonitor.configure do |config|
30
+ config.notify_slack = false
31
+ config.slack_webhook_url = nil
32
+ config.slack_channel = nil
33
+ end
34
+ end
35
+
36
+ it "sends the Slack notification" do
37
+ expect_any_instance_of(Slack::Notifier).to receive(:ping)
38
+ PgLocksMonitor::DefaultNotifier.call({ locks: "data" })
39
+ end
36
40
  end
37
41
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe PgLocksMonitor do
6
+ def spawn_update
7
+ Thread.new do
8
+ conn = PG.connect(ENV["DATABASE_URL"])
9
+ conn.exec("
10
+ BEGIN;
11
+ UPDATE pg_locks_monitor_users SET name = 'Updated';
12
+ select pg_sleep(2);
13
+ COMMIT;
14
+ ")
15
+ end
16
+ end
17
+
18
+ describe "snapshot!" do
19
+ it "works" do
20
+ expect {
21
+ PgLocksMonitor.snapshot!
22
+ }.not_to raise_error
23
+ end
24
+
25
+ it "returns correct locks data" do
26
+ spawn_update
27
+ spawn_update
28
+ sleep 1
29
+
30
+ result = PgLocksMonitor.snapshot!
31
+ expect(result.fetch(:locks).count).to eq(5)
32
+ expect(result.fetch(:blocking).count).to eq(1)
33
+ end
34
+ end
35
+ end
data/spec/spec_helper.rb CHANGED
@@ -14,8 +14,35 @@ port = if pg_version == "11"
14
14
  "5434"
15
15
  elsif pg_version == "14"
16
16
  "5435"
17
+ elsif pg_version == "15"
18
+ "5436"
19
+ elsif pg_version == "16"
20
+ "5437"
17
21
  else
18
22
  "5432"
19
23
  end
20
24
 
21
25
  ENV["DATABASE_URL"] ||= "postgresql://postgres:secret@localhost:#{port}/pg-locks-monitor-test"
26
+
27
+ RSpec.configure do |config|
28
+ Rails = {}
29
+
30
+ config.before(:each) do
31
+ # Mock Rails and its logger
32
+ logger_double = double("Logger")
33
+ allow(logger_double).to receive(:info)
34
+ allow(Rails).to receive(:logger).and_return(logger_double)
35
+ end
36
+
37
+ config.before(:suite) do
38
+ conn = RubyPgExtras.connection
39
+ conn.exec("CREATE TABLE IF NOT EXISTS pg_locks_monitor_users (id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL);")
40
+ conn.exec("INSERT INTO pg_locks_monitor_users (name) VALUES ('Alice');")
41
+ conn.exec("INSERT INTO pg_locks_monitor_users (name) VALUES ('Bob');")
42
+ end
43
+
44
+ config.after(:suite) do
45
+ conn = RubyPgExtras.connection
46
+ conn.exec("DROP TABLE IF EXISTS pg_locks_monitor_users;")
47
+ end
48
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg-locks-monitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
@@ -105,6 +105,7 @@ 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
108
109
  - spec/spec_helper.rb
109
110
  homepage: http://github.com/pawurb/pg-locks-monitor
110
111
  licenses:
@@ -133,4 +134,5 @@ summary: Observe PostgreSQL database locks obtained by a Rails application.
133
134
  test_files:
134
135
  - spec/configuration_spec.rb
135
136
  - spec/default_notifier_spec.rb
137
+ - spec/smoke_spec.rb
136
138
  - spec/spec_helper.rb