out_forward: unacknowledged chunks are resent forever with heartbeat_type none, ignoring retry limits and secondary
メンテナーはふだん 1 日以内に返信
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 74/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- ruby
調査の方向性
Start with lib/fluent/plugin/out_forward.rb around ack_check and rollback_write, then read lib/fluent/plugin/out_forward/ack_handler.rb around collect_response. Trace how ACK timeouts and closed connections affect retry state when heartbeat_type none is used. Add coverage for the reproduced configuration and verify failed acknowledgments honor the retry limits and secondary behavior.
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
With require_ack_response true and heartbeat_type none, a chunk that the destination never acknowledges is resent forever. retry_timeout, retry_max_times and <secondary> never apply.
When the ACK times out or the destination closes the connection, ack_check calls rollback_write(chunk_id, update_retry: false) (lib/fluent/plugin/out_forward.rb:547). This puts the chunk back to the queue without starting a retry state, so the next flush sends it again at once. With the default heartbeat_type transport, node&.disable! on line 546 makes the next write raise NoNodesAvailable, and that starts the retry state. NoneHeartbeatNode#available? always returns true, so heartbeat_type none never reaches that path.
A destination that rejects a chunk is one way to hit this. in_forward drops a chunk larger than chunk_size_limit and sends no ACK.
To Reproduce
- Save the configuration below as
fluentd.conf. - Run
fluentd -c fluentd.conffor about 40 seconds and stop it. - Count the log lines and the files in the secondary directory.
$ grep -c "larger than 'chunk_size_limit', dropped" fluentd.log
66
$ grep -c "destination node closed the connection" fluentd.log
66
$ find /tmp/fluentd-secondary -type f | wc -l
0
sample creates one chunk per second, but the destination dropped 66 chunks in about 37 seconds. The same chunks were sent again and again. Nothing was written to the secondary although retry_timeout is 10 seconds. The only failed to flush the buffer line came at shutdown, after the destination had stopped (Errno::ECONNREFUSED).
Without deny_keepalive true, the destination keeps the connection open and the ACK times out instead. Adding ack_response_timeout 3s to <match> makes this quick. The result is the same: 45 no response from node warnings, no retry and no secondary file in about 37 seconds.
With the default heartbeat_type transport (remove the heartbeat_type none line), the retry state starts and the chunks go to the secondary (retry succeeded by secondary).
Expected behavior
A chunk that is never acknowledged follows the retry settings, as it does with heartbeat_type transport or when the write raises an error. It should be retried with backoff, go to <secondary> after retry_secondary_threshold, and stop after retry_timeout or retry_max_times.
Your Environment
- Fluentd version: 1.20.1 (master at 73976761)
- Package version: none (git checkout)
- Operating system: CachyOS
- Kernel version: 7.3.1-1-cachyos
- Ruby: 4.0.9
Your Configuration
<source>
@type sample
tag test
rate 1
size 1
</source>
<match test>
@type forward
require_ack_response true
heartbeat_type none
<server>
host 127.0.0.1
port 24411
</server>
<buffer>
flush_interval 1s
retry_timeout 10s
retry_max_times 2
</buffer>
<secondary>
@type secondary_file
directory /tmp/fluentd-secondary
</secondary>
</match>
# The destination. It drops every chunk and closes the connection.
<source>
@type forward
@label @IN
bind 127.0.0.1
port 24411
chunk_size_limit 10
deny_keepalive true
</source>
<label @IN>
<match **>
@type null
</match>
</label>
Your Error Log
2026-11-09 14:23:36 +0900 [warn]: #0 Input chunk size is larger than 'chunk_size_limit', dropped: tag="test" host="127.0.0.1" limit=10 size=120
2026-11-09 14:23:36 +0900 [warn]: #0 destination node closed the connection. regard it as unavailable. host="127.0.0.1" port=24411
2026-11-09 14:23:37 +0900 [warn]: #0 Input chunk size is larger than 'chunk_size_limit', dropped: tag="test" host="127.0.0.1" limit=10 size=120
2026-11-09 14:23:37 +0900 [warn]: #0 destination node closed the connection. regard it as unavailable. host="127.0.0.1" port=24411
(the same pair repeats until shutdown)
Additional context
The ACK timeout path in AckHandler#collect_response (lib/fluent/plugin/out_forward/ack_handler.rb:53) also ends in the same rollback_write(..., update_retry: false). #5607 sends a connection closed with FIN (where recv returns nil) to this path too. Today a FIN close raises NoMethodError and the chunk waits for the delayed commit timeout, which does update the retry state.
- 主要言語
- Ruby
- スター
- 13.6k
- フォーク
- 1.4k
- 平均マージ
- 16時間 41分
- マージ済み PR(30日)
- 70
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
fluent/fluentd のほかの issue
-
bug
難易度 4/5 3〜5日 初心者へのやさしさ 42/100
メンテナーはふだん 1 日以内に返信
-
bug enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
fluent/fluentd#5494 · コメント 2 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
BufferChunkOverflowError inside @ERROR loops forever - no buffer parameter can stop it再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープンbug
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
fluent/fluentd#5462 · コメント 8 件 ·
メンテナーはふだん 1 日以内に返信
-
<system> umask` / `--umask` is not applied to worker-created files under a foreground supervisor再び着手できるかも @mbmtbtbc が 118 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンenhancement
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
fluent/fluentd#5435 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 25/100
fluent/fluentd#5216 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
metanorma/metanorma-cli#494 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
メンテナーはふだん 1 日以内に返信