Silent self-deadlock with SetMaxOpenConns(1) when insert hooks use the pool
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 52/100
調査の方向性
Start by running the provided Go reproduction with MaxOpenConns(1), then compare the client.Insert and InsertTx paths with hook and middleware execution. Review the SetMaxOpenConns guidance and relevant hook documentation before choosing a scoped direction. Done should include coverage for the deadlock scenario and a clear user-facing explanation or failure mode.
索引モデルが issue の本文から書いたものです。
説明
Note: this issue was written by Claude (an AI assistant) from an investigation it ran, and @bgentry reviewed it and okayed filing it. @brandur, could you take a look?
The riversqlite package docs recommend dbPool.SetMaxOpenConns(1) to avoid SQLITE_BUSY errors from River's parallel internal operations. With that setting, two fairly natural patterns hang silently until the context deadline, or forever if the context has none. database/sql has no way to detect the self-deadlock, so the user sees no error, only a stuck insert.
1. A hook or middleware that uses the pool during a non-transactional insert. client.Insert opens its own transaction, which takes the pool's only connection, and runs insert hooks and middleware inside it. Hooks and middleware don't receive that transaction, so a hook that needs the database has to go through the pool. It then waits for the connection its own insert is holding.
2. client.Insert (instead of InsertTx) while the app holds an open transaction on the same pool. River's BEGIN waits for the connection that the app's transaction holds.
Reproduction against master (9573203e) with riversqlite and modernc.org/sqlite, a file database in WAL mode:
type poolHook struct {
river.HookDefaults
db *sql.DB
}
func (h *poolHook) InsertBegin(ctx context.Context, params *rivertype.JobInsertParams) error {
_, err := h.db.ExecContext(ctx, "SELECT 1")
return err
}
// db.SetMaxOpenConns(n); client configured with Hooks: []rivertype.Hook{&poolHook{db: db}}
ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
_, err := client.Insert(ctx, someArgs{}, nil)
MaxOpenConns(1) hook uses pool during client.Insert: err=context deadline exceeded after 2.001s
MaxOpenConns(4) hook uses pool during client.Insert: err=<nil> after 1ms
MaxOpenConns(1) client.Insert while app holds a tx: err=error beginning transaction: context deadline exceeded after 2s
This isn't strictly SQLite-specific. Any database/sql or pgx pool capped at one connection behaves the same way. It mostly bites SQLite users in practice, because that's where the docs recommend a single connection.
Some possible directions, not mutually exclusive:
- Document it. Next to the
SetMaxOpenConns(1)advice, and in the hooks/middleware docs, explain that hook and middleware code runs while River holds a connection, and that app code inside its own transaction should useInsertTx. - Fail fast on re-entry. River could mark the context while it holds its own insert transaction, so a re-entrant River call on the same client returns a clear error instead of hanging. This wouldn't catch a hook calling
db.Execdirectly on the raw pool, but it would cover River-level re-entry. - Let hooks and middleware use River's transaction. Expose the insert's transaction to them, for example through the context, so they can do database work without a second connection. This is a bigger API change.
My suggestion is (1) plus (2), with (3) as a possible follow-up.
- 主要言語
- Go
- スター
- 5.7k
- フォーク
- 187
- 平均マージ
- 1日 11時間
- マージ済み PR(30日)
- 63
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
riverqueue/river のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
riverqueue/river#1454 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
AddWorkerSafely leaves registered kinds after an alias collision対応中かも @flcrom が 3 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 25/100
riverqueue/river#1433 ·
メンテナーはふだん 1 日以内に返信
-
Remote JobCancel() can be silently lost while the notifier is reconnecting (no durable-poll fallback)対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 5/5 1週間以上 初心者へのやさしさ 45/100
riverqueue/river#1358 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
riverqueue/river#1258 · コメント 7 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
riverqueue/river#1225 · コメント 14 件 ·
メンテナーはふだん 1 日以内に返信
riverqueue/river の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
evilmartians/lefthook#1588 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
kubernetes-sigs/kubebuilder#6084 ·
メンテナーはふだん 3 日以内に返信
-
agent-research-recommend agent-review-finding chore
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
jordansmall/spindrift#4821 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
area:web
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
praetorianer777/GoTome#178 ·
メンテナーはふだん 1 日以内に返信