rails_soft_lock 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/README.md +76 -19
- data/lib/rails_soft_lock/configuration.rb +18 -34
- data/lib/rails_soft_lock/lock_object.rb +1 -1
- data/lib/rails_soft_lock/model_extensions.rb +8 -20
- data/lib/rails_soft_lock/redis_config.rb +68 -0
- data/lib/rails_soft_lock/version.rb +1 -1
- data/lib/rails_soft_lock.rb +31 -2
- data/lib/tasks/rails_soft_lock.rake +2 -2
- data/sig/rails_soft_lock.rbs +15 -0
- metadata +5 -9
- data/sig/rails_soft_lock/configuration.rbs +0 -50
- data/sig/rails_soft_lock/lock_object.rbs +0 -41
- data/sig/rails_soft_lock/model_extensions.rbs +0 -6
- data/sig/rails_soft_lock/railtie.rbs +0 -7
- data/sig/rails_soft_lock/redis_adapter.rbs +0 -29
- data/sig/rails_soft_lock/version.rbs +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f6443555d20169a04a8c16dbe970b56fca4f3befe6a840bea0f1385e6783524
|
4
|
+
data.tar.gz: '08382ac46d6a3fe067e4899721da2b217ccd74065bf76061886509694ab6c85a'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1bd7a8346ccfc3e17b12f632847627bd313ae27bb2cc641e437524f932d708cd93f2edcf9e7694a8e5b9df81efab8b1c76006d67fb7508fe5ad5e8df48797d6
|
7
|
+
data.tar.gz: 892296a9f41bf10c6c61eca479b42bd6f79892cb2dfbe9762f978080b634630b34f97178759259f0efa20db7bbed25ac059403a83e44cf3febcc3175932f6fd6
|
data/README.md
CHANGED
@@ -1,21 +1,49 @@
|
|
1
|
-
# RailsSoftLock
|
1
|
+
# RailsSoftLock – Group Locking for ApplicationRecord by Attribute
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
it
|
6
|
-
|
7
|
-
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
The RailsSoftLock gem provides group-level locking for Rails ApplicationRecord objects based on a shared attribute. Instead of individually locking each database record (which can be expensive and complex), it creates and manages a single in-memory lock for the entire group via the attribute. This reduces database contention while maintaining thread safety.
|
6
|
+
|
7
|
+
### Key Features
|
8
|
+
|
9
|
+
Lightweight Group Locking:
|
10
|
+
|
11
|
+
Locks records sharing the same attribute value via an in-memory database (e.g., Redis, NATS).
|
12
|
+
|
13
|
+
Avoids expensive row-level locks in your primary database.
|
14
|
+
|
15
|
+
ActiveRecord Integration:
|
16
|
+
|
17
|
+
Extends Rails’ built-in locking mechanisms with adapters for in-memory stores.
|
18
|
+
|
19
|
+
Supports scoped uniqueness (e.g., lock groups by account_id + category).
|
20
|
+
|
21
|
+
Beyond Locking:
|
22
|
+
|
23
|
+
Can also mark/tag groups of records (e.g., flag all records with project_id=123 as "favorites").
|
24
|
+
|
25
|
+
Useful for batch operations or state management (e.g., "processing", "archived").
|
26
|
+
|
27
|
+
### Current Status
|
28
|
+
|
29
|
+
Active Development: New features and optimizations in progress.
|
30
|
+
|
31
|
+
Available Adapters: Redis and Redis-compatible databases (e.g., Valkey).
|
8
32
|
|
9
33
|
## Installation
|
10
34
|
|
11
35
|
Install the gem and add to the application's Gemfile:
|
12
36
|
|
13
37
|
```bash
|
38
|
+
# Stable version
|
39
|
+
gem "rails_soft_lock"
|
40
|
+
# Last version
|
14
41
|
gem "rails_soft_lock", git: "https://github.com/sergey-arkhipov/rails_soft_lock.git"
|
15
42
|
|
16
43
|
```
|
17
44
|
|
18
|
-
|
45
|
+
When using Redis as an adapter and having REDIS_URL in config/redis.yml it is not necessary to install the initializer.
|
46
|
+
Only when need to replace some standard settings, User model, for example, or adapter.
|
19
47
|
|
20
48
|
```bash
|
21
49
|
bundle install
|
@@ -57,6 +85,19 @@ Gem use ConnectionPool inside for safety connect to Redis adapter (now inplement
|
|
57
85
|
|
58
86
|
Gem assumes that the User model is used to determine the user who sets the lock.
|
59
87
|
|
88
|
+
Another model for setting the attribute of the blocking user can be specified in the configuration.
|
89
|
+
The model ID is used for blocking.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
RailsSoftLock.configure do |config|
|
93
|
+
...
|
94
|
+
# (Optional) Model class for locked_by lookups
|
95
|
+
config.locked_by_class = "User"
|
96
|
+
|
97
|
+
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
60
101
|
Model < ApplicationRecord should include `RailsSoftLock::ModelExtensions`
|
61
102
|
and `acts_as_locked_by` with `acts_as_locked_scope` should be set, for example
|
62
103
|
|
@@ -64,26 +105,42 @@ and `acts_as_locked_by` with `acts_as_locked_scope` should be set, for example
|
|
64
105
|
class Article < ApplicationRecord
|
65
106
|
include RailsSoftLock::ModelExtensions
|
66
107
|
|
67
|
-
acts_as_locked_by
|
68
|
-
|
108
|
+
acts_as_locked_by: attribyte, scope: -> { 'scope_result'}
|
109
|
+
|
69
110
|
|
70
111
|
```
|
71
112
|
|
72
113
|
See `spec/rails_soft_lock/model_extensions_spec.rb for implemented methods`
|
73
114
|
|
74
|
-
###
|
115
|
+
### Understanding the lock_or_find Method
|
116
|
+
|
117
|
+
The lock_or_find method returns a hash with the following structure:
|
118
|
+
ruby
|
119
|
+
|
120
|
+
{ has_locked: false, locked_by: user.id }
|
121
|
+
|
122
|
+
Key Points:
|
123
|
+
|
124
|
+
has_locked: false indicates that the object was not locked prior to this operation.
|
125
|
+
|
126
|
+
Note: This does not refer to the success/failure of the lock attempt itself.
|
127
|
+
|
128
|
+
How locking works:
|
129
|
+
|
130
|
+
Since this is an in-memory database designed for fast access, the method:
|
131
|
+
|
132
|
+
Sets the lock (if no lock existed).
|
133
|
+
|
134
|
+
Reports (has_locked: false) that no prior lock was present.
|
135
|
+
|
136
|
+
Returns the ID of the user who now holds the lock.
|
75
137
|
|
76
|
-
|
138
|
+
If the object was already locked, it returns:
|
139
|
+
ruby
|
77
140
|
|
78
|
-
|
79
|
-
`has_locked: false, locked_by: user.id`
|
141
|
+
{ has_locked: true, locked_by: <existing_lock_user_id> }
|
80
142
|
|
81
|
-
|
82
|
-
Not to be confused with the result of executing the lock itself.
|
83
|
-
Since this is an in-memory base and the goal is quick and easy access, the method sets the lock,
|
84
|
-
reports that there was no lock before, and returns the user of the lock.
|
85
|
-
If there was a lock, true is returned and the user of this current lock.
|
86
|
-
The lock itself is not changed.
|
143
|
+
In this case, the lock remains unchanged (no new lock is set).
|
87
144
|
|
88
145
|
## Development
|
89
146
|
|
@@ -7,21 +7,31 @@ module RailsSoftLock
|
|
7
7
|
# List of supported adapters.
|
8
8
|
VALID_ADAPTERS = %i[redis nats memcached].freeze
|
9
9
|
attr_reader :adapter
|
10
|
-
|
10
|
+
# :reek:Attribute
|
11
|
+
attr_accessor :adapter_options
|
12
|
+
# :reek:Attribute
|
13
|
+
attr_writer :locked_by_class
|
11
14
|
|
12
15
|
def initialize
|
13
16
|
@adapter = :redis # Default adapter
|
14
|
-
@adapter_options
|
15
|
-
@
|
16
|
-
@acts_as_locked_scope = -> { "default" }
|
17
|
+
@adapter_options ||= RedisConfig.default_adapter_options # Default adapter options
|
18
|
+
@locked_by_class = locked_by_class || "User"
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
20
|
-
|
21
|
+
def acts_as_locked_by(attribute = :lock_attribute, scope: -> { "none" })
|
22
|
+
@acts_as_locked_options = { by: attribute, scope: scope }
|
21
23
|
end
|
22
24
|
|
23
|
-
def
|
24
|
-
|
25
|
+
def acts_as_locked_attribute
|
26
|
+
@acts_as_locked_options&.[](:by) || :lock_attribute
|
27
|
+
end
|
28
|
+
|
29
|
+
def acts_as_locked_scope
|
30
|
+
@acts_as_locked_options&.[](:scope)&.call || "none"
|
31
|
+
end
|
32
|
+
|
33
|
+
def locked_by_class
|
34
|
+
@locked_by_class.is_a?(String) ? @locked_by_class.constantize : @locked_by_class
|
25
35
|
end
|
26
36
|
|
27
37
|
# Sets the adapter and validates it.
|
@@ -33,30 +43,4 @@ module RailsSoftLock
|
|
33
43
|
@adapter = value
|
34
44
|
end
|
35
45
|
end
|
36
|
-
|
37
|
-
class << self
|
38
|
-
# Configures the RailsSoftLock gem with a block.
|
39
|
-
# @yield [config] Yields the configuration object to the block.
|
40
|
-
# @return [void]
|
41
|
-
def configure
|
42
|
-
@configuration ||= Configuration.new
|
43
|
-
if block_given?
|
44
|
-
yield(@configuration)
|
45
|
-
else
|
46
|
-
warn "[RailsSoftLock] No configuration block provided in `configure`"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns the current configuration instance.
|
51
|
-
# @return [Configuration] The configuration object.
|
52
|
-
def configuration
|
53
|
-
@configuration ||= Configuration.new
|
54
|
-
end
|
55
|
-
|
56
|
-
# Resets the configuration (useful for testing).
|
57
|
-
# @return [void]
|
58
|
-
def reset_configuration
|
59
|
-
@configuration = nil
|
60
|
-
end
|
61
|
-
end
|
62
46
|
end
|
@@ -9,7 +9,7 @@ module RailsSoftLock
|
|
9
9
|
# - object_key: The identifier of the lock instance, typically a unique database record ID
|
10
10
|
# - object_value: The identifier of the locker that locked the record
|
11
11
|
class LockObject
|
12
|
-
#
|
12
|
+
# Attach adapter based on config
|
13
13
|
def self.adapter
|
14
14
|
case RailsSoftLock.configuration.adapter
|
15
15
|
when :redis
|
@@ -3,25 +3,13 @@
|
|
3
3
|
# lib/rails_soft_lock/model_extensions.rb
|
4
4
|
|
5
5
|
module RailsSoftLock
|
6
|
-
#
|
6
|
+
# Extend model and give methods from gem
|
7
7
|
module ModelExtensions
|
8
8
|
extend ActiveSupport::Concern
|
9
|
-
|
10
9
|
class_methods do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def current_locked_attribute
|
16
|
-
RailsSoftLock.configuration[:acts_as_locked_by]
|
17
|
-
end
|
18
|
-
|
19
|
-
def acts_as_locked_scope(attribute = nil)
|
20
|
-
RailsSoftLock.configuration[:acts_as_locked_scope] = attribute || -> { "default" }
|
21
|
-
end
|
22
|
-
|
23
|
-
def current_locked_scope
|
24
|
-
RailsSoftLock.configuration[:acts_as_locked_scope]
|
10
|
+
# :reek:UtilityFunction
|
11
|
+
def acts_as_locked_by(attribute = :lock_attribute, scope: -> { "none" })
|
12
|
+
RailsSoftLock.configuration.acts_as_locked_by(attribute, scope: scope)
|
25
13
|
end
|
26
14
|
|
27
15
|
def all_locks
|
@@ -33,8 +21,8 @@ module RailsSoftLock
|
|
33
21
|
end
|
34
22
|
|
35
23
|
def object_name
|
36
|
-
scope =
|
37
|
-
"#{name}
|
24
|
+
scope = RailsSoftLock.configuration.acts_as_locked_scope
|
25
|
+
"#{name}::#{scope}"
|
38
26
|
end
|
39
27
|
end
|
40
28
|
|
@@ -55,11 +43,11 @@ module RailsSoftLock
|
|
55
43
|
|
56
44
|
def locked_by
|
57
45
|
user_id = base_lock_object.locked_by&.to_i
|
58
|
-
user_id ?
|
46
|
+
user_id ? RailsSoftLock.configuration.locked_by_class.find_by(id: user_id) : nil
|
59
47
|
end
|
60
48
|
|
61
49
|
def object_key
|
62
|
-
attribute = RailsSoftLock.configuration
|
50
|
+
attribute = RailsSoftLock.configuration.acts_as_locked_attribute
|
63
51
|
raise ArgumentError, "No locked attribute defined" if attribute == :none
|
64
52
|
|
65
53
|
send(attribute)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/rails_soft_lock/redis_config.rb
|
4
|
+
module RailsSoftLock
|
5
|
+
# Provides Redis configuration management for RailsSoftLock gem
|
6
|
+
# Handles:
|
7
|
+
# - Default Redis settings
|
8
|
+
# - Rails-specific configuration lookup
|
9
|
+
# - Safe fallbacks when Rails isn't available
|
10
|
+
module RedisConfig
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# Returns the complete Redis adapter options hash
|
14
|
+
# @return [Hash] Options hash with :redis key containing configuration
|
15
|
+
# @example
|
16
|
+
# { redis: { host: 'localhost', port: 6379, db: 0, timeout: 5 } }
|
17
|
+
def default_adapter_options
|
18
|
+
{ redis: config_with_defaults }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Merges default settings with any Rails-specific configuration
|
22
|
+
# @return [Hash] Complete Redis configuration
|
23
|
+
# @note Will return just defaults if Rails isn't available
|
24
|
+
def config_with_defaults
|
25
|
+
base_config = rails_available? ? rails_config : {}
|
26
|
+
default_settings.merge(base_config)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Checks if Rails environment is available and properly configured
|
30
|
+
# @return [Boolean]
|
31
|
+
def rails_available?
|
32
|
+
if defined?(Rails) &&
|
33
|
+
Rails.respond_to?(:application) &&
|
34
|
+
Rails.application
|
35
|
+
true
|
36
|
+
else
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Attempts to load Redis config from Rails application
|
42
|
+
# @return [Hash] Redis configuration from Rails or empty hash if unavailable
|
43
|
+
# @note Safely handles cases where config_for isn't available
|
44
|
+
def rails_config
|
45
|
+
return {} unless rails_config_available?
|
46
|
+
|
47
|
+
config = Rails.application.config_for(:redis)
|
48
|
+
|
49
|
+
config.is_a?(Hash) ? config.symbolize_keys : {}
|
50
|
+
rescue RuntimeError, ArgumentError
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
# Checks if Rails provides config_for functionality
|
55
|
+
# @return [Boolean]
|
56
|
+
# @api private
|
57
|
+
def rails_config_available?
|
58
|
+
Rails.application.respond_to?(:config_for)
|
59
|
+
end
|
60
|
+
|
61
|
+
# The default Redis connection settings
|
62
|
+
# @return [Hash]
|
63
|
+
# @api private
|
64
|
+
def default_settings
|
65
|
+
{ url: "redis://localhost:6379/0", timeout: 5 }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/rails_soft_lock.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# lib/rails_soft_lock.rb
|
4
|
+
|
3
5
|
require "zeitwerk"
|
4
|
-
loader = Zeitwerk::Loader.for_gem
|
5
|
-
loader.setup
|
6
6
|
|
7
7
|
# RailsSoftLock - module for soft lock ApplicationRecord by attribyte
|
8
8
|
module RailsSoftLock
|
@@ -30,6 +30,35 @@ module RailsSoftLock
|
|
30
30
|
lock_manager(object_name: object_name, object_key: object_key, object_value: object_value).lock_or_find
|
31
31
|
end
|
32
32
|
|
33
|
+
class << self
|
34
|
+
# Configures the RailsSoftLock gem with a block.
|
35
|
+
# @yield [config] Yields the configuration object to the block.
|
36
|
+
# @return [void]
|
37
|
+
def configure
|
38
|
+
@configuration ||= Configuration.new
|
39
|
+
if block_given?
|
40
|
+
yield(@configuration)
|
41
|
+
else
|
42
|
+
warn "[RailsSoftLock] No configuration block provided in `configure`"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the current configuration instance.
|
47
|
+
# @return [Configuration] The configuration object.
|
48
|
+
def configuration
|
49
|
+
@configuration ||= Configuration.new
|
50
|
+
end
|
51
|
+
|
52
|
+
# Resets the configuration (useful for testing).
|
53
|
+
# @return [void]
|
54
|
+
def reset_configuration
|
55
|
+
@configuration = nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
33
59
|
# Load rake task if Rails
|
34
60
|
require "rails_soft_lock/railtie" if defined?(Rails)
|
35
61
|
end
|
62
|
+
|
63
|
+
loader = Zeitwerk::Loader.for_gem
|
64
|
+
loader.setup
|
@@ -22,7 +22,7 @@ namespace :rails_soft_lock do
|
|
22
22
|
|
23
23
|
# configuration for the redis adapter
|
24
24
|
config.adapter_options = {
|
25
|
-
redis:
|
25
|
+
redis: Rails.application.config_for(:redis).merge(
|
26
26
|
timeout: 5
|
27
27
|
)
|
28
28
|
}
|
@@ -34,7 +34,7 @@ namespace :rails_soft_lock do
|
|
34
34
|
# config.acts_as_locked_scope = -> { "default_scope" }
|
35
35
|
|
36
36
|
# (Optional) Model class for locked_by lookups
|
37
|
-
# config.locked_by_class = User
|
37
|
+
# config.locked_by_class = "User"
|
38
38
|
end
|
39
39
|
RUBY
|
40
40
|
puts "Created RailsSoftLock configuration file at #{initializer_path}"
|
data/sig/rails_soft_lock.rbs
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
module RailsSoftLock
|
3
3
|
self.@lock_manager: untyped
|
4
4
|
|
5
|
+
self.@configuration: untyped
|
6
|
+
|
5
7
|
# Error class for gem
|
6
8
|
class Error < StandardError
|
7
9
|
end
|
@@ -14,4 +16,17 @@ module RailsSoftLock
|
|
14
16
|
def self.create: (untyped object_name, untyped object_key, untyped object_value) -> untyped
|
15
17
|
|
16
18
|
def self.update: (untyped object_name, untyped object_key, untyped object_value) -> untyped
|
19
|
+
|
20
|
+
# Configures the RailsSoftLock gem with a block.
|
21
|
+
# @yield [config] Yields the configuration object to the block.
|
22
|
+
# @return [void]
|
23
|
+
def self.configure: () ?{ (untyped) -> untyped } -> untyped
|
24
|
+
|
25
|
+
# Returns the current configuration instance.
|
26
|
+
# @return [Configuration] The configuration object.
|
27
|
+
def self.configuration: () -> untyped
|
28
|
+
|
29
|
+
# Resets the configuration (useful for testing).
|
30
|
+
# @return [void]
|
31
|
+
def self.reset_configuration: () -> untyped
|
17
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_soft_lock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Arkhipov
|
8
8
|
- Vladimir Peskov
|
9
9
|
bindir: lib
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: connection_pool
|
@@ -40,7 +40,8 @@ dependencies:
|
|
40
40
|
version: '2.7'
|
41
41
|
description: Using In-Memory Databases to Work with Rails Active Record Locks
|
42
42
|
email:
|
43
|
-
- sergey-
|
43
|
+
- sergey-arkhipov@ya.ru
|
44
|
+
- v.peskov@mail.ru
|
44
45
|
executables: []
|
45
46
|
extensions: []
|
46
47
|
extra_rdoc_files: []
|
@@ -59,15 +60,10 @@ files:
|
|
59
60
|
- lib/rails_soft_lock/model_extensions.rb
|
60
61
|
- lib/rails_soft_lock/railtie.rb
|
61
62
|
- lib/rails_soft_lock/redis_adapter.rb
|
63
|
+
- lib/rails_soft_lock/redis_config.rb
|
62
64
|
- lib/rails_soft_lock/version.rb
|
63
65
|
- lib/tasks/rails_soft_lock.rake
|
64
66
|
- sig/rails_soft_lock.rbs
|
65
|
-
- sig/rails_soft_lock/configuration.rbs
|
66
|
-
- sig/rails_soft_lock/lock_object.rbs
|
67
|
-
- sig/rails_soft_lock/model_extensions.rbs
|
68
|
-
- sig/rails_soft_lock/railtie.rbs
|
69
|
-
- sig/rails_soft_lock/redis_adapter.rbs
|
70
|
-
- sig/rails_soft_lock/version.rbs
|
71
67
|
homepage: https://github.com/sergey-arkhipov/rails_soft_lock
|
72
68
|
licenses:
|
73
69
|
- MIT
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# lib/rails_soft_lock/configuration.rb
|
2
|
-
module RailsSoftLock
|
3
|
-
self.@configuration: untyped
|
4
|
-
|
5
|
-
# Configuration class for RailsSoftLock gem.
|
6
|
-
class Configuration
|
7
|
-
@adapter: untyped
|
8
|
-
|
9
|
-
@adapter_options: untyped
|
10
|
-
|
11
|
-
@acts_as_locked_by: untyped
|
12
|
-
|
13
|
-
@acts_as_locked_scope: untyped
|
14
|
-
|
15
|
-
# List of supported adapters.
|
16
|
-
VALID_ADAPTERS: ::Array[:redis | :nats | :memcached]
|
17
|
-
|
18
|
-
attr_reader adapter: untyped
|
19
|
-
|
20
|
-
attr_accessor adapter_options: untyped
|
21
|
-
|
22
|
-
attr_accessor acts_as_locked_by: untyped
|
23
|
-
|
24
|
-
attr_accessor acts_as_locked_scope: untyped
|
25
|
-
|
26
|
-
def initialize: () -> void
|
27
|
-
|
28
|
-
def []: (untyped key) -> untyped
|
29
|
-
|
30
|
-
def []=: (untyped key, untyped value) -> untyped
|
31
|
-
|
32
|
-
# Sets the adapter and validates it.
|
33
|
-
# @param value [Symbol] The adapter to use.
|
34
|
-
# @raise [ArgumentError] If the adapter is not supported.
|
35
|
-
def adapter=: (untyped value) -> untyped
|
36
|
-
end
|
37
|
-
|
38
|
-
# Configures the RailsSoftLock gem with a block.
|
39
|
-
# @yield [config] Yields the configuration object to the block.
|
40
|
-
# @return [void]
|
41
|
-
def self.configure: () ?{ (untyped) -> untyped } -> untyped
|
42
|
-
|
43
|
-
# Returns the current configuration instance.
|
44
|
-
# @return [Configuration] The configuration object.
|
45
|
-
def self.configuration: () -> untyped
|
46
|
-
|
47
|
-
# Resets the configuration (useful for testing).
|
48
|
-
# @return [void]
|
49
|
-
def self.reset_configuration: () -> untyped
|
50
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module RailsSoftLock
|
2
|
-
# Service for managing object locks
|
3
|
-
# A lock object contains the following parameters:
|
4
|
-
# - object_name: The name of the lock storage, typically the model name with an optional scope
|
5
|
-
# - object_key: The identifier of the lock instance, typically a unique database record ID
|
6
|
-
# - object_value: The identifier of the locker that locked the record
|
7
|
-
class LockObject
|
8
|
-
@object_name: untyped
|
9
|
-
|
10
|
-
@object_key: untyped
|
11
|
-
|
12
|
-
@object_value: untyped
|
13
|
-
|
14
|
-
# Подключаем адаптер на основе конфигурации
|
15
|
-
def self.adapter: () -> untyped
|
16
|
-
|
17
|
-
attr_reader object_name: untyped
|
18
|
-
|
19
|
-
attr_reader object_key: untyped
|
20
|
-
|
21
|
-
attr_reader object_value: untyped
|
22
|
-
|
23
|
-
def initialize: (object_name: untyped, ?object_key: untyped?, ?object_value: untyped?) -> void
|
24
|
-
|
25
|
-
# Returns the ID of the locker who locked the object
|
26
|
-
# @return [String, nil] The locker's ID or nil if not locked
|
27
|
-
def locked_by: () -> untyped
|
28
|
-
|
29
|
-
# Attempts to lock the object or returns the existing lock
|
30
|
-
# @return [Hash] { has_locked: Boolean, locked_by: String or nil }
|
31
|
-
def lock_or_find: () -> { has_locked: untyped, locked_by: untyped }
|
32
|
-
|
33
|
-
# Unlocks the object
|
34
|
-
# @return [Boolean] True if the lock was removed, false otherwise
|
35
|
-
def unlock: () -> untyped
|
36
|
-
|
37
|
-
# Returns all locks in the storage
|
38
|
-
# @return [Hash] All key-value pairs in the storage
|
39
|
-
def all_locks: () -> untyped
|
40
|
-
end
|
41
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module RailsSoftLock
|
2
|
-
# Adapter for store lock in redis
|
3
|
-
module RedisAdapter
|
4
|
-
@redis_client: untyped
|
5
|
-
|
6
|
-
# Initialize Redis client
|
7
|
-
def redis_client: () -> untyped
|
8
|
-
|
9
|
-
# Retrieves a value by key from the specified hash
|
10
|
-
# @return [String, nil] The value associated with the key
|
11
|
-
def get: () -> untyped
|
12
|
-
|
13
|
-
# Creates a new key-value pair if the key does not exist
|
14
|
-
# @return [Boolean] true if the key was created, false if it already existed
|
15
|
-
def create: () -> untyped
|
16
|
-
|
17
|
-
# Updates the value for an existing key or creates a new key-value pair
|
18
|
-
# @return [Boolean] true if the key was updated, false if it was created
|
19
|
-
def update: () -> untyped
|
20
|
-
|
21
|
-
# Deletes a key from the specified hash
|
22
|
-
# @return [Boolean] true if the key was deleted, false if it did not exist
|
23
|
-
def delete: () -> untyped
|
24
|
-
|
25
|
-
# Retrieves all key-value pairs in the specified hash
|
26
|
-
# @return [Hash] The key-value pairs in the hash
|
27
|
-
def all: () -> untyped
|
28
|
-
end
|
29
|
-
end
|