diff --git a/Assets/Plugins/StreamChat/Changelog.txt b/Assets/Plugins/StreamChat/Changelog.txt index 3a66b3e1..9905da9d 100644 --- a/Assets/Plugins/StreamChat/Changelog.txt +++ b/Assets/Plugins/StreamChat/Changelog.txt @@ -3,6 +3,10 @@ Features: * Add IStreamClientConfig.OptimisticMessageInsert (default true). When true (the existing behavior), a message you send is inserted into the local channel state and raised via IStreamChannel.MessageReceived immediately, before the server's message.new echo arrives. Set it to false to skip the optimistic local insert and wait for the server echo instead, so every participant - including the sender - observes messages in the same server-defined order. Useful when consistent cross-client ordering matters more than instant local feedback (e.g. a shared, broadcast-ordered feed). +Fixes: + +* TaskUtils.LogIfFailed now logs connectivity/transport failures as warnings instead of errors/exceptions. The SDK fire-and-forgets its connect, reconnect, and state-restore operations through LogIfFailed; when the device is offline these fail with HttpRequestException / WebException / SocketException / IOException / TimeoutException, which the reconnect flow recovers from - so surfacing them at error severity flooded crash/error reporting (Sentry, Bugsnag, etc.) with handled, non-actionable noise. Genuine (non-connectivity) failures still log as exceptions. Complements the connection-attempt-timeout fix from PR #213. + v5.5.0: Features: diff --git a/Assets/Plugins/StreamChat/Libs/Utils/TaskUtils.cs b/Assets/Plugins/StreamChat/Libs/Utils/TaskUtils.cs index 1c292bd7..276c5d54 100644 --- a/Assets/Plugins/StreamChat/Libs/Utils/TaskUtils.cs +++ b/Assets/Plugins/StreamChat/Libs/Utils/TaskUtils.cs @@ -17,7 +17,19 @@ public static void LogIfFailed(this Task t, ILogs logger) return; } - Debug.LogException(_.Exception); + if (IsTransientNetworkException(_.Exception)) + { + // A connectivity/transport failure (no network, a dropped/refused connection, + // a TLS or socket read failure, or a request timeout) on a fire-and-forget task + // is an expected, transient condition the reconnect flow recovers from. Log it as + // a warning instead of an exception so it does not flood crash/error reporting with + // handled, non-actionable noise. Genuine failures still surface as exceptions. + Debug.LogWarning(_.Exception.ToString()); + } + else + { + Debug.LogException(_.Exception); + } }, TaskScheduler.FromCurrentSynchronizationContext()); @@ -53,12 +65,47 @@ public static void LogIfFailed(this Task t) if (_sb.Length > 0) { - Debug.LogError(_sb.ToString()); + // See LogIfFailed(Task, ILogs): connectivity/transport failures are expected, + // transient, and recovered by the reconnect flow, so log them as warnings rather + // than errors to avoid flooding crash/error reporting with non-actionable noise. + if (IsTransientNetworkException(_.Exception)) + { + Debug.LogWarning(_sb.ToString()); + } + else + { + Debug.LogError(_sb.ToString()); + } _sb.Length = 0; } }, TaskScheduler.FromCurrentSynchronizationContext()); + // True when a task faulted because of a connectivity / transport problem — no network, a + // dropped/refused connection, a TLS or socket read failure, or a request timeout — rather than + // a genuine application error. The SDK fire-and-forgets its connect / reconnect / restore + // operations through LogIfFailed; when the device is offline these fail with such exceptions + // and the reconnect flow recovers from them, so they are logged as warnings, not errors. + private static bool IsTransientNetworkException(AggregateException aggregateException) + { + foreach (Exception inner in aggregateException.Flatten().InnerExceptions) + { + for (Exception e = inner; e != null; e = e.InnerException) + { + if (e is System.Net.Http.HttpRequestException || + e is System.Net.WebException || + e is System.Net.Sockets.SocketException || + e is System.IO.IOException || + e is TimeoutException) + { + return true; + } + } + } + + return false; + } + private static readonly StringBuilder _sb = new StringBuilder(); } } \ No newline at end of file