On Thu, Mar 12, 2015 at 1:22 PM, Man Vuong <
thanh...@gmail.com> wrote:
> Hi,
>
> In one of my projects, I'm using RestCore in Rails application, then I
> encountered this error:
>
> ActiveRecord::ConnectionTimeoutError: connection pool was full
>
> After debugging, I figured out it was because of some code related to
> ActiveRecord in callbacks, something likes this:
>
> client.get("/friends") do |response|
> friend = User.find_by(id: response['id'])
> # ...
> end
>
> DB connection leak!
Yes, they never fix this, and you have to wrap your code with:
ActiveRecord::Base.connection_pool.with_connection do
...
end
Or the database connection would leak. So you'll have to do something like:
client.get("/friends") do |response|
ActiveRecord::Base.connection_pool.with_connection do
friend = User.find_by(id: response['id'])
end
end
This is quite tedious indeed, but this is how it works for years :(
Sequel has no problem with this, it could cleanup itself.
http://sequel.jeremyevans.net/
On the other hand, if you're using ActiveRecord outside Rails,
with a threaded server, you would need this Rack middleware:
use ActiveRecord::ConnectionAdapters::ConnectionManagement
It would do something like the `with_connection` for the application.
I have no idea why they never fix this. Maybe they just don't use threads.
> I also noticed a very unusual high memory usage. At the beginning I thought
> it was because I'm using thread pool size 1000, too many threads? But after
> decreasing the pool size to 500, it's still. So I thought there was
> something wrong with the GC.
>
> Finally I could reproduce the problem by doing steps like this interesting
> thread. Ruby does have problem with GC and threads!
Given the gist:
https://gist.github.com/ryanlecompte/3281509
I guess if you use `with_connection`, the GC would work more as expected.
I believe ActiveRecord holds the connection all the time, and the records
hold the connection all the time, therefore all AR objects are not garbage.
With `with_connection`, maybe they could become garbage and the GC
could work properly.
I believe AR should do something like Sequel to cleanup itself.
Hope we could see this in the future.
> I end up with this monkey patch:
>
> module RestCore
> # Patch RestCore::Promise
> module PromiseExt
> protected
>
> def protected_yield(*args)
> super
> ensure
> collect_garbage
> end
>
> def collect_garbage
> # Cleanup DB connections.
> ActiveRecord::Base.clear_active_connections!
>
> # Force the Garbage collector to run,
> # otherwise, useless resources born inside threads may be never
> released.
> GC.start
> end
> end
>
> class Promise
> prepend PromiseExt
> end
> end
>
>
> The DB connection leak was fixed. Memory usage was decreased, but not much.
Does the DB connection leak if you remove GC.start?
I never really know what GC.start would affect...
> So, my question is that is it a correct way to do cleanup unused resources
> in `protected_yield` method? and is there any better way to achieve it?
>
> Any suggestion is appreciated.
>
> Thanks.
I guess this should work, and I agree that even if `with_connection` works
properly, it's quite tedious to do it in every single callback.
Maybe we could provide a callback wrapper, so that we could do something
like this:
client = Client.new(:callback_wrapper =>
ActiveRecord::Base.connection_pool.method(with_connection))
client.get("/friends") do |response|
# ... would work as if under `with_connection`
end
What do you think? My concern is that there are already some random stuffs,
like `error_callback`. I didn't think too much and added it because I
would like to
monitor all errors without fiddling around with ErrorHandler. I am a
bit worried that
all this kind of stuffs would grow out of control. I am still not sure
if `error_callback`
would be a good idea, it just... works for me, and that's it.
The name could be quite confusing as well...
Cheers,