Skip to content

Commit

Permalink
BackgroundHelper: avoid leaking threads (#475)
Browse files Browse the repository at this point in the history
* Fix activerecord trilogy adapter config override test

* BackgroundHelper: avoid leaking threads

Many test cases would define `teardown` without calling super
so we were never killing threads...

It's better to use `before_teardown` anyway, and it's less popular
so less likely to be overriden without a super.

This is very likely to be the cause of the crash we've seen
at https://github.com/Shopify/semian/actions/runs/4122969863/jobs/7120418231

Co-Authored-By: Adrianna Chang <adrianna.chang@shopify.com>

* Rescue timeout errors from background thread

---------

Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
  • Loading branch information
3 people authored Feb 13, 2023
1 parent 2b8c8d8 commit 154f31b
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 22 deletions.
12 changes: 7 additions & 5 deletions test/adapters/activerecord_trilogy_adapter_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
module ActiveRecord
module ConnectionAdapters
class ActiveRecordTrilogyAdapterTest < Minitest::Test
include BackgroundHelper

ERROR_TIMEOUT = 5
ERROR_THRESHOLD = 1
SEMIAN_OPTIONS = {
Expand All @@ -18,6 +20,7 @@ class ActiveRecordTrilogyAdapterTest < Minitest::Test
}

def setup
super
@proxy = Toxiproxy[:semian_test_mysql]
Semian.destroy(:mysql_testing)

Expand All @@ -34,6 +37,7 @@ def setup
end

def teardown
super
@adapter.disconnect!
end

Expand All @@ -60,12 +64,10 @@ def test_semian_can_be_disabled
end

def test_adapter_does_not_modify_config
config = @configuration.merge(config_overrides)

assert(config.key?(:semian))
TrilogyAdapter.new(config)
assert(@configuration.key?(:semian))
TrilogyAdapter.new(@configuration)

assert(config.key?(:semian))
assert(@configuration.key?(:semian))
end

def test_unconfigured
Expand Down
3 changes: 3 additions & 0 deletions test/adapters/mysql2_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
require "semian/mysql2"

class TestMysql2 < Minitest::Test
include BackgroundHelper

ERROR_TIMEOUT = 5
ERROR_THRESHOLD = 1
SEMIAN_OPTIONS = {
Expand All @@ -17,6 +19,7 @@ class TestMysql2 < Minitest::Test
}

def setup
super
@proxy = Toxiproxy[:semian_test_mysql]
Semian.destroy(:mysql_testing)
end
Expand Down
11 changes: 8 additions & 3 deletions test/adapters/redis_client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
require "benchmark"

module RedisClientTests
include BackgroundHelper

REDIS_TIMEOUT = 0.5
ERROR_TIMEOUT = 5
ERROR_THRESHOLD = 1
Expand All @@ -20,9 +22,8 @@ module RedisClientTests
error_timeout: ERROR_TIMEOUT,
}

attr_writer :threads

def setup
super
@proxy = Toxiproxy[:semian_test_redis]
Semian.destroy(:redis_testing)
end
Expand Down Expand Up @@ -156,7 +157,11 @@ def test_other_redis_errors_are_not_tagged_with_the_resource_identifier

def test_resource_timeout_on_connect
@proxy.downstream(:latency, latency: redis_timeout_ms).apply do
background { connect_to_redis! }
background do
connect_to_redis!
rescue RedisClient::CircuitOpenError
nil
end

assert_raises(RedisClient::ResourceBusyError) do
connect_to_redis!
Expand Down
11 changes: 8 additions & 3 deletions test/adapters/redis_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
require "semian/redis"

module RedisTests
include BackgroundHelper

REDIS_TIMEOUT = 0.5
ERROR_TIMEOUT = 5
ERROR_THRESHOLD = 1
Expand All @@ -21,9 +23,8 @@ module RedisTests
error_timeout: ERROR_TIMEOUT,
}

attr_writer :threads

def setup
super
@proxy = Toxiproxy[:semian_test_redis]
Semian.destroy(:redis_testing)
end
Expand Down Expand Up @@ -198,7 +199,11 @@ def test_other_redis_errors_are_not_tagged_with_the_resource_identifier

def test_resource_timeout_on_connect
@proxy.downstream(:latency, latency: redis_timeout_ms).apply do
background { connect_to_redis! }
background do
connect_to_redis!
rescue Redis::CircuitOpenError
nil
end

assert_raises(Redis::ResourceBusyError) do
connect_to_redis!
Expand Down
19 changes: 9 additions & 10 deletions test/helpers/background_helper.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
# frozen_string_literal: true

module BackgroundHelper
attr_writer :threads
def after_setup
@_threads = []
end

def teardown
threads.each(&:kill)
self.threads = []
def before_teardown
@_threads.each(&:kill)
@_threads.each(&:join)
@_threads = nil
end

private

def background(&block)
thread = Thread.new(&block)
thread.report_on_exception = false
threads << thread
@_threads << thread
thread.join(0.1)
thread
end

def threads
@threads ||= []
end

def yield_to_background
threads.each(&:join)
@_threads.each(&:join)
end
end
1 change: 1 addition & 0 deletions test/protected_resource_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
class TestProtectedResource < Minitest::Test
include CircuitBreakerHelper
include ResourceHelper
include BackgroundHelper

def setup
destroy_all_semian_resources
Expand Down
1 change: 0 additions & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@

module Minitest
class Test
include BackgroundHelper
include TimeHelper
include ResourceHelper
end
Expand Down

0 comments on commit 154f31b

Please sign in to comment.