pg_advisory_lock 0.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +69 -0
- data/.rubocop.yml +1 -1
- data/README.md +5 -1
- data/lib/pg_advisory_lock/base.rb +41 -23
- data/lib/pg_advisory_lock/version.rb +1 -1
- data/pg_advisory_lock.gemspec +1 -1
- metadata +5 -5
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a63a1943d6c02f12078939e1c72cad482972a9493ec408a0984308b329e269b
|
4
|
+
data.tar.gz: fcf0e101ff148fa73651759f0dbe4fe32cbaac1be1b5e9a13f26a7816c2d3a15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12b30ae854f94924bbced7bd831f4bbe89e682a50a0d01c299b7c3071c79e04e1d8cadadc5017574138d328104dc118f35f0fcee4e69889ea3ebb01bb0b8c8a8
|
7
|
+
data.tar.gz: 33ce47ca69b19de4985d8bf9d7517fecb5d9074bf3fe5ce53518b2b880ae6a7e1110f607a2160a6e8b8ee3928938603c75d53e957ee3f8e7dca1f5961b38682b
|
@@ -0,0 +1,69 @@
|
|
1
|
+
name: Tests
|
2
|
+
on:
|
3
|
+
pull_request:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
rubocop:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
name: Rubocop lint
|
12
|
+
env:
|
13
|
+
RAILS_VERSION: '~> 6.0'
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: 2.7
|
19
|
+
bundler-cache: true
|
20
|
+
- name: Run rubocop
|
21
|
+
run: |
|
22
|
+
gem install bundler
|
23
|
+
bundle install
|
24
|
+
bundle exec rake rubocop
|
25
|
+
test:
|
26
|
+
runs-on: ubuntu-latest
|
27
|
+
strategy:
|
28
|
+
matrix:
|
29
|
+
ruby: [ '2.7', '3.0', '3.1' ]
|
30
|
+
rails: [ '~> 6.0', '~> 7.0' ]
|
31
|
+
name: Tests with Ruby ${{ matrix.ruby }} Activerecord ${{ matrix.rails }}
|
32
|
+
services:
|
33
|
+
# Label used to access the service container
|
34
|
+
postgres:
|
35
|
+
# Docker Hub image
|
36
|
+
image: postgres
|
37
|
+
# Provide the password for postgres
|
38
|
+
env:
|
39
|
+
POSTGRES_DB: postgres_db
|
40
|
+
POSTGRES_PORT: 5432
|
41
|
+
POSTGRES_USER: postgres_user
|
42
|
+
POSTGRES_PASSWORD: postgres_password
|
43
|
+
ports:
|
44
|
+
- 5432:5432
|
45
|
+
# Set health checks to wait until postgres has started
|
46
|
+
options: >-
|
47
|
+
--health-cmd pg_isready
|
48
|
+
--health-interval 10s
|
49
|
+
--health-timeout 5s
|
50
|
+
--health-retries 5
|
51
|
+
env:
|
52
|
+
RAILS_VERSION: ${{ matrix.rails }}
|
53
|
+
POSTGRES_HOST: localhost
|
54
|
+
POSTGRES_DB: postgres_db
|
55
|
+
POSTGRES_PORT: 5432
|
56
|
+
POSTGRES_USER: postgres_user
|
57
|
+
POSTGRES_PASSWORD: postgres_password
|
58
|
+
steps:
|
59
|
+
- uses: actions/checkout@v2
|
60
|
+
- uses: ruby/setup-ruby@v1
|
61
|
+
with:
|
62
|
+
ruby-version: ${{ matrix.ruby }}
|
63
|
+
bundler-cache: true
|
64
|
+
- name: Run tests
|
65
|
+
run: |
|
66
|
+
gem install bundler
|
67
|
+
bundle install
|
68
|
+
cp -v spec/config/database.ci.yml spec/config/database.yml
|
69
|
+
bundle exec rake spec
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# PgAdvisoryLock
|
2
2
|
|
3
|
+

