A label looked up at runtime during a graceful reload can keep dropping the events of a tag
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 42/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- ruby
- Ambito
- backend, distributed-systems
Direzione di ricerca
Start with plugin_helper/event_emitter.rb and engine.rb to trace how event_emitter_router selects a label during Engine#reload_config; then read event_router.rb and agent.rb for match caching and rule setup. Use the reproduction script in the issue to confirm the lost events during reload and after it. Done means events reach the label belonging to their configuration through graceful reload without leaving tags cached as unmatched.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
During a graceful reload (Engine#reload_config), a plugin of the old configuration that looks up a label with event_emitter_router while it runs sends its events to that label of the new configuration. If they come before the new <label> gets its <match>, they are dropped with "no patterns matched". After that, the new configuration drops its own events of that tag to that label too, until the next reload, or until 1,024 other tags push the tag out of the MatchCache.
Two things cause this (line numbers of v1.20.1, and master has the same code):
event_emitter_router(label_name)looks up the label inFluent::Engine.root_agent(plugin_helper/event_emitter.rb:62-67).Engine#reload_configmakes the new configurationFluent::Engine.root_agentbefore it configures it (engine.rb:195, 197), and the old inputs keep emitting untilstop_phase(old_agent)(engine.rb:213). So the old plugins send to the labels of the new configuration, which are not configured or started yet.EventRouterkeeps the result of matching a tag in itsMatchCache, includingNoMatchMatch(event_router.rb:134).add_ruledoes not clear it (event_router.rb:84-86). So once an event of a tag arrives beforeAgent#add_matchadds the<match>(agent.rb:143), the tag stays unmatched in the new configuration, until theMatchCachedrops it after 1,024 other tags.
The plugins that look up the label while they run cause this, such as fluent-plugin-rewrite-tag-filter (the label of a rule) and fluent-plugin-concat (timeout_label). relabel and @label look up the label once in configure, so they do not cause it. But once the tag is unmatched in the new label, the events that they send there with that tag are dropped too.
To Reproduce
This script needs no plugin other than Fluentd. It uses the test helpers of Fluentd, so it needs test-unit too, for example with this Gemfile and bundle exec ruby repro.rb:
source "https://rubygems.org"
gem "fluentd", "1.20.1"
gem "test-unit"
The output label_at_runtime looks up its label for each event stream, as the plugins above do. The script emits one event from the old configuration while the new <label @L> is configured, before its <match> is added. The hook on Agent#add_match only makes this timing certain. Then it emits 5 events into the new configuration.
require "fluent/version"
require "fluent/test"
require "fluent/plugin/output"
Fluent::Test.setup
# Looks up the label for each event stream, as some plugins do.
class LabelAtRuntimeOutput < Fluent::Plugin::Output
Fluent::Plugin.register_output("label_at_runtime", self)
helpers :event_emitter
config_param :to, :string
def process(tag, es)
event_emitter_router(@to).emit_stream("#{tag}.out", es)
end
end
class CountOutput < Fluent::Plugin::Output
Fluent::Plugin.register_output("count", self)
def self.events; @events ||= []; end
def process(tag, es)
es.each { |_time, record| self.class.events << record["message"] }
end
end
def conf
Fluent::Config.parse(<<~CONF, "(test)", "(test_dir)", syntax: :v1)
<match t>
@type label_at_runtime
to @L
</match>
<label @L>
<match **>
@type count
</match>
</label>
CONF
end
Fluent::Engine.run_configure(conf)
Fluent::Engine.root_agent.start
$old_output = Fluent::Engine.root_agent.outputs.find { |o| o.is_a?(LabelAtRuntimeOutput) }
# The old configuration emits one event while the new <label @L> is configured, before its <match> is added.
module EmitDuringReload
def add_match(type, pattern, conf)
if @context == "@L" && !$emitted && !ENV["NO_EVENT_DURING_RELOAD"]
$emitted = true
$old_output.process("t", Fluent::OneEventStream.new(Fluent::EventTime.now, { "message" => "during" }))
end
super
end
end
Fluent::Agent.prepend(EmitDuringReload)
Fluent::Engine.reload_config(conf)
5.times { |i| Fluent::Engine.root_agent.event_router.emit("t", Fluent::EventTime.now, { "message" => "after#{i}" }) }
puts "Fluentd #{Fluent::VERSION}: #{CountOutput.events.inspect}"
It prints Fluentd 1.20.1: []. The event during the reload and all the 5 events after it are lost. With NO_EVENT_DURING_RELOAD=1, it prints the 5 events.
Expected behavior
The events that a plugin sends to a label go to that label of the configuration that the plugin belongs to, as with relabel, and the new configuration routes its own events.
Graceful reload is no longer the main way to restart (#3415, #4624), but it is still used with the RPC /api/config.gracefulReload, with SIGUSR2 to a worker, and on Windows. If this is not going to be fixed, it would help to document it as a limitation of graceful reload.
Your Environment
- Fluentd version: 1.20.1 (also 1.19.3)
- Ruby version: 4.0.9
- Operating system: Linux
Your Configuration
The configuration is in the script above.
Your Error Log
[warn]: no patterns matched tag="t.out"
Additional context
-
I tried two changes with the script on 1.20.1:
event_emitter_routerlooks up the label in the root agent of the plugin's owncontext_router, whichAgent#add_matchsets beforeconfigure(agent.rb:131). All the 6 events arrive, and the event during the reload goes to the old@L.add_ruleclears theMatchCache. The 5 events after the reload arrive, but the event during the reload is still lost. Another window stays too, as #175 describes: an event that reaches a new output after the new configuration is configured, but before it starts, is discarded by a memory buffer when it starts.
The comment at engine.rb:193-194 says that
@root_agentis replaced first forevent_emitter_router, so that the new plugins find the new labels inconfigure. The first change keeps that, ascontext_routeris set beforeconfigure. -
fluent/fluent-plugin-rewrite-tag-filter#175 analyzed this in detail and works around it in that plugin. It measured that 5 of 20 graceful reloads dropped a tag on 1.20.1. We'd rather not work around it in each plugin, as the workaround depends on how Fluentd shuts down the plugins.
-
#175 also describes a problem that a fix in Fluentd needs to handle: an event of the old configuration that comes late in its shutdown can reach a plugin that has already dropped its router in
after_shutdown. -
#2259 is another case of lost events at graceful shutdown, with a different cause.
- Lingua principale
- Ruby
- Stelle
- 13.6k
- Fork
- 1.4k
- Merge medio
- 1g 1h
- PR unite (30g)
- 61
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di fluent/fluentd
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
in_tcp, in_syslog: a non-ASCII delimiter closes the connection with Encoding::CompatibilityErrorApertabug
Difficoltà 3/5 1-2 giorni Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
bug enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
fluent/fluentd#5494 · 2 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
BufferChunkOverflowError inside @ERROR loops forever - no buffer parameter can stop itForse di nuovo libera Una pull request per questa issue è stata chiusa senza essere unita. Apertabug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
fluent/fluentd#5462 · 8 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
<system> umask` / `--umask` is not applied to worker-created files under a foreground supervisorForse di nuovo libera @mbmtbtbc l’ha presa 114 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
Difficoltà 4/5 3-5 giorni Idoneità per principianti 45/100
fluent/fluentd#5435 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di fluent/fluentd
Issue simili
-
Visual COBOL: missing 11.0 and 12.0, and 9.0 date differs from Rocket Software's lifecycle pageAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
endoflife-date/endoflife.date#11561 ·
I maintainer di solito rispondono entro 1 giorno
-
internal
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
Kong/developer.konghq.com#7954 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
Fresh comstockpostproc install fails on import: PyAthena 4.x requires SQLAlchemy 2 (AttributeError: sqlalchemy.types has no attribute DOUBLE)Forse già presa @JanghyunJK l’ha presa oggi. Apertapostprocessing
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
NatLabRockies/ComStock#473 ·
-
No Ruby in CIApertaarea: core area: devops lane: strong-agent priority: P2 roadmap size: S type: removal type: task
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
arminazimi/slipway#1216 ·
I maintainer di solito rispondono entro 1 giorno