Skip to content

Commit 84bc2cc

Browse files
authored
Check that advisory lock prefix fits inside four bytes (#24)
Add an extra safety check that an advisory lock prefix fits inside of four bytes, which is all that's reserved for one.
1 parent 94aca9b commit 84bc2cc

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
- Advisory lock prefixes are now checked to make sure they fit inside of four bytes. [PR #24](https://github.com/riverqueue/riverqueue-ruby/pull/24).
11+
1012
## [0.5.0] - 2024-07-05
1113

1214
### Changed

lib/client.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module River
2626
class Client
2727
def initialize(driver, advisory_lock_prefix: nil)
2828
@driver = driver
29-
@advisory_lock_prefix = advisory_lock_prefix
29+
@advisory_lock_prefix = check_advisory_lock_prefix_bounds(advisory_lock_prefix)
3030
@time_now_utc = -> { Time.now.utc } # for test time stubbing
3131
end
3232

@@ -137,6 +137,16 @@ def insert_many(args)
137137
@driver.job_insert_many(all_params)
138138
end
139139

140+
private def check_advisory_lock_prefix_bounds(advisory_lock_prefix)
141+
return nil if advisory_lock_prefix.nil?
142+
143+
# 2**32-1 is 0xffffffff (the largest number that's four bytes)
144+
if advisory_lock_prefix < 0 || advisory_lock_prefix > 2**32 - 1
145+
raise ArgumentError, "advisory lock prefix must fit inside four bytes"
146+
end
147+
advisory_lock_prefix
148+
end
149+
140150
# Default states that are used during a unique insert. Can be overridden by
141151
# setting UniqueOpts#by_state.
142152
DEFAULT_UNIQUE_STATES = [

sig/client.rbs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ module River
88
@driver: _Driver
99
@time_now_utc: ^() -> Time
1010

11-
DEFAULT_UNIQUE_STATES: Array[jobStateAll]
12-
EMPTY_INSERT_OPTS: InsertOpts
13-
1411
def initialize: (_Driver driver, ?advisory_lock_prefix: Integer?) -> void
1512
def insert: (jobArgs, ?insert_opts: InsertOpts) -> InsertResult
1613
def insert_many: (Array[jobArgs | InsertManyParams]) -> Integer
1714

15+
private def check_advisory_lock_prefix_bounds: (Integer?) -> Integer?
16+
17+
DEFAULT_UNIQUE_STATES: Array[jobStateAll]
18+
EMPTY_INSERT_OPTS: InsertOpts
19+
1820
private def check_unique_job: (Driver::JobInsertParams, UniqueOpts?) { () -> InsertResult } -> InsertResult
1921
private def make_insert_params: (jobArgs, InsertOpts, ?is_insert_many: bool) -> [Driver::JobInsertParams, UniqueOpts?]
2022
private def truncate_time: (Time, Integer) -> Time

spec/client_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ class SimpleArgsWithInsertOpts < SimpleArgs
173173
)
174174
end
175175

176+
it "errors if advisory lock prefix is larger than four bytes" do
177+
River::Client.new(mock_driver, advisory_lock_prefix: 123)
178+
179+
expect do
180+
River::Client.new(mock_driver, advisory_lock_prefix: -1)
181+
end.to raise_error(ArgumentError, "advisory lock prefix must fit inside four bytes")
182+
183+
# 2^32-1 is 0xffffffff (1s for 32 bits) which fits
184+
River::Client.new(mock_driver, advisory_lock_prefix: 2**32 - 1)
185+
186+
# 2^32 is 0x100000000, which does not
187+
expect do
188+
River::Client.new(mock_driver, advisory_lock_prefix: 2**32)
189+
end.to raise_error(ArgumentError, "advisory lock prefix must fit inside four bytes")
190+
end
191+
176192
it "errors if args don't respond to #kind" do
177193
args_klass = Class.new do
178194
def to_json = {}

0 commit comments

Comments
 (0)