diff --git a/EonaCat.LogStack/EonaCat.LogStack.csproj b/EonaCat.LogStack/EonaCat.LogStack.csproj
index 7ccef21..d4a1243 100644
--- a/EonaCat.LogStack/EonaCat.LogStack.csproj
+++ b/EonaCat.LogStack/EonaCat.LogStack.csproj
@@ -14,7 +14,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
EonaCat (Jeroen Saey)
EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey
- 0.1.9
+ 0.2.0
README.md
True
LICENSE
@@ -25,7 +25,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
- 0.1.9+{chash:10}.{c:ymd}
+ 0.2.0+{chash:10}.{c:ymd}
true
true
v[0-9]*
@@ -36,7 +36,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
- 0.1.9
+ 0.2.0
EonaCat.LogStack
EonaCat.LogStack
https://git.saey.me/EonaCat/EonaCat.LogStack
diff --git a/EonaCat.LogStack/EonaCatLogger.cs b/EonaCat.LogStack/EonaCatLogger.cs
index 0f4139d..ce918dd 100644
--- a/EonaCat.LogStack/EonaCatLogger.cs
+++ b/EonaCat.LogStack/EonaCatLogger.cs
@@ -718,54 +718,93 @@ namespace EonaCat.LogStack
// Drain and stop the async channel pipeline if active
if (_asyncChannel != null)
{
- // Flush all logs from flows first to ensure they're written to disk
- await FlushAsync().ConfigureAwait(false);
-
- // Complete the channel - no more writes allowed
+ // Complete the channel immediately - no more writes allowed
_asyncChannel.Writer.TryComplete();
if (_asyncConsumer != null)
{
try
{
- // Wait for the consumer task to finish draining the channel
- // Use a generous timeout (30 seconds) since we're dealing with legitimate I/O
- // but prevent infinite hangs if something is truly deadlocked
- using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
+ // Give the consumer a very short window (1 second) to finish naturally
+ // If it doesn't complete in time, we proceed anyway to not block app shutdown
+ // This is critical for ensuring the logger never blocks application exit
+ using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
{
try
{
await _asyncConsumer.ConfigureAwait(false);
}
catch (OperationCanceledException)
- {
- // Do nothing
+ {
+ // Timeout expired - consumer didn't finish in time
+ // This is acceptable; the background task will continue draining
+ // but we don't wait for it to allow app exit
}
}
}
catch (Exception ex)
{
- // Do nothing
+ // Ignore any errors during consumer shutdown
+ }
+ }
+
+ // Attempt to flush flows with a very short timeout
+ // Don't await indefinitely - prioritize app exit over log flushing
+ try
+ {
+ using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)))
+ {
+ await FlushAsync(cts.Token).ConfigureAwait(false);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ // Flush timed out - that's OK, some logs might be lost but app exits cleanly
+ }
+ catch (Exception ex)
+ {
+ // Ignore flush errors
+ }
+
+ // Dispose flows with a short timeout
+ var disposeTasks = _concurrentFlows.Select(f => f.DisposeAsync().AsTask()).ToArray();
+ if (disposeTasks.Length > 0)
+ {
+ try
+ {
+ using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
+ {
+ await Task.WhenAll(disposeTasks).ConfigureAwait(false);
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ // Disposal timed out - proceed anyway
+ }
+ catch (Exception ex)
+ {
+ // Ignore disposal errors
}
}
}
else
{
- // If using synchronous mode, just flush
- await FlushAsync().ConfigureAwait(false);
- }
-
- // Dispose flows - they should already be flushed above
- var disposeTasks = _concurrentFlows.Select(f => f.DisposeAsync().AsTask()).ToArray();
- try
- {
- await Task.WhenAll(disposeTasks).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- // Do nothing
+ // If using synchronous mode, attempt a quick flush but don't block
+ try
+ {
+ using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)))
+ {
+ await FlushAsync(cts.Token).ConfigureAwait(false);
+ }
+ }
+ catch
+ {
+ // Ignore errors during sync-mode flush
+ }
}
+ // Request cancellation of the async pipeline if it's still running
+ _asyncCts?.Cancel();
_asyncCts?.Dispose();
GC.SuppressFinalize(this);
}
diff --git a/EonaCat.LogStack/EonaCatLoggerCore/Flows/FileFlow.cs b/EonaCat.LogStack/EonaCatLoggerCore/Flows/FileFlow.cs
index 19fa2c9..a1c07e5 100644
--- a/EonaCat.LogStack/EonaCatLoggerCore/Flows/FileFlow.cs
+++ b/EonaCat.LogStack/EonaCatLoggerCore/Flows/FileFlow.cs
@@ -223,7 +223,7 @@ namespace EonaCat.LogStack.Flows
// Dedicated writer thread
_writerThread = new Thread(WriterThreadBody)
{
- IsBackground = false,
+ IsBackground = true,
Name = "FileFlow.Writer[" + filePrefix + "]",
Priority = ThreadPriority.AboveNormal,
};