diff --git a/README.md b/README.md index f8c6c4fbd..1e7535701 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,4 @@ MyGet Pre-release feed: https://www.myget.org/gallery/stackoverflow | ------- | ------------ | ----------------- | --------- | ----- | | [StackExchange.Redis](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/absoluteLatest) | [![StackExchange.Redis](https://img.shields.io/nuget/dt/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis MyGet](https://img.shields.io/myget/stackoverflow/vpre/StackExchange.Redis.svg)](https://www.myget.org/feed/stackoverflow/package/nuget/StackExchange.Redis) | -Release notes at: https://github.com/StackExchange/StackExchange.Redis/releases (3.0 onwards; earlier releases at https://seredis.dev/ReleaseNotes) +Release notes at: [GitHub Releases](https://github.com/StackExchange/StackExchange.Redis/releases) (3.0 onwards; [earlier releases](https://seredis.dev/ReleaseNotes)) diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 000000000..cb4dd0ac4 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,50 @@ +--- +layout: default +title: Page not found +sitemap: false +--- + +

There is nothing at this address.

+ + + +

If you got here from a link in an exception message or a log line, the punctuation after the URL was +probably picked up as part of it — most link detectors will happily swallow a closing bracket or a +quote.

+ + + + diff --git a/docs/CompareAndSwap.md b/docs/CompareAndSwap.md index 7d79d42a0..c88347b12 100644 --- a/docs/CompareAndSwap.md +++ b/docs/CompareAndSwap.md @@ -316,6 +316,6 @@ var condition = ValueCondition.CalculateDigest(largeValueBytes); ## See Also -- [Transactions](Transactions.md) - For multi-key atomic operations -- [Keys and Values](KeysValues.md) - Understanding Redis data types +- [Transactions](Transactions) - For multi-key atomic operations +- [Keys and Values](KeysValues) - Understanding Redis data types - [Redis CAS/CAD Documentation](https://redis.io/docs/latest/commands/set/) - Redis 8.4 SET command with IFEQ/IFNE/IFDEQ/IFDNE modifiers diff --git a/docs/Profiling.md b/docs/Profiling.md index cffdae25d..6b34f55e6 100644 --- a/docs/Profiling.md +++ b/docs/Profiling.md @@ -5,6 +5,6 @@ The profiling API has undergone breaking changes between 1.* and 2.*; in 1.*; in the `object GetContext()` API was unintuitive for consumers and expensive for the library (due to book-keeping). The API in 2.* is much simpler and more "obvious". This is a breaking change. -[Profiling in 1.\*](Profiling_v1.md) +[Profiling in 1.\*](Profiling_v1) -[Profiling in 2.\*](Profiling_v2.md) +[Profiling in 2.\*](Profiling_v2) diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 14231ff50..500a416dd 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -613,7 +613,7 @@ Changes: - **Soft Break**: The `PreserveAsyncOrder` behaviour of the pub/sub API has been deprecated; a *new* API has been provided for scenarios that require in-order pub/sub handling - the `Subscribe` method has a new overload *without* a handler parameter which returns a `ChannelMessageQueue`, which provides `async` ordered access to messages) - Internal: The network architecture has moved to use `System.IO.Pipelines`; this has allowed us to simplify and unify a lot of the network code, and in particular fix a lot of problems relating to how the library worked with TLS and/or .NETStandard -- Change: As a result of the `System.IO.Pipelines` change, the error-reporting on timeouts is now much simpler and clearer; the [timeouts documentation](Timeouts.md) has been updated +- Change: As a result of the `System.IO.Pipelines` change, the error-reporting on timeouts is now much simpler and clearer; the [timeouts documentation](Timeouts) has been updated - Removed: The `HighPriority` (queue-jumping) flag is now deprecated - Internal: Most buffers internally now make use of pooled memory; `RedisValue` no longer preemptively allocates buffers - Internal: Added new custom thread-pool for handling async continuations to avoid thread-pool starvation issues diff --git a/src/StackExchange.Redis/ExceptionFactory.cs b/src/StackExchange.Redis/ExceptionFactory.cs index d47d62c97..aa9bf7001 100644 --- a/src/StackExchange.Redis/ExceptionFactory.cs +++ b/src/StackExchange.Redis/ExceptionFactory.cs @@ -309,9 +309,12 @@ internal static Exception Timeout(ConnectionMultiplexer multiplexer, string? bas } AddCommonDetail(data, sb, message, multiplexer, server); - sb.Append(" (Please take a look at this article for some common client-side issues that can cause timeouts: ") + // Keep the URL away from the end of the message and away from punctuation: linkifiers in log + // viewers, chat and issue trackers greedily swallow a trailing ')' or '"', and the docs site + // then sees a 404 for /Timeouts). The space after it is what makes them stop. + sb.Append(" (see ") .Append(TimeoutHelpLink) - .Append(')'); + .Append(" for some common client-side issues that can cause timeouts)"); // If we're from a backlog timeout scenario, we log a more intuitive connection exception for the timeout...because the timeout was a symptom // and we have a more direct cause: we had no connection to send it on. diff --git a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs index 0c156300c..e2c34c9ad 100644 --- a/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs +++ b/tests/StackExchange.Redis.Tests/AbortOnConnectFailTests.cs @@ -49,7 +49,7 @@ public async Task DisconnectAndReconnectThrowsConnectionExceptionSync() Assert.SkipUnless(server.CanSimulateConnectionFailure, "Skipping because server cannot simulate connection failure"); server.SimulateConnectionFailure(SimulatedFailureType.All); - // Exception: The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: SocketFailure (InputReaderCompleted, last-recv: 7) on 127.0.0.1:6379/Interactive, Idle/ReadAsync, last: PING, origin: SimulateConnectionFailure, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 100s, state: ConnectedEstablished, mgr: 10 of 10 available, in: 0, in-pipe: 0, out-pipe: 0, last-heartbeat: never, last-mbeat: 0s ago, global: 0s ago, v: 2.6.120.51136, command=PING, timeout: 100, inst: 13, qu: 1, qs: 0, aw: False, bw: Inactive, last-in: 0, cur-in: 0, sync-ops: 2, async-ops: 0, serverEndpoint: 127.0.0.1:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: CRAVERTOP7(SE.Redis-v2.6.120.51136), IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=2,Free=32765,Min=16,Max=32767), POOL: (Threads=33,QueuedItems=0,CompletedItems=6237,Timers=39), v: 2.6.120.51136 (Please take a look at this article for some common client-side issues that can cause timeouts: https://seredis.dev/Timeouts) + // Exception: The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: SocketFailure (InputReaderCompleted, last-recv: 7) on 127.0.0.1:6379/Interactive, Idle/ReadAsync, last: PING, origin: SimulateConnectionFailure, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 100s, state: ConnectedEstablished, mgr: 10 of 10 available, in: 0, in-pipe: 0, out-pipe: 0, last-heartbeat: never, last-mbeat: 0s ago, global: 0s ago, v: 2.6.120.51136, command=PING, timeout: 100, inst: 13, qu: 1, qs: 0, aw: False, bw: Inactive, last-in: 0, cur-in: 0, sync-ops: 2, async-ops: 0, serverEndpoint: 127.0.0.1:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: CRAVERTOP7(SE.Redis-v2.6.120.51136), IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=2,Free=32765,Min=16,Max=32767), POOL: (Threads=33,QueuedItems=0,CompletedItems=6237,Timers=39), v: 2.6.120.51136 (see https://seredis.dev/Timeouts for some common client-side issues that can cause timeouts) var ex = Assert.ThrowsAny(() => db.Ping()); Log("Exception: " + ex.Message); Assert.True(ex is RedisConnectionException or RedisTimeoutException); @@ -75,7 +75,7 @@ public async Task DisconnectAndNoReconnectThrowsConnectionExceptionAsync() Assert.SkipUnless(server.CanSimulateConnectionFailure, "Skipping because server cannot simulate connection failure"); server.SimulateConnectionFailure(SimulatedFailureType.All); - // Exception: The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: SocketFailure (InputReaderCompleted, last-recv: 7) on 127.0.0.1:6379/Interactive, Idle/ReadAsync, last: PING, origin: SimulateConnectionFailure, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 100s, state: ConnectedEstablished, mgr: 8 of 10 available, in: 0, in-pipe: 0, out-pipe: 0, last-heartbeat: never, last-mbeat: 0s ago, global: 0s ago, v: 2.6.120.51136, command=PING, timeout: 100, inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, last-in: 0, cur-in: 0, sync-ops: 1, async-ops: 1, serverEndpoint: 127.0.0.1:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 8 of 10 available, clientName: CRAVERTOP7(SE.Redis-v2.6.120.51136), IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=6,Free=32761,Min=16,Max=32767), POOL: (Threads=33,QueuedItems=0,CompletedItems=5547,Timers=60), v: 2.6.120.51136 (Please take a look at this article for some common client-side issues that can cause timeouts: https://seredis.dev/Timeouts) + // Exception: The message timed out in the backlog attempting to send because no connection became available (400ms) - Last Connection Exception: SocketFailure (InputReaderCompleted, last-recv: 7) on 127.0.0.1:6379/Interactive, Idle/ReadAsync, last: PING, origin: SimulateConnectionFailure, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 100s, state: ConnectedEstablished, mgr: 8 of 10 available, in: 0, in-pipe: 0, out-pipe: 0, last-heartbeat: never, last-mbeat: 0s ago, global: 0s ago, v: 2.6.120.51136, command=PING, timeout: 100, inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, last-in: 0, cur-in: 0, sync-ops: 1, async-ops: 1, serverEndpoint: 127.0.0.1:6379, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 8 of 10 available, clientName: CRAVERTOP7(SE.Redis-v2.6.120.51136), IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=6,Free=32761,Min=16,Max=32767), POOL: (Threads=33,QueuedItems=0,CompletedItems=5547,Timers=60), v: 2.6.120.51136 (see https://seredis.dev/Timeouts for some common client-side issues that can cause timeouts) var ex = await Assert.ThrowsAsync(() => db.PingAsync()); Log("Exception: " + ex.Message); Assert.StartsWith("The message timed out in the backlog attempting to send because no connection became available (1000ms) - Last Connection Exception: ", ex.Message); diff --git a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs index ea868fb46..00d39b60d 100644 --- a/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs +++ b/tests/StackExchange.Redis.Tests/ExceptionFactoryTests.cs @@ -116,7 +116,7 @@ public async Task TimeoutException() var ex = Assert.IsType(rawEx); Log("Exception: " + ex.Message); - // Example format: "Test Timeout, command=PING, inst: 0, qu: 0, qs: 0, aw: False, in: 0, in-pipe: 0, out-pipe: 0, last-in: 0, cur-in: 0, serverEndpoint: 127.0.0.1:6379, mgr: 10 of 10 available, clientName: TimeoutException, IOCP: (Busy=0,Free=1000,Min=8,Max=1000), WORKER: (Busy=2,Free=2045,Min=8,Max=2047), v: 2.1.0 (Please take a look at this article for some common client-side issues that can cause timeouts: https://seredis.dev/Timeouts)"; + // Example format: "Test Timeout, command=PING, inst: 0, qu: 0, qs: 0, aw: False, in: 0, in-pipe: 0, out-pipe: 0, last-in: 0, cur-in: 0, serverEndpoint: 127.0.0.1:6379, mgr: 10 of 10 available, clientName: TimeoutException, IOCP: (Busy=0,Free=1000,Min=8,Max=1000), WORKER: (Busy=2,Free=2045,Min=8,Max=2047), v: 2.1.0 (see https://seredis.dev/Timeouts for some common client-side issues that can cause timeouts)"; Assert.StartsWith("Test Timeout, command=PING", ex.Message); Assert.Contains("clientName: " + nameof(TimeoutException), ex.Message); // Ensure our pipe numbers are in place @@ -138,7 +138,7 @@ public async Task TimeoutException() Assert.Contains("Timers=", ex.Message); #endif Assert.DoesNotContain("Unspecified/", ex.Message); - Assert.EndsWith(" (Please take a look at this article for some common client-side issues that can cause timeouts: https://seredis.dev/Timeouts)", ex.Message); + Assert.EndsWith(" (see https://seredis.dev/Timeouts for some common client-side issues that can cause timeouts)", ex.Message); Assert.Null(ex.InnerException); } finally