Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
3ba20c7f
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
3ba20c7f
编写于
11月 26, 2017
作者:
M
Matthew Draper
提交者:
GitHub
11月 26, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #31221 from matthewd/flush-idle-connections
Flush idle database connections
上级
4b2bbcf8
9027faff
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
129 addition
and
17 deletion
+129
-17
activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
...ve_record/connection_adapters/abstract/connection_pool.rb
+58
-16
activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
...lib/active_record/connection_adapters/abstract_adapter.rb
+8
-0
activerecord/lib/active_record/connection_handling.rb
activerecord/lib/active_record/connection_handling.rb
+1
-1
activerecord/lib/active_record/railtie.rb
activerecord/lib/active_record/railtie.rb
+9
-0
activerecord/test/cases/connection_pool_test.rb
activerecord/test/cases/connection_pool_test.rb
+47
-0
activerecord/test/cases/reaper_test.rb
activerecord/test/cases/reaper_test.rb
+6
-0
未找到文件。
activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
浏览文件 @
3ba20c7f
...
...
@@ -63,15 +63,13 @@ module ConnectionAdapters
# There are several connection-pooling-related options that you can add to
# your database connection configuration:
#
# * +pool+: number indicating size of connection pool (default 5)
# * +checkout_timeout+: number of seconds to block and wait for a connection
# before giving up and raising a timeout error (default 5 seconds).
# * +reaping_frequency+: frequency in seconds to periodically run the
# Reaper, which attempts to find and recover connections from dead
# threads, which can occur if a programmer forgets to close a
# connection at the end of a thread or a thread dies unexpectedly.
# Regardless of this setting, the Reaper will be invoked before every
# blocking wait. (Default +nil+, which means don't schedule the Reaper).
# * +pool+: maximum number of connections the pool may manage (default 5).
# * +idle_timeout+: number of seconds that a connection will be kept
# unused in the pool before it is automatically disconnected (default
# 300 seconds). Set this to zero to keep connections forever.
# * +checkout_timeout+: number of seconds to wait for a connection to
# become available before giving up and raising a timeout error (default
# 5 seconds).
#
#--
# Synchronization policy:
...
...
@@ -280,12 +278,12 @@ def internal_poll(timeout)
end
end
# Every +frequency+ seconds, the reaper will call +reap+
on +pool+.
#
A reaper instantiated with a +nil+ frequency will never reap the
# connection pool.
# Every +frequency+ seconds, the reaper will call +reap+
and +flush+ on
#
+pool+. A reaper instantiated with a zero frequency will never reap
#
the
connection pool.
#
# Configure the frequency by setting
"reaping_frequency" in your
#
database yaml file
.
# Configure the frequency by setting
+reaping_frequency+ in your database
#
yaml file (default 60 seconds)
.
class
Reaper
attr_reader
:pool
,
:frequency
...
...
@@ -295,11 +293,12 @@ def initialize(pool, frequency)
end
def
run
return
unless
frequency
return
unless
frequency
&&
frequency
>
0
Thread
.
new
(
frequency
,
pool
)
{
|
t
,
p
|
loop
do
sleep
t
p
.
reap
p
.
flush
end
}
end
...
...
@@ -323,6 +322,10 @@ def initialize(spec)
@spec
=
spec
@checkout_timeout
=
(
spec
.
config
[
:checkout_timeout
]
&&
spec
.
config
[
:checkout_timeout
].
to_f
)
||
5
if
@idle_timeout
=
spec
.
config
.
fetch
(
:idle_timeout
,
300
)
@idle_timeout
=
@idle_timeout
.
to_f
@idle_timeout
=
nil
if
@idle_timeout
<=
0
end
# default max pool size to 5
@size
=
(
spec
.
config
[
:pool
]
&&
spec
.
config
[
:pool
].
to_i
)
||
5
...
...
@@ -353,7 +356,10 @@ def initialize(spec)
@lock_thread
=
false
@reaper
=
Reaper
.
new
(
self
,
spec
.
config
[
:reaping_frequency
]
&&
spec
.
config
[
:reaping_frequency
].
to_f
)
# +reaping_frequency+ is configurable mostly for historical reasons, but it could
# also be useful if someone wants a very low +idle_timeout+.
reaping_frequency
=
spec
.
config
.
fetch
(
:reaping_frequency
,
60
)
@reaper
=
Reaper
.
new
(
self
,
reaping_frequency
&&
reaping_frequency
.
to_f
)
@reaper
.
run
end
...
...
@@ -587,6 +593,35 @@ def reap
end
end
# Disconnect all connections that have been idle for at least
# +minimum_idle+ seconds. Connections currently checked out, or that were
# checked in less than +minimum_idle+ seconds ago, are unaffected.
def
flush
(
minimum_idle
=
@idle_timeout
)
return
if
minimum_idle
.
nil?
idle_connections
=
synchronize
do
@connections
.
select
do
|
conn
|
!
conn
.
in_use?
&&
conn
.
seconds_idle
>=
minimum_idle
end
.
each
do
|
conn
|
conn
.
lease
@available
.
delete
conn
@connections
.
delete
conn
end
end
idle_connections
.
each
do
|
conn
|
conn
.
disconnect!
end
end
# Disconnect all currently idle connections. Connections currently checked
# out are unaffected.
def
flush!
reap
flush
(
-
1
)
end
def
num_waiting_in_queue
# :nodoc:
@available
.
num_waiting
end
...
...
@@ -956,6 +991,13 @@ def clear_all_connections!
connection_pool_list
.
each
(
&
:disconnect!
)
end
# Disconnects all currently idle connections.
#
# See ConnectionPool#flush! for details.
def
flush_idle_connections!
connection_pool_list
.
each
(
&
:flush!
)
end
# Locate the connection of the nearest super class. This can be an
# active or defined connection: if it is the latter, it will be
# opened and set as the active connection for the class it was defined
...
...
activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
浏览文件 @
3ba20c7f
...
...
@@ -105,6 +105,7 @@ def initialize(connection, logger = nil, config = {}) # :nodoc:
@logger
=
logger
@config
=
config
@pool
=
nil
@idle_since
=
Concurrent
.
monotonic_time
@schema_cache
=
SchemaCache
.
new
self
@quoted_column_names
,
@quoted_table_names
=
{},
{}
@visitor
=
arel_visitor
...
...
@@ -164,6 +165,7 @@ def expire
"Current thread:
#{
Thread
.
current
}
."
end
@idle_since
=
Concurrent
.
monotonic_time
@owner
=
nil
else
raise
ActiveRecordError
,
"Cannot expire connection, it is not currently leased."
...
...
@@ -183,6 +185,12 @@ def steal! # :nodoc:
end
end
# Seconds since this connection was returned to the pool
def
seconds_idle
# :nodoc:
return
0
if
in_use?
Concurrent
.
monotonic_time
-
@idle_since
end
def
unprepared_statement
old_prepared_statements
,
@prepared_statements
=
@prepared_statements
,
false
yield
...
...
activerecord/lib/active_record/connection_handling.rb
浏览文件 @
3ba20c7f
...
...
@@ -140,6 +140,6 @@ def clear_cache! # :nodoc:
end
delegate
:clear_active_connections!
,
:clear_reloadable_connections!
,
:clear_all_connections!
,
to: :connection_handler
:clear_all_connections!
,
:flush_idle_connections!
,
to: :connection_handler
end
end
activerecord/lib/active_record/railtie.rb
浏览文件 @
3ba20c7f
...
...
@@ -177,7 +177,16 @@ class Railtie < Rails::Railtie # :nodoc:
initializer
"active_record.clear_active_connections"
do
config
.
after_initialize
do
ActiveSupport
.
on_load
(
:active_record
)
do
# Ideally the application doesn't connect to the database during boot,
# but sometimes it does. In case it did, we want to empty out the
# connection pools so that a non-database-using process (e.g. a master
# process in a forking server model) doesn't retain a needless
# connection. If it was needed, the incremental cost of reestablishing
# this connection is trivial: the rest of the pool would need to be
# populated anyway.
clear_active_connections!
flush_idle_connections!
end
end
end
...
...
activerecord/test/cases/connection_pool_test.rb
浏览文件 @
3ba20c7f
...
...
@@ -156,6 +156,53 @@ def test_reap_inactive
@pool
.
connections
.
each
{
|
conn
|
conn
.
close
if
conn
.
in_use?
}
end
def
test_flush
idle_conn
=
@pool
.
checkout
recent_conn
=
@pool
.
checkout
active_conn
=
@pool
.
checkout
@pool
.
checkin
idle_conn
@pool
.
checkin
recent_conn
assert_equal
3
,
@pool
.
connections
.
length
def
idle_conn
.
seconds_idle
1000
end
@pool
.
flush
(
30
)
assert_equal
2
,
@pool
.
connections
.
length
assert_equal
[
recent_conn
,
active_conn
].
sort_by
(
&
:__id__
),
@pool
.
connections
.
sort_by
(
&
:__id__
)
ensure
@pool
.
checkin
active_conn
end
def
test_flush_bang
idle_conn
=
@pool
.
checkout
recent_conn
=
@pool
.
checkout
active_conn
=
@pool
.
checkout
_dead_conn
=
Thread
.
new
{
@pool
.
checkout
}.
join
@pool
.
checkin
idle_conn
@pool
.
checkin
recent_conn
assert_equal
4
,
@pool
.
connections
.
length
def
idle_conn
.
seconds_idle
1000
end
@pool
.
flush!
assert_equal
1
,
@pool
.
connections
.
length
assert_equal
[
active_conn
].
sort_by
(
&
:__id__
),
@pool
.
connections
.
sort_by
(
&
:__id__
)
ensure
@pool
.
checkin
active_conn
end
def
test_remove_connection
conn
=
@pool
.
checkout
assert
conn
.
in_use?
...
...
activerecord/test/cases/reaper_test.rb
浏览文件 @
3ba20c7f
...
...
@@ -18,6 +18,7 @@ def setup
class
FakePool
attr_reader
:reaped
attr_reader
:flushed
def
initialize
@reaped
=
false
...
...
@@ -26,6 +27,10 @@ def initialize
def
reap
@reaped
=
true
end
def
flush
@flushed
=
true
end
end
# A reaper with nil time should never reap connections
...
...
@@ -47,6 +52,7 @@ def test_some_time
Thread
.
pass
end
assert
fp
.
reaped
assert
fp
.
flushed
end
def
test_pool_has_reaper
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录