Skip to content

Instantly share code, notes, and snippets.

@ahoward
Created January 31, 2019 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahoward/c626ac69aea19a9f146aedaf314b7f9a to your computer and use it in GitHub Desktop.
Save ahoward/c626ac69aea19a9f146aedaf314b7f9a to your computer and use it in GitHub Desktop.
rails just *cannot* run in threads. doing even simple things will bork it in strange and magical ways
class A
attr_accessor :dsl
attr_accessor :state
def initialize
@state = []
@dsl = self.class.dsl
sleep(rand)
instance_eval(&@dsl) if @dsl
sleep(rand)
end
def A.dsl(&block)
if block
@dsl = block
end
sleep(rand)
defined?(@dsl) && @dsl
end
end
class B < A
B.dsl do
@state.push Thread.current
end
end
threads =
[]
5.times do
threads <<
Thread.new do
Thread.current.abort_on_exception = true
(sleep(rand) && load('a.rb')) unless defined?(A) # initial rails autoload of base class
(sleep(rand) && load('b.rb')) unless defined?(B) # subsequent app load of a needed subclass of base
42.times do
b = B.new
raise 'borked' if b.state != [Thread.current]
end
end
end
threads.map{|t| t.join}
__END__
run this via and watch it bork:
~> while true;do ruby c.rb || say 'borked' && echo 'borked'; done
borked
borked
borked
borked
borked
borked
...
couple of notes:
- ruby's own require / load are NOT thread safe
- yet rails makes an attempt to implement an autoload that will be on top if it
- it ain't. well, it might be, but to find out you'd have to just write code
with 'A.foo' vs 'A.foo if defined?(A)', meaning you'd have to avoid all
'defined?' tests and trigger the `const_missing` handler rails uses to
attempt to work around mt loading issues. theoretically possible but
*extremely* fragile.
ref:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment