diff --git a/Directory.Build.props b/Directory.Build.props
index fbb5c39f5..55c0088fe 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,9 +10,9 @@
true
$(MSBuildThisFileDirectory)Shared.ruleset
NETSDK1069
-
- $(NoWarn);NU5105;NU1507;SER004;SER005;SER009;SER010
+
+ $(NoWarn);NU5105;NU1507;SER004;SER005;SER009
https://github.com/StackExchange/StackExchange.Redis/releases
https://seredis.dev/
MIT
diff --git a/docs/Configuration.md b/docs/Configuration.md
index 9297386a8..b86f2148d 100644
--- a/docs/Configuration.md
+++ b/docs/Configuration.md
@@ -368,13 +368,8 @@ broken connection. This requires RESP3, and the client asks for it per connectio
| `enabled` | **Required**: ask, and reject the connection unless notifications are live. Only point this at a deployment you know supports them. |
Note that `enabled` means *required*, not merely *on* - it is the cross-client name for that mode, and it will
-refuse a connection that cannot deliver notifications, including any RESP2 connection.
-
-**For now this is purely opt-in: you must set `maintNotifications` yourself.** The `amr`, `rediscloud` and
-`enterprise` providers are intended to select `auto` for you, so that on those deployments nothing needs
-setting - but that auto-enlistment is held back until the feature has been through formal acceptance testing,
-and is expected in a follow-up release. Naming a provider today sets its other defaults without turning
-notifications on.
+refuse a connection that cannot deliver notifications, including any RESP2 connection. The `amr`, `rediscloud`
+and `enterprise` providers select `auto` for you, so on those deployments you need not set anything.
While a disruption has been announced, command timeouts are relaxed - raised to `maintRelaxedTimeout`, never
lowered, so a caller with a more generous timeout keeps it. The window ends when the server says the disruption
diff --git a/docs/ServerMaintenanceEvent.md b/docs/ServerMaintenanceEvent.md
index 91790bf46..15ef44c5a 100644
--- a/docs/ServerMaintenanceEvent.md
+++ b/docs/ServerMaintenanceEvent.md
@@ -13,8 +13,6 @@ If you are a Redis vendor and want to integrate support for ServerMaintenanceEve
# Server-native maintenance notifications (Redis Enterprise and Redis Cloud)
-> These APIs are experimental, behind diagnostic id `SER010`; see [SER010](exp/SER010.md).
-
Redis Enterprise and Redis Cloud can tell a client *directly* that a disruption is coming: a shard is migrating, a node is failing over, or the endpoint you are connected to is being replaced. These arrive as RESP3 push frames on the connection itself, and the client does not merely report them: it relaxes timeouts for the duration, re-reads the cluster topology when slots have moved, recovers sharded subscriptions that were stranded, and moves off an endpoint that is going away rather than waiting to be disconnected.
### What this feature is called
@@ -29,34 +27,29 @@ Server-side you may also see it discussed as *maintenance mode*, *shard migratio
## Do I need to configure anything?
-**Yes — for now.** In this release maintenance notifications are **purely opt-in**: nothing turns them on for you, whatever you connect to. You get them only by asking, with `maintNotifications=Auto` (or `Enabled`).
-
-> **This is temporary.** The intent is that the options providers enlist you automatically, so that connecting to a recognized Redis Cloud or Azure Managed Redis hostname turns the feature on without any configuration — exactly as the table below describes. That is held back only until the feature has been through formal acceptance testing, and is expected to land in a follow-up release. Until then, treat the "will be" column as a statement of direction, not of current behaviour.
+Usually not. If you connect using the hostname your provider gave you, the matching options provider recognizes it and turns the feature on for you by default.
-| You connect to | Recognized as | Notifications now | Will be |
-|---|---|---|---|
-| `something.cloud.redislabs.com`, `.cloud.redis.io`, `.redislabs.com` | Redis Cloud | **off** unless asked | on (`Auto`) |
-| `something.redis.azure.net`, `.redisenterprise.cache.azure.net` | Azure Managed Redis | **off** unless asked | on (`Auto`) |
-| `defaults=enterprise`, `defaults=rediscloud`, `defaults=amr` | named explicitly | **off** unless asked | on (`Auto`) |
-| your own hostname, a CNAME, private DNS, or through a proxy | nothing | **off** | **off** |
-| a self-managed Redis Enterprise cluster | nothing (there is no DNS pattern to recognize) | **off** | **off** |
+| You connect to | Recognized as | Notifications |
+|---|---|---|
+| `something.cloud.redislabs.com`, `.cloud.redis.io`, `.redislabs.com` | Redis Cloud | on (`Auto`) |
+| `something.redis.azure.net`, `.redisenterprise.cache.azure.net` | Azure Managed Redis | on (`Auto`) |
+| `defaults=enterprise`, `defaults=rediscloud`, `defaults=amr` | named explicitly | on (`Auto`) |
+| your own hostname, a CNAME, private DNS, or through a proxy | nothing | **off** |
+| a self-managed Redis Enterprise cluster | nothing (there is no DNS pattern to recognize) | **off** |
-Nothing fails when the feature is off: the connection works normally and you simply never receive a notification. So to use it today, ask for it explicitly. Either:
+The last two rows are the ones to know about, because nothing fails: the connection works normally and you simply never receive a notification. If your endpoint does not look like your provider's, say so explicitly. Either:
```csharp
-// change nothing except this feature
-var options = ConfigurationOptions.Parse("my-redis.internal.example.com:6379,maintNotifications=Auto");
+// the whole deployment posture: prefer RESP3, skip the OSS config-broadcast channel, and ask for notifications
+var options = ConfigurationOptions.Parse("my-redis.internal.example.com:6379,defaults=enterprise");
```
-or, to take the whole deployment posture as well - prefer RESP3 and skip the OSS config-broadcast channel:
+or, to change nothing except this feature:
```csharp
-var options = ConfigurationOptions.Parse(
- "my-redis.internal.example.com:6379,defaults=enterprise,maintNotifications=Auto");
+var options = ConfigurationOptions.Parse("my-redis.internal.example.com:6379,maintNotifications=Auto");
```
-Note that `maintNotifications` is needed in *both* forms for now: while the feature is opt-in, naming a provider sets that provider's other defaults but does not turn notifications on. Once auto-enlistment lands, `defaults=enterprise` alone will be enough.
-
`defaults=` accepts `rediscloud`, `enterprise`, `amr` and `azure`; see [Configuration](Configuration.md) for what each provider sets. It is also the right answer for a *hosted* deployment reached somewhere its own provider cannot see it, such as behind a CNAME or a private endpoint.
### RESP3 is required, and is already the default
@@ -77,8 +70,8 @@ options.MaintenanceNotifications = MaintenanceNotificationMode.Auto;
| Mode | Meaning |
|---|---|
-| `Disabled` | never ask. **The default everywhere, for now** - see above |
-| `Auto` | ask, and carry on if the server says no. What the providers will select once auto-enlistment lands |
+| `Disabled` | never ask. The default unless a provider recognizes the endpoint - see above |
+| `Auto` | ask, and carry on if the server says no. What the Redis Cloud, Redis Enterprise and Azure Managed Redis providers select |
| `Enabled` | **require** them: if the server will not deliver them, or the connection ends up on RESP2, the connection is **rejected** |
`Auto` is the right choice almost always: asking costs one command during the handshake, and a server that accepts and then never sends anything costs nothing at all. `Enabled` exists for the case where running without advance warning is worse than not running: it turns a silent absence into a startup failure, which also makes it a useful way to prove the feature is live in a staging environment.
@@ -231,7 +224,7 @@ Alternatively set `MaintenanceNotifications = Enabled` in a test or staging envi
So for now the connection succeeds *without* the feature and logs a warning saying so. Note this is the one case where `Enabled` does not reject the connection - it would otherwise be impossible to configure an explicit opt-in for a group at all. Expect this restriction to be lifted; if you are relying on maintenance notifications today, use a single-group connection.
-Redis Enterprise and Redis Cloud send them, subject to the feature being enabled on the cluster. Azure Managed Redis is configured to ask for them ahead of its own rollout, so the setting is harmless until their servers begin emitting. Redis Open Source, Valkey and other servers do not send them at all, and the setting is simply inert there: the opt-in is refused and the client carries on.
+Redis Enterprise and Redis Cloud send them, subject to the feature being enabled on the cluster. On Redis Enterprise there are *two* switches, and they are easy to conflate: a **cluster-level flag** decides whether the subcommand exists at all (`client_maint_notifications` for proxy-routed databases, `oss_cluster_client_maint_notifications` for `oss_cluster` ones), and the per-connection opt-in that `maintNotifications` controls asks one connection to receive them. With the flag off, `CLIENT MAINT_NOTIFICATIONS ON` is refused, which `Auto` absorbs silently and `Enabled` turns into a refused connection - so if `Enabled` rejects connections to a deployment you believe supports the feature, check the cluster flag before suspecting the client. Azure Managed Redis is configured to ask for them ahead of its own rollout, so the setting is harmless until their servers begin emitting. Redis Open Source, Valkey and other servers do not send them at all, and the setting is simply inert there: the opt-in is refused and the client carries on.
# Azure Cache for Redis maintenance events (pub/sub)
diff --git a/docs/exp/SER010.md b/docs/exp/SER010.md
index 89dcbff70..9f2f9dd7d 100644
--- a/docs/exp/SER010.md
+++ b/docs/exp/SER010.md
@@ -1,57 +1,39 @@
-Maintenance notifications ("smart client handoffs") are a server feature by which a server warns a
-connected client in advance of a disruptive event - a shard migration, a failover, or the endpoint
-itself being replaced - so the client can act before the disruption rather than react to a broken
-connection afterwards. The client opts in per connection with `CLIENT MAINT_NOTIFICATIONS ON`, and the
-notifications then arrive as RESP3 push frames on the connection that carries commands.
+# Maintenance notifications - SER010 retired
-The feature is experimental here for three separate reasons:
+**This diagnostic is no longer produced.** Server-native maintenance notifications ("smart client
+handoffs") are no longer marked `[Experimental]`, so nothing emits `SER010` and no suppression is needed.
+The page is kept because the diagnostic's help link pointed here, and older builds still carry it.
-1. **The server side is not universal.** Only Redis Enterprise and Redis Cloud emit these
- notifications today; OSS Redis, Valkey and Garnet do not recognize the opt-in at all. That is why
- `MaintenanceNotificationMode.Auto` exists, and why the default is `Disabled`.
-2. **The wire contract is still evolving.** Notification types have been proposed and withdrawn during
- its development, and the payloads are described in prose rather than pinned down by a formal
- specification. Our parsing is validated against frames captured from live deployments and is
- deliberately liberal about what it accepts, but the shapes may still change.
-3. **What the client *does* in response is the substantial part**, and it is being built in stages -
- timeout relaxation, then endpoint handoff. Behaviour may therefore change materially between
- versions while the diagnostic is in place, even where the API does not.
+If you have a suppression for `SER010` - in a `csproj`, a `.editorconfig`, or a `#pragma` - it is now
+inert, and can be removed whenever it suits you.
-**Currently purely opt-in.** Nothing enables this for you: the options providers for Redis Cloud, Azure
-Managed Redis and Redis Enterprise are intended to select `Auto` so that a recognized endpoint needs no
-configuration, but that auto-enlistment is held back until the feature has been through formal acceptance
-testing, and is expected in a follow-up release. Until then the only thing that turns notifications on is
-setting `maintNotifications` yourself.
+For how the feature works and how to configure it, see [ServerMaintenanceEvent](../ServerMaintenanceEvent.md).
-`MaintenanceNotificationMode`:
+## What it covered
-- `Disabled` (the default) - never ask; the server sends nothing.
-- `Enabled` - **required**: ask, and *reject the connection* unless notifications end up live. That covers a
- server that refuses, a server that answers `HELLO 3` as RESP2, and a configuration that could never ask in
- the first place (`Protocol = Resp2`, or `HELLO` unavailable) - requiring a RESP3-only feature over RESP2 is
- a contradiction, and it fails rather than being half-honoured. Only point this at a deployment you know
- supports them.
-- `Auto` - ask, and carry on if the server refuses or the connection ends up RESP2; the feature is then
- simply off for that server and the connection is never rejected over it. Safe against a mixture of
- servers, or one whose support you don't know, and what most callers want.
+Maintenance notifications are a server feature by which a server warns a connected client in advance of
+a disruptive event - a shard migration, a failover, or the endpoint itself being replaced - so the client
+can act before the disruption rather than react to a broken connection afterwards. The gated surface was:
-The names are the cross-client ones (they match go-redis and redis-py, so a connection string ports
-between clients), which makes `Enabled` easy to misread as "on" - it means "required". One deliberate
-divergence: the cross-client spec only calls for interrupting the connection when the *server* errors,
-whereas we extend that to the RESP2 cases above, on the grounds that a required feature which cannot
-possibly be delivered is the same failure either way.
+- the `MaintenanceNotificationMode` and `MaintenanceEndpointType` enums, and the
+ `MaintenanceNotifications`, `MaintenanceMovingEndpointType`, `MaintenanceRelaxedTimeout`,
+ `MaintenanceRelaxedWindowMax` and `MaintenancePostEventRelaxedDuration` options on
+ `ConfigurationOptions` and `DefaultOptionsProvider`
+- `PushMaintenanceEvent`, `ClusterSlotMigration` and `MaintenanceNotificationType`
+- the `MaintenanceType` property on `FaultContext`, `RedisConnectionException` and `RedisTimeoutException`
-## A deployment prerequisite worth knowing
+## What it used to mean
-On Redis Enterprise there are *two* switches, and they are easy to conflate. A **cluster-level flag** decides
-whether the subcommand exists at all - `client_maint_notifications` for proxy-routed databases,
-`oss_cluster_client_maint_notifications` for `oss_cluster` ones - and the **per-connection opt-in** this option
-controls asks one connection to receive them. A cluster running a supporting version with the flag off will
-refuse `CLIENT MAINT_NOTIFICATIONS ON`, which `Auto` absorbs silently and `Enabled` turns into a refused
-connection. So if `Enabled` is rejecting connections against a deployment you believe supports the feature,
-check the cluster flag before suspecting the client.
+While the feature was experimental, it was flagged as subject to change for three reasons:
-If you accept the above, you can suppress this warning by adding the following to your `csproj` file:
+1. **The server side is not universal.** Only Redis Enterprise and Redis Cloud emitted these
+ notifications; OSS Redis, Valkey and Garnet do not recognize the opt-in at all.
+2. **The wire contract was still evolving.** Notification types were proposed and withdrawn during its
+ development, and the payloads are described in prose rather than by a formal specification.
+3. **What the client *does* in response was being built in stages** - timeout relaxation, then endpoint
+ handoff - so behaviour could change materially between versions even where the API did not.
+
+Acknowledging that was what the suppression meant:
```xml
$(NoWarn);SER010
@@ -62,3 +44,8 @@ or more granularly / locally in C#:
``` c#
#pragma warning disable SER010
```
+
+## Reserved, not recycled
+
+`SER010` is not reused for anything else, so an old suppression cannot silently hide an unrelated
+warning. The same applies to the other retired identifiers - see `Experiments.cs`.
diff --git a/src/RESPite/Shared/Experiments.cs b/src/RESPite/Shared/Experiments.cs
index 40fc397e0..93fd067f8 100644
--- a/src/RESPite/Shared/Experiments.cs
+++ b/src/RESPite/Shared/Experiments.cs
@@ -17,12 +17,12 @@ internal static class Experiments
// SER006 = Server_8_8 (Redis 8.8 features)
// SER007 = GeoRedundantFailover (multi-group connections, health checks, retry)
// SER008 = Server_8_10 (Redis 8.10 features)
+ // SER010 = MaintenanceNotifications (server-native maintenance notifications / smart client handoffs)
// ReSharper disable InconsistentNaming
public const string Respite = "SER004";
public const string UnitTesting = "SER005";
public const string Transport = "SER009";
- public const string MaintenanceNotifications = "SER010";
// ReSharper restore InconsistentNaming
diff --git a/src/StackExchange.Redis/Availability/FaultContext.cs b/src/StackExchange.Redis/Availability/FaultContext.cs
index d13963147..3c43f10f8 100644
--- a/src/StackExchange.Redis/Availability/FaultContext.cs
+++ b/src/StackExchange.Redis/Availability/FaultContext.cs
@@ -128,7 +128,6 @@ public FaultContext(Exception fault)
/// was for. Left to policy rather than acted on here, since "ignore faults during maintenance" is a
/// judgement about the deployment, not about the protocol.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public Maintenance.MaintenanceNotificationType MaintenanceType { get; }
private static bool IsKnownNotApplied(RedisErrorKind kind, CommandStatus status)
diff --git a/src/StackExchange.Redis/Configuration/AzureManagedRedisOptionsProvider.cs b/src/StackExchange.Redis/Configuration/AzureManagedRedisOptionsProvider.cs
index 1f3198eda..1ab612bea 100644
--- a/src/StackExchange.Redis/Configuration/AzureManagedRedisOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/AzureManagedRedisOptionsProvider.cs
@@ -71,16 +71,16 @@ public override Task AfterConnectAsync(ConnectionMultiplexer muxer, Action
public override string ConfigurationChannel => ""; // disable on AMR
- // Auto-enlistment, deliberately withheld for now; maintenance notifications ship purely opt-in, and
- // this goes back in a follow-up once the feature has been through formal acceptance testing. Kept here
- // commented rather than deleted so that what returns is exactly what was reviewed.
- //
- // Pre-emptive: AMR does not emit these yet, and support is being added concurrently with this
- // client-side work. Auto is what makes that safe - until the server side ships, the opt-in is refused
- // and the feature stays off, and it then starts working without anybody needing to change a connection
- // string. AMR also already prefers RESP3 here, which the feature requires.
- //
- // [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
- // public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
+ ///
+ /// Ask for maintenance notifications, tolerating a server that doesn't offer them.
+ ///
+ ///
+ /// Pre-emptive: AMR does not emit these yet, and support is being added concurrently with this
+ /// client-side work. is what makes that safe - until
+ /// the server side ships, the opt-in is refused and the feature stays off, and it then starts working
+ /// without anybody needing to change a connection string. AMR also already prefers RESP3 here, which
+ /// the feature requires.
+ ///
+ public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
}
}
diff --git a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
index 055c3d23d..c0cb836e0 100644
--- a/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/DefaultOptionsProvider.cs
@@ -362,7 +362,6 @@ protected virtual string GetDefaultClientName() =>
/// CLIENT subcommand is not guaranteed to be answered as politely as a server would. A provider
/// that recognizes a deployment which supports the feature should override this.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public virtual MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Disabled;
///
@@ -381,14 +380,12 @@ protected virtual string GetDefaultClientName() =>
/// fall back to a bare opt-in; nothing observed so far needs it.
///
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public virtual MaintenanceEndpointType MaintenanceMovingEndpointType => MaintenanceEndpointType.Auto;
///
/// Gets the value command timeouts are relaxed to during an announced disruption; 10 seconds, as the
/// notification contract prescribes.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public virtual TimeSpan MaintenanceRelaxedTimeout => TimeSpan.FromSeconds(10);
///
@@ -402,7 +399,6 @@ protected virtual string GetDefaultClientName() =>
/// there is ample room for a legitimate window while a stuck one is bounded to half a minute. Return a
/// value here to pin it regardless of the relaxed timeout.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public virtual TimeSpan? MaintenanceRelaxedWindowMax => null;
///
@@ -420,7 +416,6 @@ protected virtual string GetDefaultClientName() =>
/// to for that behaviour.
///
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public virtual TimeSpan? MaintenancePostEventRelaxedDuration => null;
///
diff --git a/src/StackExchange.Redis/Configuration/RedisCloudOptionsProvider.cs b/src/StackExchange.Redis/Configuration/RedisCloudOptionsProvider.cs
index 8787a578a..59f24df0c 100644
--- a/src/StackExchange.Redis/Configuration/RedisCloudOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/RedisCloudOptionsProvider.cs
@@ -59,16 +59,16 @@ private static bool IsHostInDomains(string hostName, string[] domains)
///
public override string ConfigurationChannel => "";
- // Auto-enlistment, deliberately withheld for now; maintenance notifications ship purely opt-in, and
- // this goes back in a follow-up once the feature has been through formal acceptance testing. Kept here
- // commented rather than deleted so that what returns is exactly what was reviewed.
- //
- // This is the deployment family the feature exists for, and Auto rather than Enabled because a
- // database that has not been updated yet must keep working: the opt-in is then refused and the feature
- // stays off, rather than the connection being rejected.
- //
- // [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
- // public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
+ ///
+ /// Ask for maintenance notifications, tolerating a server that doesn't offer them.
+ ///
+ ///
+ /// This is the deployment family the feature exists for.
+ /// rather than because a database that has not been
+ /// updated yet must keep working: the opt-in is then refused and the feature stays off, rather than the
+ /// connection being rejected.
+ ///
+ public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
// Two things AzureManagedRedisOptionsProvider does that are deliberately *not* repeated here:
//
diff --git a/src/StackExchange.Redis/Configuration/RedisEnterpriseOptionsProvider.cs b/src/StackExchange.Redis/Configuration/RedisEnterpriseOptionsProvider.cs
index aafe4c54d..fb1f47caf 100644
--- a/src/StackExchange.Redis/Configuration/RedisEnterpriseOptionsProvider.cs
+++ b/src/StackExchange.Redis/Configuration/RedisEnterpriseOptionsProvider.cs
@@ -31,20 +31,16 @@ public class RedisEnterpriseOptionsProvider : DefaultOptionsProvider
///
public override string ConfigurationChannel => "";
- // Auto-enlistment, deliberately withheld for now; maintenance notifications ship purely opt-in, and
- // this goes back in a follow-up once the feature has been through formal acceptance testing. Kept here
- // commented rather than deleted so that what returns is exactly what was reviewed.
- //
- // Note this provider is reached only by naming it (defaults=enterprise), never by endpoint matching,
- // so restoring it enlists nobody who did not already ask for this deployment posture. It is withheld
- // anyway, so that in this release the *only* thing that turns the feature on is maintNotifications.
- //
- // Auto rather than Enabled: a cluster that has not been updated yet, or has the feature switched off,
- // must keep working. Choose Enabled explicitly if you would rather a connection be refused than run
- // without advance warning.
- //
- // [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
- // public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
+ ///
+ /// Ask for maintenance notifications, tolerating a server that doesn't offer them.
+ ///
+ ///
+ /// rather than
+ /// : a cluster that has not been updated yet, or has
+ /// the feature switched off, must keep working. Choose Enabled explicitly if you would rather a
+ /// connection be refused than run without advance warning.
+ ///
+ public override MaintenanceNotificationMode MaintenanceNotifications => MaintenanceNotificationMode.Auto;
// Note: no GetDefaultSsl and no DefaultVersion override. Both are deployment choices here rather than
// properties of the product - TLS is configured per database, and the version is whatever was
diff --git a/src/StackExchange.Redis/ConfigurationOptions.cs b/src/StackExchange.Redis/ConfigurationOptions.cs
index 5b75fd4ed..1dae28c9a 100644
--- a/src/StackExchange.Redis/ConfigurationOptions.cs
+++ b/src/StackExchange.Redis/ConfigurationOptions.cs
@@ -1599,7 +1599,6 @@ public RedisProtocol? Protocol
/// configure for a group. Expect the restriction to be lifted.
///
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public MaintenanceNotificationMode MaintenanceNotifications
{
get => HasValue(OptionFlags.MaintenanceNotificationsHasValue) ? _maintenanceNotifications : Defaults.MaintenanceNotifications;
@@ -1616,7 +1615,6 @@ public MaintenanceNotificationMode MaintenanceNotifications
/// a client that wants a named replacement should ask for one. Prefer an FQDN form under TLS: an address
/// cannot be validated against a certificate carrying only DNS names.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public MaintenanceEndpointType MaintenanceMovingEndpointType
{
get => HasValue(OptionFlags.MaintenanceMovingEndpointTypeHasValue)
@@ -1636,7 +1634,6 @@ public MaintenanceEndpointType MaintenanceMovingEndpointType
/// relaxed; keep-alive, the heartbeat and connection-failure detection are deliberately untouched, so
/// a server that dies mid-maintenance is still noticed on the usual schedule.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public TimeSpan MaintenanceRelaxedTimeout
{
get => HasValue(OptionFlags.MaintenanceRelaxedTimeoutHasValue) ? _maintenanceRelaxedTimeout : Defaults.MaintenanceRelaxedTimeout;
@@ -1652,7 +1649,6 @@ public TimeSpan MaintenanceRelaxedTimeout
/// closes early, since relaxation delays the point at which a genuinely slow server surfaces as a
/// timeout. Expressed in seconds in a configuration string.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public TimeSpan MaintenanceRelaxedWindowMax
{
get => HasValue(OptionFlags.MaintenanceRelaxedWindowMaxHasValue)
@@ -1672,7 +1668,6 @@ public TimeSpan MaintenanceRelaxedWindowMax
/// : in that case nothing told us the event finished, and
/// extending past the backstop would defeat it. Expressed in seconds in a configuration string.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public TimeSpan MaintenancePostEventRelaxedDuration
{
get => HasValue(OptionFlags.MaintenancePostEventRelaxedDurationHasValue)
diff --git a/src/StackExchange.Redis/Maintenance/ClusterSlotMigration.cs b/src/StackExchange.Redis/Maintenance/ClusterSlotMigration.cs
index 7a9b7d950..39f0c841f 100644
--- a/src/StackExchange.Redis/Maintenance/ClusterSlotMigration.cs
+++ b/src/StackExchange.Redis/Maintenance/ClusterSlotMigration.cs
@@ -14,7 +14,6 @@ namespace StackExchange.Redis.Maintenance;
/// that sent it - every node in the cluster reports the same movements, so the sender is not implicitly the
/// source.
///
-[Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public readonly struct ClusterSlotMigration
{
internal ClusterSlotMigration(EndPoint? source, EndPoint? target, IReadOnlyList slots, string? raw)
diff --git a/src/StackExchange.Redis/Maintenance/MaintenanceFaultSurface.cs b/src/StackExchange.Redis/Maintenance/MaintenanceFaultSurface.cs
index fbcae6149..e7bb2044e 100644
--- a/src/StackExchange.Redis/Maintenance/MaintenanceFaultSurface.cs
+++ b/src/StackExchange.Redis/Maintenance/MaintenanceFaultSurface.cs
@@ -34,7 +34,6 @@ public sealed partial class RedisTimeoutException
/// occasionally naming a window that a *different*, later command merely followed.
///
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public MaintenanceNotificationType MaintenanceType { get; internal init; }
}
@@ -50,6 +49,5 @@ public sealed partial class RedisConnectionException
/// its deadline surfaces either way round: as a timeout when the command was already in flight, and as a
/// connection fault when the endpoint went away underneath it.
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public MaintenanceNotificationType MaintenanceType { get; internal init; }
}
diff --git a/src/StackExchange.Redis/Maintenance/MaintenanceNotificationType.cs b/src/StackExchange.Redis/Maintenance/MaintenanceNotificationType.cs
index ae66e4ce2..7ae80b57f 100644
--- a/src/StackExchange.Redis/Maintenance/MaintenanceNotificationType.cs
+++ b/src/StackExchange.Redis/Maintenance/MaintenanceNotificationType.cs
@@ -12,7 +12,6 @@ namespace StackExchange.Redis.Maintenance;
/// ). Unrecognized types are dropped rather than surfaced, so no member here means
/// "something we didn't understand".
///
-[Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public enum MaintenanceNotificationType
{
///
diff --git a/src/StackExchange.Redis/Maintenance/PushMaintenanceEvent.cs b/src/StackExchange.Redis/Maintenance/PushMaintenanceEvent.cs
index 67d2ac955..28bdf1a0b 100644
--- a/src/StackExchange.Redis/Maintenance/PushMaintenanceEvent.cs
+++ b/src/StackExchange.Redis/Maintenance/PushMaintenanceEvent.cs
@@ -24,7 +24,6 @@ namespace StackExchange.Redis.Maintenance;
/// what to do with it.
///
///
-[Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public sealed class PushMaintenanceEvent : ServerMaintenanceEvent
{
internal PushMaintenanceEvent(
diff --git a/src/StackExchange.Redis/MaintenanceEndpointType.cs b/src/StackExchange.Redis/MaintenanceEndpointType.cs
index 8f0639e1c..15e1bfa91 100644
--- a/src/StackExchange.Redis/MaintenanceEndpointType.cs
+++ b/src/StackExchange.Redis/MaintenanceEndpointType.cs
@@ -21,7 +21,6 @@ namespace StackExchange.Redis;
/// connecting with TLS.
///
///
-[Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public enum MaintenanceEndpointType
{
///
diff --git a/src/StackExchange.Redis/MaintenanceNotificationMode.cs b/src/StackExchange.Redis/MaintenanceNotificationMode.cs
index fc7c15623..5d08de275 100644
--- a/src/StackExchange.Redis/MaintenanceNotificationMode.cs
+++ b/src/StackExchange.Redis/MaintenanceNotificationMode.cs
@@ -19,7 +19,6 @@ namespace StackExchange.Redis;
/// this is the one place they are easy to misread.
///
///
-[Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
public enum MaintenanceNotificationMode
{
///
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
index 8920089de..dca665b06 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Shipped.txt
@@ -102,7 +102,7 @@ StackExchange.Redis.Availability.FaultContext.FaultContext() -> void
StackExchange.Redis.Availability.FaultContext.FaultContext(System.Exception! fault) -> void
StackExchange.Redis.Availability.FaultContext.Flags.get -> StackExchange.Redis.CommandFlags
StackExchange.Redis.Availability.FaultContext.IsFault.get -> bool
-[SER010]StackExchange.Redis.Availability.FaultContext.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Availability.FaultContext.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
StackExchange.Redis.Availability.FaultContext.NotApplied.get -> bool
StackExchange.Redis.Availability.GroupConnectionChangedEventArgs
StackExchange.Redis.Availability.GroupConnectionChangedEventArgs.ChangeType
@@ -584,11 +584,11 @@ virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.KeepAliveInterv
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryName.get -> string!
static StackExchange.Redis.Configuration.DefaultOptionsProvider.LibraryVersion.get -> string!
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.LoggerFactory.get -> Microsoft.Extensions.Logging.ILoggerFactory?
-[SER010]virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceMovingEndpointType.get -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
-[SER010]virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenancePostEventRelaxedDuration.get -> System.TimeSpan?
-[SER010]virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceRelaxedTimeout.get -> System.TimeSpan
-[SER010]virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceRelaxedWindowMax.get -> System.TimeSpan?
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceMovingEndpointType.get -> StackExchange.Redis.MaintenanceEndpointType
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenancePostEventRelaxedDuration.get -> System.TimeSpan?
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceRelaxedTimeout.get -> System.TimeSpan
+virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.MaintenanceRelaxedWindowMax.get -> System.TimeSpan?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Name.get -> string?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Password.get -> string?
virtual StackExchange.Redis.Configuration.DefaultOptionsProvider.Protocol.get -> StackExchange.Redis.RedisProtocol?
@@ -731,16 +731,16 @@ StackExchange.Redis.ConfigurationOptions.LibraryName.get -> string?
StackExchange.Redis.ConfigurationOptions.LibraryName.set -> void
StackExchange.Redis.ConfigurationOptions.LoggerFactory.get -> Microsoft.Extensions.Logging.ILoggerFactory?
StackExchange.Redis.ConfigurationOptions.LoggerFactory.set -> void
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceMovingEndpointType.get -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceMovingEndpointType.set -> void
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceNotifications.set -> void
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenancePostEventRelaxedDuration.get -> System.TimeSpan
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenancePostEventRelaxedDuration.set -> void
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedTimeout.get -> System.TimeSpan
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedTimeout.set -> void
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedWindowMax.get -> System.TimeSpan
-[SER010]StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedWindowMax.set -> void
+StackExchange.Redis.ConfigurationOptions.MaintenanceMovingEndpointType.get -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.ConfigurationOptions.MaintenanceMovingEndpointType.set -> void
+StackExchange.Redis.ConfigurationOptions.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
+StackExchange.Redis.ConfigurationOptions.MaintenanceNotifications.set -> void
+StackExchange.Redis.ConfigurationOptions.MaintenancePostEventRelaxedDuration.get -> System.TimeSpan
+StackExchange.Redis.ConfigurationOptions.MaintenancePostEventRelaxedDuration.set -> void
+StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedTimeout.get -> System.TimeSpan
+StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedTimeout.set -> void
+StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedWindowMax.get -> System.TimeSpan
+StackExchange.Redis.ConfigurationOptions.MaintenanceRelaxedWindowMax.set -> void
static StackExchange.Redis.ConfigurationOptions.Parse(string! configuration) -> StackExchange.Redis.ConfigurationOptions!
static StackExchange.Redis.ConfigurationOptions.Parse(string! configuration, bool ignoreUnknown) -> StackExchange.Redis.ConfigurationOptions!
StackExchange.Redis.ConfigurationOptions.Password.get -> string?
@@ -2202,48 +2202,48 @@ StackExchange.Redis.Maintenance.AzureNotificationType.NodeMaintenanceScheduled =
StackExchange.Redis.Maintenance.AzureNotificationType.NodeMaintenanceStart = 3 -> StackExchange.Redis.Maintenance.AzureNotificationType
StackExchange.Redis.Maintenance.AzureNotificationType.NodeMaintenanceStarting = 2 -> StackExchange.Redis.Maintenance.AzureNotificationType
StackExchange.Redis.Maintenance.AzureNotificationType.Unknown = 0 -> StackExchange.Redis.Maintenance.AzureNotificationType
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration.ClusterSlotMigration() -> void
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration.RawSlots.get -> string?
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration.Slots.get -> System.Collections.Generic.IReadOnlyList!
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration.Source.get -> System.Net.EndPoint?
-[SER010]StackExchange.Redis.Maintenance.ClusterSlotMigration.Target.get -> System.Net.EndPoint?
-[SER010]override StackExchange.Redis.Maintenance.ClusterSlotMigration.ToString() -> string!
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.FailedOver = 5 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.FailingOver = 4 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.Migrated = 3 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.Migrating = 2 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.Moving = 1 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.None = 0 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.SlotMigrated = 7 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.MaintenanceNotificationType.SlotMigrating = 6 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.EndPoint.get -> System.Net.EndPoint?
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.NewEndPoint.get -> System.Net.EndPoint?
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.NotificationType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.Payload.get -> string?
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.SequenceId.get -> long
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.SlotMigrations.get -> System.Collections.Generic.IReadOnlyList!
-[SER010]StackExchange.Redis.Maintenance.PushMaintenanceEvent.Time.get -> System.TimeSpan?
-[SER010]override StackExchange.Redis.Maintenance.PushMaintenanceEvent.ToString() -> string?
+StackExchange.Redis.Maintenance.ClusterSlotMigration
+StackExchange.Redis.Maintenance.ClusterSlotMigration.ClusterSlotMigration() -> void
+StackExchange.Redis.Maintenance.ClusterSlotMigration.RawSlots.get -> string?
+StackExchange.Redis.Maintenance.ClusterSlotMigration.Slots.get -> System.Collections.Generic.IReadOnlyList!
+StackExchange.Redis.Maintenance.ClusterSlotMigration.Source.get -> System.Net.EndPoint?
+StackExchange.Redis.Maintenance.ClusterSlotMigration.Target.get -> System.Net.EndPoint?
+override StackExchange.Redis.Maintenance.ClusterSlotMigration.ToString() -> string!
+StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.FailedOver = 5 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.FailingOver = 4 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.Migrated = 3 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.Migrating = 2 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.Moving = 1 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.None = 0 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.SlotMigrated = 7 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.MaintenanceNotificationType.SlotMigrating = 6 -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.PushMaintenanceEvent
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.EndPoint.get -> System.Net.EndPoint?
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.NewEndPoint.get -> System.Net.EndPoint?
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.NotificationType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.Payload.get -> string?
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.SequenceId.get -> long
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.SlotMigrations.get -> System.Collections.Generic.IReadOnlyList!
+StackExchange.Redis.Maintenance.PushMaintenanceEvent.Time.get -> System.TimeSpan?
+override StackExchange.Redis.Maintenance.PushMaintenanceEvent.ToString() -> string?
StackExchange.Redis.Maintenance.ServerMaintenanceEvent
StackExchange.Redis.Maintenance.ServerMaintenanceEvent.RawMessage.get -> string?
StackExchange.Redis.Maintenance.ServerMaintenanceEvent.ReceivedTimeUtc.get -> System.DateTime
StackExchange.Redis.Maintenance.ServerMaintenanceEvent.StartTimeUtc.get -> System.DateTime?
override StackExchange.Redis.Maintenance.ServerMaintenanceEvent.ToString() -> string?
-[SER010]StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.Auto = 1 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.ExternalFqdn = 5 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.ExternalIp = 4 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.InternalFqdn = 3 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.InternalIp = 2 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.None = 6 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceEndpointType.ServerDefault = 0 -> StackExchange.Redis.MaintenanceEndpointType
-[SER010]StackExchange.Redis.MaintenanceNotificationMode
-[SER010]StackExchange.Redis.MaintenanceNotificationMode.Auto = 2 -> StackExchange.Redis.MaintenanceNotificationMode
-[SER010]StackExchange.Redis.MaintenanceNotificationMode.Disabled = 0 -> StackExchange.Redis.MaintenanceNotificationMode
-[SER010]StackExchange.Redis.MaintenanceNotificationMode.Enabled = 1 -> StackExchange.Redis.MaintenanceNotificationMode
+StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.Auto = 1 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.ExternalFqdn = 5 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.ExternalIp = 4 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.InternalFqdn = 3 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.InternalIp = 2 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.None = 6 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceEndpointType.ServerDefault = 0 -> StackExchange.Redis.MaintenanceEndpointType
+StackExchange.Redis.MaintenanceNotificationMode
+StackExchange.Redis.MaintenanceNotificationMode.Auto = 2 -> StackExchange.Redis.MaintenanceNotificationMode
+StackExchange.Redis.MaintenanceNotificationMode.Disabled = 0 -> StackExchange.Redis.MaintenanceNotificationMode
+StackExchange.Redis.MaintenanceNotificationMode.Enabled = 1 -> StackExchange.Redis.MaintenanceNotificationMode
StackExchange.Redis.MigrateOptions
StackExchange.Redis.MigrateOptions.Copy = 1 -> StackExchange.Redis.MigrateOptions
StackExchange.Redis.MigrateOptions.None = 0 -> StackExchange.Redis.MigrateOptions
@@ -2415,7 +2415,7 @@ StackExchange.Redis.RedisConnectionException.CommandStatus.get -> StackExchange.
StackExchange.Redis.RedisConnectionException.FailureType.get -> StackExchange.Redis.ConnectionFailureType
StackExchange.Redis.RedisConnectionException.Flags.get -> StackExchange.Redis.CommandFlags
override StackExchange.Redis.RedisConnectionException.GetObjectData(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void
-[SER010]StackExchange.Redis.RedisConnectionException.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.RedisConnectionException.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
StackExchange.Redis.RedisConnectionException.RedisConnectionException(StackExchange.Redis.ConnectionFailureType failureType, StackExchange.Redis.CommandFlags flags, string! message, System.Exception? innerException = null, StackExchange.Redis.CommandStatus commandStatus = StackExchange.Redis.CommandStatus.Unknown) -> void
StackExchange.Redis.RedisConnectionException.RedisConnectionException(StackExchange.Redis.ConnectionFailureType failureType, string! message) -> void
StackExchange.Redis.RedisConnectionException.RedisConnectionException(StackExchange.Redis.ConnectionFailureType failureType, string! message, System.Exception? innerException) -> void
@@ -2616,7 +2616,7 @@ StackExchange.Redis.RedisTimeoutException
StackExchange.Redis.RedisTimeoutException.Commandstatus.get -> StackExchange.Redis.CommandStatus
StackExchange.Redis.RedisTimeoutException.Flags.get -> StackExchange.Redis.CommandFlags
override StackExchange.Redis.RedisTimeoutException.GetObjectData(System.Runtime.Serialization.SerializationInfo! info, System.Runtime.Serialization.StreamingContext context) -> void
-[SER010]StackExchange.Redis.RedisTimeoutException.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
+StackExchange.Redis.RedisTimeoutException.MaintenanceType.get -> StackExchange.Redis.Maintenance.MaintenanceNotificationType
StackExchange.Redis.RedisTimeoutException.RedisTimeoutException(StackExchange.Redis.CommandFlags flags, string! message, StackExchange.Redis.CommandStatus commandStatus) -> void
StackExchange.Redis.RedisTimeoutException.RedisTimeoutException(string! message, StackExchange.Redis.CommandStatus commandStatus) -> void
StackExchange.Redis.RedisType
diff --git a/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt b/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
index ab058de62..444a5d1fb 100644
--- a/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
+++ b/src/StackExchange.Redis/PublicAPI/PublicAPI.Unshipped.txt
@@ -1 +1,4 @@
#nullable enable
+override StackExchange.Redis.Configuration.AzureManagedRedisOptionsProvider.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
+override StackExchange.Redis.Configuration.RedisCloudOptionsProvider.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
+override StackExchange.Redis.Configuration.RedisEnterpriseOptionsProvider.MaintenanceNotifications.get -> StackExchange.Redis.MaintenanceNotificationMode
diff --git a/src/StackExchange.Redis/ServerEndPoint.Maintenance.cs b/src/StackExchange.Redis/ServerEndPoint.Maintenance.cs
index 315ab9565..6b0c4c46e 100644
--- a/src/StackExchange.Redis/ServerEndPoint.Maintenance.cs
+++ b/src/StackExchange.Redis/ServerEndPoint.Maintenance.cs
@@ -41,7 +41,6 @@ internal sealed partial class ServerEndPoint
/// cannot be made.
///
///
- [Experimental(Experiments.MaintenanceNotifications, UrlFormat = Experiments.UrlFormat)]
private MaintenanceNotificationMode MaintenanceMode
=> Multiplexer.IsGroupMember
? MaintenanceNotificationMode.Disabled
diff --git a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
index 445027bd4..1f508f262 100644
--- a/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
+++ b/tests/StackExchange.Redis.Tests/DefaultOptionsTests.cs
@@ -197,17 +197,17 @@ public void RedisCloudDoesNotInheritTheAzureManagedAssumptions()
}
[Theory]
- [InlineData("contoso.redis.azure.net", MaintenanceNotificationMode.Disabled)] // AMR: will be Auto
- [InlineData("contoso.cloud.redislabs.com", MaintenanceNotificationMode.Disabled)] // Redis Cloud: will be Auto
+ [InlineData("contoso.redis.azure.net", MaintenanceNotificationMode.Auto)] // AMR
+ [InlineData("contoso.cloud.redislabs.com", MaintenanceNotificationMode.Auto)] // Redis Cloud
[InlineData("contoso.redis.cache.windows.net", MaintenanceNotificationMode.Disabled)] // classic Azure: stays off
[InlineData("contoso.example.com", MaintenanceNotificationMode.Disabled)] // and so does anything unrecognized
public void MaintenanceNotificationDefaultPerProvider(string hostName, MaintenanceNotificationMode expected)
{
- // Every endpoint is Disabled for now: maintenance notifications ship purely opt-in, so *nothing*
- // enlists you and the only thing that turns them on is setting maintNotifications yourself. The
- // providers for AMR and Redis Cloud are intended to select Auto - see the commented-out overrides on
- // each - and this theory is what flips back when auto-enlistment lands: the first two rows become
- // Auto, and the last two stay Disabled because nothing recognizes them either way.
+ // The recognized hosted families enlist automatically, which is the whole point of the providers: a
+ // connection string that names nothing but the hostname gets the feature. Auto rather than Enabled so
+ // that a deployment which cannot deliver keeps working - the opt-in is refused and the feature stays
+ // off. The last two rows stay Disabled because nothing recognizes them either way, and they are what
+ // stops this test passing merely because everything returns the same answer.
var epc = new EndPointCollection(new List() { new DnsEndPoint(hostName, 0) });
var provider = DefaultOptionsProvider.GetProvider(epc);
Output.WriteLine($"{hostName} -> {provider.GetType().Name}");
diff --git a/toys/MaintenanceSoak/MaintenanceSoak.csproj b/toys/MaintenanceSoak/MaintenanceSoak.csproj
index 0591dff3c..323c4302f 100644
--- a/toys/MaintenanceSoak/MaintenanceSoak.csproj
+++ b/toys/MaintenanceSoak/MaintenanceSoak.csproj
@@ -7,10 +7,9 @@
StackExchange.Redis.MaintenanceSoak
true
-
-
- $(NoWarn);SER010;StringToRedisValue
+
+ $(NoWarn);StringToRedisValue
diff --git a/toys/MaintenanceWatch/MaintenanceWatch.csproj b/toys/MaintenanceWatch/MaintenanceWatch.csproj
index b400a6ced..13da82378 100644
--- a/toys/MaintenanceWatch/MaintenanceWatch.csproj
+++ b/toys/MaintenanceWatch/MaintenanceWatch.csproj
@@ -4,8 +4,6 @@
Exe
net10.0
enable
-
- $(NoWarn);SER010