Closed stevenharman closed 5 years ago
I'm not sure what the intended/desired behavior of this library is in terms of wether we should be using the same
#thread_key
and then updatingThread.current[]=
with the new emitter. Or if we should be delegating differently?
The goal is to prevent a situation where the same Emitter
is used from two different threads and have mixed context. Like this:
logger = L2meter.build
thread_a = Thread.new do
1_000.times do
logger.context :bar do
logger.log :hi
end
end
end
thread_b = Thread.new do
1_000.times do
logger.log :bye
end
end
[thread_a, thread_b].each &:join
So, in this situation we need to make sure that bye
is never mixed with bar
context. It might actually make sense to add a test for this to make sure we can play with this code and not accidentally break things.
Honestly at this point I have no idea how to fix this memory leak without changing external API or making usage ergonomics worse.
I have a spec for this ^^^, but can't push it since I lost access to the repo as I was kicked out of heroku org. Do you mind adding me back as a collab on this repo? :)
Should be addressed by #7
I believe we have a memory leak in the
L2meter::ThreadSafe
proxy which is leaking instances ofL2meter::Emitter
into theThread.current[]
.The
ThreadSafe
proxies most requests to its internalEmitter
instance. It does so by delegating methods through a#receiver
, which will grab the thread-local instance of anEmitter
via the#current_emitter
. BUTcurrent_emitter
builds the cache key using the wrappedEmitter
instance, which could be different than the originalEmitter
instance. Further, everyThreadSafe#context
calls results in a new instance ofThreadSafe
, with an unset (nil
)@thread_key
. So the first proxied method on a new instance ofThreadSafe
will add anotherEmitter
instance to theThread.current[]
, under a new key (b/c theEmitter
is a clone).The important code from
ThreadSafe
, followed by a minimal script to reproduce.A minimal script to reproduce, named
leak_emitter_in_thread
:Running the script:
I'm not sure what the intended/desired behavior of this library is in terms of wether we should be using the same
#thread_key
and then updatingThread.current[]=
with the new emitter. Or if we should be delegating differently?Any advice, @rwz?