elixir - 如何防止繁琐的查询在 Postgrex 中超时?
问题描述
我正在运行查询并使用 Postgrex 将结果加载到 Stream 中,如下所示:
{:ok, host_pid} = Postgrex.start_link(hostname: "somewhere.hostname.io", username: "myuser", password: "mypass", database: "mydb")
Postgrex.transaction(host_pid, fn(conn) ->
# do query that takes 5 seconds
# with timeout set to be really big
query = Postgrex.prepare!(conn, "", "SELECT pg_sleep(5)", timeout: 50_000)
stream = Postgrex.stream(conn, query)
result_to_iodata = fn(%Postgrex.Result{rows: rows}) -> format_query_result(rows) end
Enum.into(stream, File.stream!("eg"), result_to_iodata)
end)
但我收到以下错误:
localhost$ mix run lib/MyPostgrexScript.exs
** (DBConnection.ConnectionError) connection not available and request was dropped
from queue after 2950ms. You can configure how long requests wait in the queue
using :queue_target and :queue_interval. See DBConnection.start_link/2 for more information
(db_connection) lib/db_connection.ex:836: DBConnection.transaction/3
lib/MyPostgrexScript.exs:3: MyPostgrexModule.sleep/0
(elixir) lib/code.ex:767: Code.require_file/2
(mix) lib/mix/tasks/run.ex:147: Mix.Tasks.Run.run/5
由于我想做繁琐的查询,这些查询肯定需要超过 2950 毫秒才能运行,我想知道如何配置 Postgrex 以让我的查询花费更多时间。我在https://hexdocs.pm/postgrex/Postgrex.html#transaction/3阅读了有关该:timeout
选项的信息,但我不确定如何包含它,或者它是否是我正在寻找的。
非常感谢任何指导,谢谢!
解决方案
我在https://hexdocs.pm/postgrex/Postgrex.html#transaction/3阅读了有关 :timeout 选项的信息, 但我不确定如何包含它,
像这样(见最后一行):
Postgrex.transaction(
host_pid,
fn(conn) ->
# do query that takes 5 seconds
# with timeout set to be really big
query = Postgrex.prepare!(conn, "", "SELECT pg_sleep(5)", timeout: 50_000)
stream = Postgrex.stream(conn, query)
result_to_iodata = fn(%Postgrex.Result{rows: rows}) ->
format_query_result(rows)
end
Enum.into(stream, File.stream!("eg"), result_to_iodata)
end,
timeout: 30_000 #30 seconds
)
每当 elixir 文档定义这样的函数时:
func_name(arg1, ...argN, opts \\ [] )
opts
是一个关键字列表,例如:
[{:a, 1}, {:b, 2}]
但是,如果关键字列表是函数调用中的最后一个参数,则关键字列表可以这样写:
func(arg1, arg2, a: 1, b: 2)
并且函数定义将接收三个参数
arg1, arg2, [{:a, 1}, {:b, 2}]
在任何情况下, :timeout 的默认值是:
:timeout - Transaction timeout (default: 15000);
错误说:
连接不可用,请求在 2950 毫秒后从队列中删除
因为2950 < 15000
:timeout 值似乎不是错误的根源。
错误消息继续:
连接不可用.... 您可以使用 :queue_target 和 :queue_interval 配置请求在队列中等待的时间。有关更多信息,请参见 DBConnection.start_link/2
这解释了如何配置这些超时:
在
config/<env>.exs
(<env>
开发、测试或产品在哪里):config :my_app, MyApp.Repo, adapter: Ecto.Adapters.Postgres, pool_size: 10, migration_timestamps: [type: :utc_datetime_usec], migration_lock: nil, queue_target: 5000
由于生产中的错误数量增加,这是我们最近必须做的事情。
还有,
处理请求是通过队列完成的。当 DBConnection 启动时,有两个相关的选项来控制队列:
:queue_target in milliseconds, defaults to 50ms :queue_interval in milliseconds, defaults to 1000ms
我们的目标是最多等待 :queue_target 连接。如果在 :queue_interval 期间检出的所有连接都超过 :queue_target,那么我们将 :queue_target 加倍。如果签出连接的时间比新目标要长,那么我们就开始丢弃消息。
例如,默认情况下我们的目标是 50 毫秒。如果所有连接检出时间超过 50 毫秒一整秒,我们将目标加倍到 100 毫秒,如果检出时间超过新限制,我们开始丢弃消息。
这使我们能够更好地规划过载,因为我们可以在请求发送到数据库之前拒绝请求,否则会增加数据库的负担,使过载变得更糟。
但是,如果您还没有触及这些默认值,那么我想知道为什么您会
2950ms
在错误消息中看到而不是接近 50 毫秒或 1000 毫秒。
推荐阅读
- linux - Jenkins 服务无法在 Oracle Linux 上使用 SDKMan Java 启动
- java - ArrayList - 计算我列出的同一个对象是否准确 2 次,如果:附加到“tempFinalFilterSearchList”
- javascript - 表单提交后如何添加成功通知
- reactjs - 如何在 react 中使用 axios 处理 401 和 403 错误?
- django - 使用 asgi 时尚未加载 Django 应用程序
- javascript - 如何使用 typescript 和 webpack 创建单页 Web 应用程序?
- python - Python Bokeh:ColumnDataSource 中的滑块回调未更新
- java - AWS MQTT Websocket 问题
- c++ - 如何使用 Visual Studio CppUnitTestFramework 初始化测试变量
- angular - 使用时间戳字段创建 Angular Pipe 过滤器