Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

Commit 42186b8

Browse files
Add advisory lock timeout configuration with error on failure
- Add advisory_lock_timeout_seconds option (default: 15 seconds) - Raise error when advisory lock cannot be acquired within timeout - This provides explicit failure behavior for lock contention issues Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fb9dfa1 commit 42186b8

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
1-
# Closure Tree
1+
# Closure Tree (OpsLevel Fork)
2+
3+
This is the OpsLevel fork of [closure_tree](https://github.com/ClosureTree/closure_tree), based on upstream v9.5.0.
4+
5+
## Fork-Specific Changes
6+
7+
This fork adds one enhancement to the advisory lock behavior:
8+
9+
### Advisory Lock Timeout with Error on Failure
10+
11+
- Adds `advisory_lock_timeout_seconds` option (default: 15 seconds)
12+
- Raises an error when the advisory lock cannot be acquired within the timeout period
13+
14+
The upstream version has no timeout and hangs forever if lock acquisition fails. This fork uses `with_advisory_lock!` (with bang) which raises `WithAdvisoryLock::FailedToAcquireLock` when the lock cannot be obtained, providing explicit failure behavior for lock contention issues.
15+
16+
```ruby
17+
class Tag < ApplicationRecord
18+
# Use default 15 second timeout
19+
has_closure_tree
20+
21+
# Or customize the timeout
22+
has_closure_tree advisory_lock_timeout_seconds: 30
23+
end
24+
```
25+
26+
---
227

328
### Closure_tree lets your ActiveRecord models act as nodes in a [tree data structure](http://en.wikipedia.org/wiki/Tree_%28data_structure%29)
429

lib/closure_tree/support.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def initialize(model_class, options)
1919
dependent: :nullify, # or :destroy, :delete_all, or :adopt -- see the README
2020
name_column: 'name',
2121
with_advisory_lock: true, # This will be overridden by adapter support
22+
advisory_lock_timeout_seconds: 15,
2223
numeric_order: false
2324
}.merge(options)
2425
raise ArgumentError, "name_column can't be 'path'" if options[:name_column] == 'path'
@@ -153,8 +154,8 @@ def build_scope_where_clause(scope_conditions)
153154
end
154155

155156
def with_advisory_lock(&block)
156-
if options[:with_advisory_lock] && connection.supports_advisory_locks? && model_class.respond_to?(:with_advisory_lock)
157-
model_class.with_advisory_lock(advisory_lock_name) do
157+
if options[:with_advisory_lock] && connection.supports_advisory_locks? && model_class.respond_to?(:with_advisory_lock!)
158+
model_class.with_advisory_lock!(advisory_lock_name, advisory_lock_options) do
158159
transaction(&block)
159160
end
160161
else

lib/closure_tree/support_attributes.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ def advisory_lock_name
3434
end
3535
end
3636

37+
def advisory_lock_options
38+
{ timeout_seconds: options[:advisory_lock_timeout_seconds] }.compact
39+
end
40+
3741
def quoted_table_name
3842
connection.quote_table_name(table_name)
3943
end

0 commit comments

Comments
 (0)