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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f4f49429d7f217072b2927e3f33876f0841caf8d027725bd7981eed010e1a37
4
- data.tar.gz: 4bd6514b91d8dad257d575b7147a41f8faa5006dd398a7d98d340a2612c0a4f8
3
+ metadata.gz: 8a63a1943d6c02f12078939e1c72cad482972a9493ec408a0984308b329e269b
4
+ data.tar.gz: fcf0e101ff148fa73651759f0dbe4fe32cbaac1be1b5e9a13f26a7816c2d3a15
5
5
  SHA512:
6
- metadata.gz: 92a9005c04a0b898ec8489027bb065ecf713ec75cc83fe0e7d0c721740874463bd80ccad2919a5be780f7b0cc5d6626593b3e5b844e9eb76b1f33851b41a6f9a
7
- data.tar.gz: 8199402c1fd8ab0b8c72df92698f94912a81bc91a4af64ba2edd9385d68d9dcf3e0439ba72ce23424be5e4db3738eade36ebd2127ee6a2372539452180e5c065
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
@@ -1,6 +1,6 @@
1
1
  AllCops:
2
2
  DisplayCopNames: true
3
- TargetRubyVersion: 2.5
3
+ TargetRubyVersion: 2.7
4
4
  Exclude:
5
5
  - vendor/**/*
6
6
  - tmp/**/*
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # PgAdvisoryLock
2
2
 
3
+ ![tests](https://github.com/didww/pg_advisory_lock/actions/workflows/tests.yml/badge.svg)
4
+ [![Gem Version](https://badge.fury.io/rb/pg_advisory_lock.svg)](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.travis.yml` for example).
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
- lock_number = name_to_number
88
- advisory_lock(lock_number, &block)
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(lock_number, &block)
114
+ def advisory_lock(lock_args, &block)
103
115
  if transaction
104
- transaction_lock(lock_number, &block)
116
+ transaction_lock(lock_args, &block)
105
117
  else
106
- non_transaction_lock(lock_number, &block)
118
+ non_transaction_lock(lock_args, &block)
107
119
  end
108
120
  end
109
121
 
110
- def transaction_lock(lock_number)
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(lock_number) unless block_given?
125
+ return perform_lock(lock_args) unless block_given?
114
126
 
115
127
  sql_caller_class.transaction do
116
- perform_lock(lock_number)
128
+ perform_lock(lock_args)
117
129
  yield
118
130
  end
119
131
  end
120
132
 
121
- def non_transaction_lock(lock_number)
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(lock_number)
137
+ perform_lock(lock_args)
126
138
  yield
127
139
  ensure
128
- perform_unlock(lock_number)
140
+ perform_unlock(lock_args)
129
141
  end
130
142
  end
131
143
 
132
- def perform_lock(lock_number)
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}(#{lock_number})")
148
+ sql_caller_class.execute("SELECT #{function_name}(#{lock_args})")
137
149
  else
138
- result = sql_caller_class.select_value("SELECT #{function_name}(#{lock_number})")
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(lock_number)
144
- sql_caller_class.select_value("SELECT pg_advisory_unlock#{'_shared' if shared}(#{lock_number})")
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 name_to_number
150
- lock_number = _lock_names.fetch(name) do
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
- lock_number = Array.wrap(lock_number)
154
- lock_number.push(id) if id.present?
155
- raise ArgumentError, "can't use lock name #{name.inspect} with id" if lock_number.size > 2
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
- lock_number.join(', ')
175
+ lock_args.join(', ')
158
176
  end
159
177
 
160
178
  def sql_caller_class
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgAdvisoryLock
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -29,5 +29,5 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_dependency 'activerecord'
31
31
  spec.add_dependency 'activesupport'
32
- spec.add_dependency 'pg_sql_caller'
32
+ spec.add_dependency 'pg_sql_caller', '>= 0.2.2'
33
33
  end
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.3.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: 2022-12-13 00:00:00.000000000 Z
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: '0'
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: '0'
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
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.5.5
6
- before_install: gem install bundler -v 2.1.4