Skip to content

Commit

Permalink
fix race condition when using semantic methods
Browse files Browse the repository at this point in the history
Enumerable and predicate methods will now behave better when they refer
to stale proxies - filtering methods will just remove them. I run into
this occasionally when I have multiple rules firing, and some of them
are adding or removing items - and calling items.locations would raise
a NoMethodError for #location? due to a race condition. This should no
longer happen - it will just ignore the now-stale items.

Signed-off-by: Cody Cutrer <[email protected]>
  • Loading branch information
ccutrer committed Nov 25, 2024
1 parent daca142 commit 79918fe
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
29 changes: 29 additions & 0 deletions lib/openhab/core/items/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,35 @@ def members
__getobj__.members
end

# Several methods can just return nil when it's a dummy item
# This helps when you're doing something like `items.locations.select {}`
# when items are getting created and removed in a concurrent thread to
# not have errors because an item disappeared
%i[
equipment
equipment?
equipment_type
location
location?
location_type
member_of?
point?
point_type
property_type
semantic?
semantic_type
tagged?
].each do |m|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
def #{m}(*args) # def equipment(*args)
target = __getobj__ # target = __getobj__
return nil if target.nil? # return nil if target.nil?
#
target.#{m}(*args) # target.equipment(*args)
end # end
RUBY
end

# @return [String]
def to_s
return name if __getobj__.nil?
Expand Down
4 changes: 4 additions & 0 deletions spec/openhab/core/items/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@
expect(item).not_to respond_to(:command)
expect { item.command }.to raise_error(NoMethodError)
end

it "disappears when calling semantic predicates on an array" do
expect([item].locations).to eql []
end
end

it "does not respond to GroupItem#members if it's backed by a non-GroupItem" do
Expand Down

0 comments on commit 79918fe

Please sign in to comment.