|
4
|
+
[](https://badge.fury.io/rb/pg_advisory_lock)
|
5
|
+
|
6
|
+
|
3
7
|
Postgresql Advisory Lock for ActiveRecord.
|
4
8
|
Allows to use mutex in applications that uses same database.
|
5
9
|
|
@@ -42,7 +46,7 @@ PgAdvisoryLock::Base.select_values 'SELECT id from users WHERE parent_name = ?',
|
|
42
46
|
## Development
|
43
47
|
|
44
48
|
After checking out the repo, run `bin/setup` to install dependencies.
|
45
|
-
Create `spec/config/database.yml` (look at `spec/config/database.
|
49
|
+
Create `spec/config/database.yml` (look at `spec/config/database.example.yml` for example).
|
46
50
|
You need to create test database, so run `psql -c 'CREATE DATABASE pg_advisory_lock_test;'`.
|
47
51
|
Then, run `rake spec` to run the tests.
|
48
52
|
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -23,6 +23,8 @@ module PgAdvisoryLock
|
|
23
23
|
# @param name [Symbol, String]
|
24
24
|
# @param value [Integer, Array<(Integer, Integer)>]
|
25
25
|
def register_lock(name, value)
|
26
|
+
raise ArgumentError, 'value must be integer or array of integers' unless int_or_array_of_ints?(value)
|
27
|
+
|
26
28
|
_lock_names[name.to_sym] = value
|
27
29
|
end
|
28
30
|
|
@@ -61,6 +63,16 @@ module PgAdvisoryLock
|
|
61
63
|
def try_lock(name, transaction: true, shared: false, id: nil, &block)
|
62
64
|
new(name, transaction: transaction, shared: shared, id: id, wait: false).lock(&block)
|
63
65
|
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def int_or_array_of_ints?(value)
|
70
|
+
return true if value.is_a?(Integer)
|
71
|
+
|
72
|
+
return true if value.is_a?(Array) && value.all? { |i| i.is_a?(Integer) }
|
73
|
+
|
74
|
+
false
|
75
|
+
end
|
64
76
|
end
|
65
77
|
|
66
78
|
# @param name [Symbol, String] - lock name (will be transformed to number).
|
@@ -84,8 +96,8 @@ module PgAdvisoryLock
|
|
84
96
|
# @return yield
|
85
97
|
def lock(&block)
|
86
98
|
with_logger do
|
87
|
-
|
88
|
-
advisory_lock(
|
99
|
+
lock_args = build_lock_args
|
100
|
+
advisory_lock(lock_args, &block)
|
89
101
|
end
|
90
102
|
end
|
91
103
|
|
@@ -99,62 +111,68 @@ module PgAdvisoryLock
|
|
99
111
|
logger.tagged(self.class.to_s, name.inspect) { yield }
|
100
112
|
end
|
101
113
|
|
102
|
-
def advisory_lock(
|
114
|
+
def advisory_lock(lock_args, &block)
|
103
115
|
if transaction
|
104
|
-
transaction_lock(
|
116
|
+
transaction_lock(lock_args, &block)
|
105
117
|
else
|
106
|
-
non_transaction_lock(
|
118
|
+
non_transaction_lock(lock_args, &block)
|
107
119
|
end
|
108
120
|
end
|
109
121
|
|
110
|
-
def transaction_lock(
|
122
|
+
def transaction_lock(lock_args)
|
111
123
|
raise ArgumentError, 'block required when not within transaction' if !block_given? && !sql_caller_class.transaction_open?
|
112
124
|
|
113
|
-
return perform_lock(
|
125
|
+
return perform_lock(lock_args) unless block_given?
|
114
126
|
|
115
127
|
sql_caller_class.transaction do
|
116
|
-
perform_lock(
|
128
|
+
perform_lock(lock_args)
|
117
129
|
yield
|
118
130
|
end
|
119
131
|
end
|
120
132
|
|
121
|
-
def non_transaction_lock(
|
133
|
+
def non_transaction_lock(lock_args)
|
122
134
|
raise ArgumentError, 'block required on transaction: false' unless block_given?
|
123
135
|
|
124
136
|
begin
|
125
|
-
perform_lock(
|
137
|
+
perform_lock(lock_args)
|
126
138
|
yield
|
127
139
|
ensure
|
128
|
-
perform_unlock(
|
140
|
+
perform_unlock(lock_args)
|
129
141
|
end
|
130
142
|
end
|
131
143
|
|
132
|
-
def perform_lock(
|
144
|
+
def perform_lock(lock_args)
|
133
145
|
function_name = "pg#{'_try' unless wait}_advisory#{'_xact' if transaction}_lock#{'_shared' if shared}"
|
134
146
|
|
135
147
|
if wait
|
136
|
-
sql_caller_class.execute("SELECT #{function_name}(#{
|
148
|
+
sql_caller_class.execute("SELECT #{function_name}(#{lock_args})")
|
137
149
|
else
|
138
|
-
result = sql_caller_class.select_value("SELECT #{function_name}(#{
|
139
|
-
raise LockNotObtained, "#{self.class} can't obtain lock (#{name}, #{id})" unless result
|
150
|
+
result = sql_caller_class.select_value("SELECT #{function_name}(#{lock_args})")
|
151
|
+
raise LockNotObtained, "#{self.class} can't obtain lock (#{name}, #{id.inspect})" unless result
|
140
152
|
end
|
141
153
|
end
|
142
154
|
|
143
|
-
def perform_unlock(
|
144
|
-
sql_caller_class.select_value("SELECT pg_advisory_unlock#{'_shared' if shared}(#{
|
155
|
+
def perform_unlock(lock_args)
|
156
|
+
sql_caller_class.select_value("SELECT pg_advisory_unlock#{'_shared' if shared}(#{lock_args})")
|
145
157
|
end
|
146
158
|
|
147
159
|
# Converts lock name to number, because pg advisory lock functions accept only bigint numbers.
|
148
160
|
# @return [String] lock number or two numbers delimited by comma.
|
149
|
-
def
|
150
|
-
|
161
|
+
def build_lock_args
|
162
|
+
lock_args = _lock_names.fetch(name) do
|
151
163
|
raise ArgumentError, "lock name #{name.inspect} is invalid, see #{self.class}::NAMES"
|
152
164
|
end
|
153
|
-
|
154
|
-
|
155
|
-
|
165
|
+
lock_args = Array.wrap(lock_args)
|
166
|
+
if id.present?
|
167
|
+
if id.is_a?(Integer)
|
168
|
+
lock_args.push(id)
|
169
|
+
else
|
170
|
+
lock_args.push("hashtext(#{sql_caller_class.connection.quote(id.to_s)})")
|
171
|
+
end
|
172
|
+
end
|
173
|
+
raise ArgumentError, "can't use lock name #{name.inspect} with id" if lock_args.size > 2
|
156
174
|
|
157
|
-
|
175
|
+
lock_args.join(', ')
|
158
176
|
end
|
159
177
|
|
160
178
|
def sql_caller_class
|
data/pg_advisory_lock.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_advisory_lock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Talakevich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.2.2
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.2.2
|
55
55
|
description: Postgresql Advisory Lock for ActiveRecord.
|
56
56
|
email:
|
57
57
|
- senid231@gmail.com
|
@@ -59,10 +59,10 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
+
- ".github/workflows/tests.yml"
|
62
63
|
- ".gitignore"
|
63
64
|
- ".rspec"
|
64
65
|
- ".rubocop.yml"
|
65
|
-
- ".travis.yml"
|
66
66
|
- CODE_OF_CONDUCT.md
|
67
67
|
- Gemfile
|
68
68
|
- LICENSE.txt
|