Skip to content

Commit 177d7d5

Browse files
committed
CI fix
1 parent 5f04dde commit 177d7d5

File tree

2 files changed

+40
-22
lines changed

2 files changed

+40
-22
lines changed

temporalio/test/gc_utils.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,25 @@ def find_retaining_path_to(target_id, max_depth: 12, max_visits: 250_000, catego
8787
[objs, root_of[ids.first]]
8888
end
8989

90-
# Print path on stdout.
91-
def print_annotated_path(path, root_category:)
92-
puts "Retaining path (len=#{path.length}) from ROOT[:#{root_category}] to target:"
93-
return if path.empty?
90+
# Return string of annotated path
91+
def annotated_path(path, root_category:)
92+
lines = []
93+
lines << "Retaining path (len=#{path.length}) from ROOT[:#{root_category}] to target:"
94+
return lines.join("\n") if path.empty?
9495

9596
# First is the root
96-
puts " ROOT[:#{root_category}] #{describe_obj(path.first)}"
97+
lines << " ROOT[:#{root_category}] #{describe_obj(path.first)}"
9798
# Then edges with labels
9899
(0...(path.length - 1)).each do |i|
99100
parent = path[i]
100101
child = path[i + 1]
101102
labels = edge_labels(parent, child)
102103
labels.each_with_index do |lab, j|
103104
arrow = (j.zero? ? ' └─' : ' •')
104-
puts "#{arrow} via #{lab}#{describe_obj(child)}"
105+
lines << "#{arrow} via #{lab}#{describe_obj(child)}"
105106
end
106107
end
108+
lines.join("\n")
107109
end
108110

109111
private

temporalio/test/worker_workflow_test.rb

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1914,9 +1914,10 @@ class ConfirmGarbageCollectWorkflow < Temporalio::Workflow::Definition
19141914
@initialized_count = 0
19151915
@finalized_count = 0
19161916
@weak_instance = nil
1917+
@strong_instance = nil
19171918

19181919
class << self
1919-
attr_accessor :initialized_count, :finalized_count, :weak_instance
1920+
attr_accessor :initialized_count, :finalized_count, :weak_instance, :strong_instance
19201921

19211922
def create_finalizer
19221923
proc { @finalized_count += 1 }
@@ -1926,6 +1927,9 @@ def create_finalizer
19261927
def initialize
19271928
self.class.initialized_count += 1
19281929
self.class.weak_instance = WeakRef.new(self)
1930+
# Uncomment this to cause test to fail
1931+
# self.class.strong_instance = self
1932+
19291933
ObjectSpace.define_finalizer(self, self.class.create_finalizer)
19301934
end
19311935

@@ -1936,11 +1940,10 @@ def execute
19361940

19371941
def test_confirm_garbage_collect
19381942
major, minor = RUBY_VERSION.split('.').take(2).map(&:to_i)
1939-
skip('Only Ruby 3.4+ has predictable eager GC') if major != 3 || minor < 4
1943+
skip('Only Ruby 3.4+ has somewhat predictable eager GC') if major != 3 || minor < 4
19401944

19411945
# This test confirms the workflow instance is reliably GC'd when workflow/worker done. To confirm the test fails
1942-
# when there is still an instance, make a "strong_instance" singleton attribute and assign "self" to it in
1943-
# initialize and confirm this calls flunk later.
1946+
# when there is still an instance, uncomment the strong_instance set in the initialize of the workflow.
19441947

19451948
execute_workflow(ConfirmGarbageCollectWorkflow) do |handle|
19461949
# Wait until it is started
@@ -1950,18 +1953,31 @@ def test_confirm_garbage_collect
19501953
assert_equal 0, ConfirmGarbageCollectWorkflow.finalized_count
19511954
end
19521955

1953-
# Perform a GC and confirm gone
1954-
GC.start
1955-
begin
1956-
# Access instance and assert that it fails when a method is called on it as expected
1957-
instance = ConfirmGarbageCollectWorkflow.weak_instance.__getobj__
1958-
1959-
# Print out the path still holding it
1960-
path, cat = GCUtils.find_retaining_path_to(instance.object_id, max_depth: 12)
1961-
GCUtils.print_annotated_path(path, root_category: cat)
1962-
flunk
1963-
rescue WeakRef::RefError
1964-
# Expected
1956+
# Perform a GC and confirm gone. There are cases in Ruby where dead stack slots leave the item around for a bit, so
1957+
# we check repeatedly for a bit (every 200ms for 10s). We can't use assert_eventually, because path doesn't show
1958+
# well.
1959+
start_time = Time.now
1960+
loop do
1961+
GC.start
1962+
# Break if the instance is gone
1963+
break unless ConfirmGarbageCollectWorkflow.weak_instance.weakref_alive?
1964+
1965+
# If this is last iteration, flunk w/ the path
1966+
if Time.now - start_time > 10
1967+
instance = ConfirmGarbageCollectWorkflow.weak_instance.__getobj__
1968+
path, cat = GCUtils.find_retaining_path_to(instance.object_id, max_depth: 12)
1969+
msg = GCUtils.annotated_path(path, root_category: cat)
1970+
msg += "\nPath:\n#{path.map { |p| " Item: #{p}" }.join("\n")}"
1971+
# Also display any Thread/Fiber backtraces that are in the path
1972+
path.grep(Thread).each do |thread|
1973+
msg += "\nThread trace: #{thread.backtrace.join("\n")}"
1974+
end
1975+
path.grep(Fiber).each do |fiber|
1976+
msg += "\nFiber trace: #{fiber.backtrace.join("\n")}"
1977+
end
1978+
flunk msg
1979+
end
1980+
sleep(0.2)
19651981
end
19661982
end
19671983

0 commit comments

Comments
 (0)