Repository navigation
in_tail: Add opt-in worker-thread parsing - #5529
Conversation
d384790 to
1501747
Compare
|
dfb7c4c to
26ad50d
Compare
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
…on order Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
ea39f47 to
73bf91e
Compare
Signed-off-by: Takuro Ashie <ashie@clear-code.com>
**Which issue(s) this PR fixes**: None. **What this PR does / why we need it**: The compatibility test can race with the stat watcher: after writing the file, the watcher may call on_notify before the test's explicit call. That consumes the test subclass's one-time false response, so the read position has already advanced when the assertion runs. Disable the stat watcher in this test so its explicit notifications control the call order. The failure reported by PR #5529 (GitHub Actions run 39210929391) is this test-ordering instability, not a failure caused by the multithreading implementation. The test uses the default synchronous mode, and this stabilizes a compatibility test introduced by a separate refactoring. **Docs Changes**: None. **Release Note**: None; this only makes a test deterministic. Assisted-by: LLM GPT-6 Luna (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
|
For the CI failure, it doesn't seem caused by this change. |
Watson1978
left a comment
There was a problem hiding this comment.
Reviewed at 16c2ae6. I ran the worker path with extra scripts on Linux (Ruby 4.0.7) and reproduced each issue below. The inline comments have the details and the numbers. The scripts are here: https://gist.github.com/Watson1978/97704fc8a8c66f1d411d89c00aeeb5e4
Must fix before merge
detach_watchercan submit a batch insidetw.detachafter the deferral decision, and the completion then corrupts another file's position entry (in_tail.rb:554).- A file that waited for queue capacity stops reading after its retried batch completes (io_handler.rb:288).
- An exception in the completion path kills the process, and the handler stays pending afterwards (worker_pool.rb:271, io_handler.rb:189).
Should fix
- A detached watcher whose batch failed to emit is never retried or closed, and the final close cannot close a pending watcher (tail_watcher.rb:134, tail_watcher.rb:77).
- The position file is never closed in worker mode (in_tail.rb:349).
- Shutdown waits for
SHUTDOWN_TIMEOUTwhenever a file is not at EOF (in_tail.rb:835). - A result published during
joinis dropped when the completion watcher is detached (in_tail.rb:348). - A worker that does not finish by the join timeout outlives
terminate(in_tail.rb:747).
The last four should items are one shutdown sequence: stop the workers, process the remaining results, close the watched files, then close the position file. They may be easier to fix together. The orphaned watcher at tail_watcher.rb:134 is a runtime path and needs its own fix.
Preserve position entries until batches submitted during detach complete, and resume file reads after a queue-saturation retry. Recover completion errors without leaving handlers pending or stopping the event loop. Serialize the shutdown handover, collect results after joining workers, and terminate workers that exceed the join timeout. Close detached file handles and the position file, and avoid waiting for throttled files to reach EOF. Drain wakeup notifications and complete NullIOHandler methods. Add regression coverage for the review findings in PR #5529 while preserving synchronous retry behavior. Assisted-by: LLM GPT-6 (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Watson1978
left a comment
There was a problem hiding this comment.
Re-reviewed at 9f91db5. I re-ran the reproduction scripts from the first round against this commit and all of the original reproduction cases now pass: the batch submitted by detach keeps its position entry through compaction, the retried batch resumes reading (1200 of 1200 records), the completion path survives a failing position write, the failed-emit watcher is closed right away, the position file is closed, shutdown no longer incurs the full drain timeout for a throttled backlog, no result was dropped during join in 15 shutdowns, and no worker thread survives terminate. Thanks for the thorough fix.
One case of the position corruption is still open with follow_inodes true, so I am keeping the request for changes for that alone. There is also one flaky test. Details inline. The new reproduction is in the same gist: https://gist.github.com/Watson1978/97704fc8a8c66f1d411d89c00aeeb5e4
Keep position entries for detached worker watchers and deferred unwatch targets during follow_inodes refreshes. Otherwise compaction can remove an entry still used by an in-flight batch and its completion can overwrite another file position. Cover both tracking paths and verify that the next refresh removes the entry once processing finishes. Refs: #5529 (comment) Assisted-by: LLM GPT-6 (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Start with an empty file and install the failing worker callback before appending the record and notifying its watcher. This prevents startup parsing from completing the first batch before the failure is injected. Refs: #5529 (comment) Assisted-by: LLM GPT-6 (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
Watson1978
left a comment
There was a problem hiding this comment.
Reviewed 8dfb08b.
b08383e closes the follow_inodes case. test_follow_inodes_refresh_unwatches_pending_detached.rb from the gist passes now. The new test_follow_inodes_refresh_preserves_worker_draining_position_entries fails on 9f91db5 and passes on this head for both data variants. 8dfb08b makes test_worker_parse_error_retries_synchronously deterministic, 5 of 5 runs here. test/plugin/test_in_tail.rb and the in_tail unit tests pass locally on Linux. The failing Windows job is test_without_event_time(TestFluentCat), which is unrelated to this PR.
One part of the earlier MUST 2 is still open, see the inline comment. The new commits did not introduce it. It is already on 9f91db5, and my earlier run of test_queue_saturation_stall.rb passed only by timing. With the watch timer off that test still fails about one run in three on both commits. I added test_parked_batch_loses_notification.rb to the gist. It reproduces the case deterministically without inotify.
https://gist.github.com/Watson1978/97704fc8a8c66f1d411d89c00aeeb5e4
Remember the read continuation when a notification arrives while a rejected batch is parked. Even if the initial read reached EOF, successful worker completion must read any data appended during the wait. Use pending_read_more rather than notify_pending so a failed emit does not cause repeated retries. Add unit coverage and extend queue saturation tests with a partial write followed by another notification, checking that all records arrive before shutdown in both notification orders. Refs: #5529 (comment) Assisted-by: LLM GPT-6 (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
|
Thanks for rechecking these cases. The remaining parked-batch issue |
Wait for both watchers to finish asynchronous completion before checking their positions. Acknowledgment releases the pool task before its position is updated, so an empty pool and only the first watcher being idle can expose the second watcher before its position is committed. This fixes the Windows Ruby 3.3 CI race without changing production code. Assisted-by: LLM GPT-6 (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
|
I'll fix the failed test: https://github.com/fluent/fluentd/actions/runs/39745003992/job/119711197908?pr=5529 |
|
Thanks! |
**Which issue(s) this PR fixes**: None. **What this PR does / why we need it**: The compatibility test can race with the stat watcher: after writing the file, the watcher may call on_notify before the test's explicit call. That consumes the test subclass's one-time false response, so the read position has already advanced when the assertion runs. Disable the stat watcher in this test so its explicit notifications control the call order. The failure reported by PR #5529 (GitHub Actions run 39210929391) is this test-ordering instability, not a failure caused by the multithreading implementation. The test uses the default synchronous mode, and this stabilizes a compatibility test introduced by a separate refactoring. **Docs Changes**: None. **Release Note**: None; this only makes a test deterministic. Assisted-by: LLM GPT-6 Luna (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com>
**Which issue(s) this PR fixes**: None. **What this PR does / why we need it**: The compatibility test can race with the stat watcher: after writing the file, the watcher may call on_notify before the test's explicit call. That consumes the test subclass's one-time false response, so the read position has already advanced when the assertion runs. Disable the stat watcher in this test so its explicit notifications control the call order. The failure reported by PR #5529 (GitHub Actions run 39210929391) is this test-ordering instability, not a failure caused by the multithreading implementation. The test uses the default synchronous mode, and this stabilizes a compatibility test introduced by a separate refactoring. **Docs Changes**: None. **Release Note**: None; this only makes a test deterministic. Assisted-by: LLM GPT-6 Luna (OpenAI) --------- Signed-off-by: Takuro Ashie <ashie@clear-code.com>
…est (#5565) (#5571) **Which issue(s) this PR fixes**: Backport #5565 None. **What this PR does / why we need it**: The compatibility test can race with the stat watcher: after writing the file, the watcher may call on_notify before the test's explicit call. That consumes the test subclass's one-time false response, so the read position has already advanced when the assertion runs. Disable the stat watcher in this test so its explicit notifications control the call order. The failure reported by PR #5529 (GitHub Actions run 39210929391) is this test-ordering instability, not a failure caused by the multithreading implementation. The test uses the default synchronous mode, and this stabilizes a compatibility test introduced by a separate refactoring. **Docs Changes**: None. **Release Note**: None; this only makes a test deterministic. Assisted-by: LLM GPT-6 Luna (OpenAI) Signed-off-by: Takuro Ashie <ashie@clear-code.com> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Takuro Ashie <ashie@clear-code.com>
Which issue(s) this PR fixes:
None
What this PR does / why we need it:
(This PR depends on #5527 and includes its commits.)
This PR adds opt-in worker-thread parsing to
in_tail. Thedefault remains synchronous (
num_threads = 1), settingnum_threadsto 2 or more enables parsing on worker threadswhen the configured parser and hooks are supported.
Parsing uses worker-specific parser instances. Event emission
and position updates remain on the event loop, and processing
for each file stays serialized. Unsupported parser
configurations and overridden compatibility hooks continue
through the synchronous path. The worker pool is bounded and
handles asynchronous completion, queue saturation, rotation,
and shutdown.
The goal is to reduce delays to other files and watcher
callbacks while a large file is being processed. In an
exploratory local Test Driver measurement, while reading an
80 MiB JSONL file with a 1 MiB/s per-file read limit, median
probe-file latency was about 48 ms with synchronous parsing
and about 1 ms with four workers. The result was similar with
the StatWatcher enabled or disabled. This is a result for
that specific setup, not a general performance guarantee. If
all workers are occupied, tasks can still wait; this change
does not guarantee a latency bound or claim a general
throughput improvement.
Docs Changes:
Updated the
num_threadsconfiguration description.fluent/fluentd-docs-gitbook#716
Release Note:
Add opt-in worker-thread parsing to
in_tailvianum_threads. The default remains synchronous.Assisted-by: GPT-6.1 Sol (OpenAI)