-
Notifications
You must be signed in to change notification settings - Fork 77
Ensure log streams are flushed before garbage collection when using GCFlushedOutputStream
by switching to Cleaner
#388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks right though I am not familiar with the API.
I finally had a bit of time to test this. As far as I can see, The only way I could figure out to make
I then went back and tested the same test changes without this PR.
So, here are my key takeaways:
|
…Stream and GCFlushedOutputStream
GCFlushedOutputStream
work as intended by switching to Cleaner
GCFlushedOutputStream
by switching to Cleaner
switch (variant) { | ||
case DelayedAutoFlushOnly -> { | ||
// TODO: It would be better to wait for `DelayBufferedOutputStream.flushBuffer` to run exactly once. | ||
Thread.sleep(DelayBufferedOutputStream.Tuning.DEFAULT.minRecurrencePeriod * 3); | ||
} | ||
case GcFlushOnly -> { | ||
listener = null; | ||
// Sleeping and calling `System.gc` more than once seem to be necessary for Cleaner to run reliably. | ||
for (int i = 0; i < 3; i++) { | ||
System.gc(); | ||
Thread.sleep(1000); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that in real-world scenarios, where we do not nicely wait after writing each individual line, there is no guarantee of ordering with GCFlushedOutputStream
or DelayBufferedOutputStream
, and so you can end up with lines in unexpected orders.
assumeThat("Skipping BufferedBuildListener-specific tests because listener is " + overall, | ||
overall, instanceOf(BufferedBuildListener.class)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unnecessary, i.e. the new tests pass against pipeline-cloudwatch-logs
, but it seemed somewhat pointless to run tests that configure implementation details of BufferedBuildListener
against unrelated listener implementations.
If desired, we could instead move the new tests down into FileLogStorageTest
add make the tests here more generic. For example, we'd just have one test that checks that if you write a line and do not flush, the line gets written if you wait for a few seconds. pipeline-cloudwatch-logs
would still pass this test without waiting because it doesn't buffer more than a single line. FileLogStorage
would only pass after a few seconds due to DelayBufferedOutputStream
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you write a line and do not flush, the line gets written if you wait for a few seconds
Fine, I guess, but no one should rely on that; remote code printing to a TaskListener
is expected to flush explicitly.
Go ahead if you think nothing would be harmed. I only dimly remember the original justification. These days I am mostly working in |
private static final Cleaner CLEANER = Cleaner.create( | ||
new NamingThreadFactory(new DaemonThreadFactory(), GCFlushedOutputStream.class.getName() + ".CLEANER")); | ||
|
||
static boolean DISABLED = Boolean.getBoolean(GCFlushedOutputStream.class.getName() + ".DISABLED"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use SystemProperties
generally. Also prefer positive to negative sense, e.g.
static final boolean ENABLED = SystemProperties.getBoolean(XXX + ".enabled", true);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I think
See #83 (comment). Alternative to #387.
Testing done
See new automated tests. I ran them manually against
pipeline-cloudwatch-logs
, which does not use the classes changed by this PR and so is unaffected (the new tests are currently skipped, but they pass even if not skipped), as well as CloudBees Pipeline Explorer, which passes with the new tests.Submitter checklist