Repository navigation
Start the sender in start(), not in the constructor - #44
Merged
Merged
Conversation
An appender that never starts must leave no sender thread behind, a second start() must not register a second shutdown hook, the batch interval must only reschedule a running sender, and a restarted appender must send on its schedule again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
start() returns early when the appender is already started, registers the shutdown hook and then creates the sender with the configured interval; the constructor no longer starts a thread. setBatchInterval() only reschedules a running sender, so logback's configuration before start() just stores the value and a stopped appender no longer throws RejectedExecutionException. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The constructor creates the scheduled sender, so every
LogtailAppenderobject runs alogtail-appenderthread from the moment it exists, whether or notstart()ever runs.stop()is the only thing that shuts that thread down, and since 0.3.8 it returns early for an appender that was never started. So an appender whose start fails, whose logback config has an error, or that code builds and never starts keeps a daemon thread waking every batch interval, and in an app server that thread keeps the undeployed webapp in memory. It showed up in Tomcat as "appears to have started a thread named [logtail-appender] but has failed to stop it" when an appender's start failed during shutdown;new LogtailAppender(); stop();is enough to reproduce it.start()does the starting: it returns early when the appender is already started (asstop()does when it is not), registers the shutdown hook and then creates the sender with the configured batch interval. Registering the hook first means astart()that fails there, for example while the JVM is already shutting down, creates no thread either.setBatchInterval()stores the interval and reschedules the sender only when the appender is started. Beforestart(), which is when logback's configuration sets it, there is nothing to reschedule; afterstop()it used to throwRejectedExecutionExceptionon the shut-down executor.start()no longer registers a second shutdown hook thatstop()could not remove, and an appender started again afterstop()gets a sender again instead of only sending when a batch fills up.The first commit only adds
LogtailAppenderLifecycleTestand is expected to fail on CI with four of its six tests; the two interval tests pin behaviour that already works.🤖 Generated with Claude Code