From e88751c69205304c07b813680e61fdb5b92c4f76 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 13:38:32 +0000 Subject: [PATCH 01/14] consumable notification shared config for brig and gundeck --- charts/wire-server/templates/brig/configmap.yaml | 1 + charts/wire-server/templates/gundeck/configmap.yaml | 1 + charts/wire-server/values.yaml | 2 ++ hack/helm_vars/wire-server/values.yaml.gotmpl | 2 ++ services/brig/brig.integration.yaml | 1 + services/brig/src/Brig/Options.hs | 4 +++- services/gundeck/gundeck.integration.yaml | 1 + services/gundeck/src/Gundeck/Options.hs | 4 +++- 8 files changed, 14 insertions(+), 2 deletions(-) diff --git a/charts/wire-server/templates/brig/configmap.yaml b/charts/wire-server/templates/brig/configmap.yaml index d5aa494f26c..1d39fee9334 100644 --- a/charts/wire-server/templates/brig/configmap.yaml +++ b/charts/wire-server/templates/brig/configmap.yaml @@ -394,5 +394,6 @@ data: {{- if hasKey . "setNomadProfiles" }} setNomadProfiles: {{ index . "setNomadProfiles" }} {{- end }} + setConsumableNotifications: {{ $.Values.consumableNotifications }} {{- end }} {{- end }} diff --git a/charts/wire-server/templates/gundeck/configmap.yaml b/charts/wire-server/templates/gundeck/configmap.yaml index 6a107a8e2fd..66af5c9f969 100644 --- a/charts/wire-server/templates/gundeck/configmap.yaml +++ b/charts/wire-server/templates/gundeck/configmap.yaml @@ -96,5 +96,6 @@ data: {{- if hasKey . "cellsEventQueue" }} cellsEventQueue: {{ .cellsEventQueue }} {{- end }} + consumableNotifications: {{ $.Values.consumableNotifications }} {{- end }} diff --git a/charts/wire-server/values.yaml b/charts/wire-server/values.yaml index f7afb73b550..79e84d8fb35 100644 --- a/charts/wire-server/values.yaml +++ b/charts/wire-server/values.yaml @@ -12,6 +12,8 @@ tags: mlsstats: false integration: false +consumableNotifications: false + galley: replicaCount: 3 image: diff --git a/hack/helm_vars/wire-server/values.yaml.gotmpl b/hack/helm_vars/wire-server/values.yaml.gotmpl index 88386340f99..5255592075c 100644 --- a/hack/helm_vars/wire-server/values.yaml.gotmpl +++ b/hack/helm_vars/wire-server/values.yaml.gotmpl @@ -6,6 +6,8 @@ tags: sftd: false integration: true +consumableNotifications: false + cassandra-migrations: imagePullPolicy: {{ .Values.imagePullPolicy }} cassandra: diff --git a/services/brig/brig.integration.yaml b/services/brig/brig.integration.yaml index 7d39b7166de..fc23b069f74 100644 --- a/services/brig/brig.integration.yaml +++ b/services/brig/brig.integration.yaml @@ -267,6 +267,7 @@ optSettings: maxRateLimitedKeys: 100000 # Estimated memory usage: 4 MB setChallengeTTL: 172800 setEphemeralUserCreationEnabled: true + setConsumableNotifications: false logLevel: Warn logNetStrings: false diff --git a/services/brig/src/Brig/Options.hs b/services/brig/src/Brig/Options.hs index 47122739bd2..91cf542e487 100644 --- a/services/brig/src/Brig/Options.hs +++ b/services/brig/src/Brig/Options.hs @@ -591,7 +591,9 @@ data Settings = Settings -- | Whether to allow ephemeral user creation ephemeralUserCreationEnabled :: !Bool, -- | Determines if this backend supports nomad profiles. - nomadProfiles :: !(Maybe Bool) + nomadProfiles :: !(Maybe Bool), + -- | Determines if consumable notifications are enabled + consumableNotifications :: !Bool } deriving (Show, Generic) diff --git a/services/gundeck/gundeck.integration.yaml b/services/gundeck/gundeck.integration.yaml index 1c33557402a..00c80574794 100644 --- a/services/gundeck/gundeck.integration.yaml +++ b/services/gundeck/gundeck.integration.yaml @@ -55,6 +55,7 @@ settings: # brig, cannon, cargohold, galley, gundeck, proxy, spar. disabledAPIVersions: [] cellsEventQueue: "cells_events" + consumableNotifications: false logLevel: Warn logNetStrings: false diff --git a/services/gundeck/src/Gundeck/Options.hs b/services/gundeck/src/Gundeck/Options.hs index ee55c98bebe..d70bbc4f91d 100644 --- a/services/gundeck/src/Gundeck/Options.hs +++ b/services/gundeck/src/Gundeck/Options.hs @@ -84,7 +84,9 @@ data Settings = Settings -- notifications from the database if notifications have inlined payloads. _internalPageSize :: Maybe Int32, -- | The name of the RabbitMQ queue to be used to forward events to Cells. - _cellsEventQueue :: !(Maybe Text) + _cellsEventQueue :: !(Maybe Text), + -- | Determines if consumable notifications are enabled + _consumableNotifications :: !Bool } deriving (Show, Generic) From a920df211c3fc0eb79cef92f6d3ff1fb2df3ffa5 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 13:39:12 +0000 Subject: [PATCH 02/14] make target to help render helm ci values --- Makefile | 4 ++++ hack/bin/helm-render-ci-values.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100755 hack/bin/helm-render-ci-values.sh diff --git a/Makefile b/Makefile index b161c0d1123..3cfcc79a36a 100644 --- a/Makefile +++ b/Makefile @@ -691,6 +691,10 @@ diff-live-manifest: clean-charts charts-integration OUTPUT_FILE="/tmp/wire-server.yaml" ./hack/bin/render-manifest.sh "$(LIVE_VALUES_FILE)"; \ DIFF_OUTPUT_FILE="$(DIFF_OUTPUT_FILE)" ./hack/bin/diff-wire-server-manifests.sh "$(LIVE_MANIFEST_FILE)" /tmp/wire-server.yaml +render-ci-manifest: clean-charts charts-integration + ./hack/bin/helm-render-ci-values.sh + ./hack/bin/render-manifest.sh /tmp/wire-server-test-a.yaml + sbom.json: nix -Lv build '.#wireServer.bomDependencies' && \ nix run 'github:wireapp/tom-bombadil#create-sbom' -- --root-package-name "wire-server" diff --git a/hack/bin/helm-render-ci-values.sh b/hack/bin/helm-render-ci-values.sh new file mode 100755 index 00000000000..09c8bd62077 --- /dev/null +++ b/hack/bin/helm-render-ci-values.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# best run via make render-wire-server-resources +# otherwise run make clean-charts and make charts-integration before + +set -euo pipefail + +# from repo root +export NAMESPACE_1="${NAMESPACE_1:-test-a}" +export NAMESPACE_2="${NAMESPACE_2:-test-b}" +export FEDERATION_DOMAIN_1="${FEDERATION_DOMAIN_1:-integration.example.com}" +export FEDERATION_DOMAIN_2="${FEDERATION_DOMAIN_2:-integration2.example.com}" +export FEDERATION_DOMAIN_BASE_1="${FEDERATION_DOMAIN_BASE_1:-example.com}" +export FEDERATION_DOMAIN_BASE_2="${FEDERATION_DOMAIN_BASE_2:-example.com}" +export FEDERATION_CA_CERTIFICATE="${FEDERATION_CA_CERTIFICATE:-$(cat services/nginz/integration-test/conf/nginz/integration-ca.pem)}" +export ENTERPRISE_IMAGE_PULL_SECRET="${ENTERPRISE_IMAGE_PULL_SECRET:-{}}" + +helmfile -f hack/helmfile.yaml.gotmpl \ + -e default \ + --skip-deps \ + -l name=wire-server \ + write-values \ + --output-file-template '/tmp/{{ .Release.Name }}-{{ .Release.Namespace }}.yaml' + +VALUES_FILE="/tmp/wire-server-${NAMESPACE_1}.yaml" + +echo "Rendered values: $VALUES_FILE" From f35a1c939ac73893e9bdf39b1e42c143c9e55348 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 13:40:02 +0000 Subject: [PATCH 03/14] guard setup of consumable notifications queues --- services/gundeck/src/Gundeck/API/Internal.hs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/services/gundeck/src/Gundeck/API/Internal.hs b/services/gundeck/src/Gundeck/API/Internal.hs index c1c1591ab8d..296b8f4f87e 100644 --- a/services/gundeck/src/Gundeck/API/Internal.hs +++ b/services/gundeck/src/Gundeck/API/Internal.hs @@ -22,11 +22,12 @@ module Gundeck.API.Internal where import Cassandra qualified -import Control.Lens (view) +import Control.Lens (view, (^.)) import Data.Id import Gundeck.Client import Gundeck.Client qualified as Client import Gundeck.Monad +import Gundeck.Options (consumableNotifications, settings) import Gundeck.Presence qualified as Presence import Gundeck.Push qualified as Push import Gundeck.Push.Data qualified as PushTok @@ -69,6 +70,8 @@ getPushTokensH uid = PushTok.PushTokenList <$> (view PushTok.addrPushToken <$$> registerConsumableNotificationsClient :: UserId -> ClientId -> Gundeck NoContent registerConsumableNotificationsClient uid cid = do - chan <- getRabbitMqChan - void . liftIO $ setupConsumableNotifications chan uid cid + enabled <- asks (^. options . settings . consumableNotifications) + when enabled $ do + chan <- getRabbitMqChan + void . liftIO $ setupConsumableNotifications chan uid cid pure NoContent From 58b5ac56913587e0a4ca1691793170cb01c115e6 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 15:15:02 +0000 Subject: [PATCH 04/14] disable based on setting --- services/brig/src/Brig/API/Client.hs | 6 ++++-- services/gundeck/src/Gundeck/Push.hs | 10 +++++++++- services/gundeck/test/unit/MockGundeck.hs | 1 + 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/services/brig/src/Brig/API/Client.hs b/services/brig/src/Brig/API/Client.hs index 89a0fc641f1..ce43b65844d 100644 --- a/services/brig/src/Brig/API/Client.hs +++ b/services/brig/src/Brig/API/Client.hs @@ -218,7 +218,8 @@ addClientWithReAuthPolicy policy luid@(tUnqualified -> u) con new = do (Data.addClientWithReAuthPolicy policy luid clientId' new maxPermClients mCaps) !>> ClientDataError let clt = clt0 {clientMLSPublicKeys = newClientMLSPublicKeys new} - when (supportsConsumableNotifications clt) $ lift $ liftSem $ do + consumableNotificationsEnabled <- asks (.settings.consumableNotifications) + when (consumableNotificationsEnabled && supportsConsumableNotifications clt) $ lift $ liftSem $ do setupConsumableNotifications u clt.clientId lift $ do for_ old $ execDelete u con @@ -253,13 +254,14 @@ updateClient :: (Handler r) () updateClient uid cid req = do client <- (lift (liftSem (ClientStore.lookupClient uid cid)) >>= maybe (throwE ClientNotFound) pure) !>> clientError + consumableNotificationsEnabled <- asks (.settings.consumableNotifications) lift . liftSem $ for_ req.updateClientLabel $ ClientStore.updateLabel uid cid . Just for_ req.updateClientCapabilities $ \caps -> do if client.clientCapabilities.fromClientCapabilityList `Set.isSubsetOf` caps.fromClientCapabilityList then do -- first set up the notification queues then save the data is more robust than the other way around let addedCapabilities = caps.fromClientCapabilityList \\ client.clientCapabilities.fromClientCapabilityList - when (ClientSupportsConsumableNotifications `Set.member` addedCapabilities) $ lift $ liftSem $ do + when (consumableNotificationsEnabled && ClientSupportsConsumableNotifications `Set.member` addedCapabilities) $ lift $ liftSem $ do setupConsumableNotifications uid cid lift . liftSem . ClientStore.updateCapabilities uid cid . Just $ caps else throwE $ clientError ClientCapabilitiesCannotBeRemoved diff --git a/services/gundeck/src/Gundeck/Push.hs b/services/gundeck/src/Gundeck/Push.hs index 3609bb5dfb0..7024e0057ae 100644 --- a/services/gundeck/src/Gundeck/Push.hs +++ b/services/gundeck/src/Gundeck/Push.hs @@ -104,6 +104,7 @@ push ps = do -- | Abstract over all effects in 'pushAll' (for unit testing). class (MonadThrow m) => MonadPushAll m where + mpaConsumableNotificationsEnabled :: m Bool mpaNotificationTTL :: m NotificationTTL mpaCellsEventQueue :: m (Maybe Text) mpaMkNotificationId :: m NotificationId @@ -117,6 +118,7 @@ class (MonadThrow m) => MonadPushAll m where mpaPublishToRabbitMq :: Text -> Text -> Q.Message -> m () instance MonadPushAll Gundeck where + mpaConsumableNotificationsEnabled = view (options . settings . consumableNotifications) mpaNotificationTTL = view (options . settings . notificationTTL) mpaCellsEventQueue = view (options . settings . cellsEventQueue) mpaMkNotificationId = mkNotificationId @@ -241,7 +243,13 @@ getClients uids = do pushAll :: (MonadPushAll m, MonadNativeTargets m, MonadMapAsync m, Log.MonadLogger m) => [Push] -> m () pushAll pushes = do Log.debug $ msg (val "pushing") . Log.field "pushes" (Aeson.encode pushes) - (rabbitmqPushes, legacyPushes, allUserClients) <- splitPushes pushes + consumableNotificationsEnabled <- mpaConsumableNotificationsEnabled + (rabbitmqPushes, legacyPushes, allUserClients) <- + if consumableNotificationsEnabled + then splitPushes pushes + else do + allUserClients <- mpaGetClients (Set.unions $ map (\p -> Set.map (._recipientId) $ p._pushRecipients) pushes) + pure ([], pushes, allUserClients) legacyNotifs <- mapM mkNewNotification legacyPushes pushAllLegacy legacyNotifs allUserClients diff --git a/services/gundeck/test/unit/MockGundeck.hs b/services/gundeck/test/unit/MockGundeck.hs index cb7b4f5fa88..f6d6ebe44f0 100644 --- a/services/gundeck/test/unit/MockGundeck.hs +++ b/services/gundeck/test/unit/MockGundeck.hs @@ -433,6 +433,7 @@ instance MonadThrow MockGundeck where -- as well crash badly here, as long as it doesn't go unnoticed...) instance MonadPushAll MockGundeck where + mpaConsumableNotificationsEnabled = pure True mpaNotificationTTL = pure $ NotificationTTL 300 -- (longer than we want any test to take.) mpaCellsEventQueue = pure $ Just "cells" mpaMkNotificationId = mockMkNotificationId From 9e90bf2c4ab4e72ced691641594cd57b7820d3e0 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 15:50:44 +0000 Subject: [PATCH 05/14] explicitly enable consumable notifications in tests --- integration/test/Test/Events.hs | 150 +++++++++++++++++--------------- 1 file changed, 82 insertions(+), 68 deletions(-) diff --git a/integration/test/Test/Events.hs b/integration/test/Test/Events.hs index d85b42ba326..5f687d52a2a 100644 --- a/integration/test/Test/Events.hs +++ b/integration/test/Test/Events.hs @@ -55,8 +55,8 @@ import Testlib.ResourcePool import UnliftIO hiding (handle) testConsumeEventsOneWebSocket :: (HasCallStack) => App () -testConsumeEventsOneWebSocket = do - alice <- randomUser OwnDomain def +testConsumeEventsOneWebSocket = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def lastNotifResp <- retrying @@ -95,11 +95,13 @@ testConsumeEventsOneWebSocket = do testWebSocketTimeout :: (HasCallStack) => App () testWebSocketTimeout = withModifiedBackend - def - { cannonCfg = - setField "wsOpts.activityTimeout" (1000000 :: Int) - >=> setField "wsOpts.pongTimeout" (1000000 :: Int) - } + ( enableConsumableNotifications + def + { cannonCfg = + setField "wsOpts.activityTimeout" (1000000 :: Int) + >=> setField "wsOpts.pongTimeout" (1000000 :: Int) + } + ) $ \domain -> do alice <- randomUser domain def client <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 @@ -118,8 +120,8 @@ testWebSocketTimeout = withModifiedBackend $ assertFailure "Expected web socket timeout" testConsumeTempEvents :: (HasCallStack) => App () -testConsumeTempEvents = do - alice <- randomUser OwnDomain def +testConsumeTempEvents = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def client0 <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 clientId0 <- objId client0 @@ -160,7 +162,7 @@ testConsumeTempEvents = do testTemporaryQueuesAreDeletedAfterUse :: (HasCallStack) => App () testTemporaryQueuesAreDeletedAfterUse = do - startDynamicBackendsReturnResources [def] $ \[beResource] -> do + startDynamicBackendsReturnResources [enableConsumableNotifications def] $ \[beResource] -> do let domain = beResource.berDomain rabbitmqAdmin <- mkRabbitMqAdminClientForResource beResource [alice, bob] <- createAndConnectUsers [domain, domain] @@ -204,8 +206,8 @@ testTemporaryQueuesAreDeletedAfterUse = do queuesAfterWS.items `shouldMatchSet` [deadNotifsQueue, cellsEventsQueue, aliceClientQueue, backgroundJobsQueue] testSendMessageNoReturnToSenderWithConsumableNotificationsProteus :: (HasCallStack) => App () -testSendMessageNoReturnToSenderWithConsumableNotificationsProteus = do - (alice, tid, bob : _) <- createTeam OwnDomain 2 +testSendMessageNoReturnToSenderWithConsumableNotificationsProteus = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, tid, bob : _) <- createTeam domain 2 aliceOldClient <- addClient alice def >>= getJSON 201 aliceClient <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 aliceClientId <- objId aliceClient @@ -237,8 +239,8 @@ testSendMessageNoReturnToSenderWithConsumableNotificationsProteus = do assertNoEvent_ ws testEventsForSpecificClients :: (HasCallStack) => App () -testEventsForSpecificClients = do - alice <- randomUser OwnDomain def +testEventsForSpecificClients = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def uid <- objId alice client1 <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 cid1 <- objId client1 @@ -262,7 +264,7 @@ testEventsForSpecificClients = do "payload" .= [object ["hello" .= "client2"]] ] - GundeckInternal.postPush OwnDomain [eventForClient1, eventForClient2] >>= assertSuccess + GundeckInternal.postPush domain [eventForClient1, eventForClient2] >>= assertSuccess assertEvent ws1 $ \e -> e %. "data.event.payload.0.hello" `shouldMatch` "client1" @@ -273,9 +275,9 @@ testEventsForSpecificClients = do $ assertNoEvent_ wsTemp testConsumeEventsForDifferentUsers :: (HasCallStack) => App () -testConsumeEventsForDifferentUsers = do - alice <- randomUser OwnDomain def - bob <- randomUser OwnDomain def +testConsumeEventsForDifferentUsers = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def + bob <- randomUser domain def aliceClient <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 aliceClientId <- objId aliceClient @@ -299,8 +301,8 @@ testConsumeEventsForDifferentUsers = do sendAck ws deliveryTag False testConsumeEventsWhileHavingLegacyClients :: (HasCallStack) => App () -testConsumeEventsWhileHavingLegacyClients = do - alice <- randomUser OwnDomain def +testConsumeEventsWhileHavingLegacyClients = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def -- Even if alice has no clients, the notifications should still be persisted -- in Cassandra. This choice is kinda arbitrary as these notifications @@ -333,8 +335,8 @@ testConsumeEventsWhileHavingLegacyClients = do resp.json %. "notifications.1.payload.0.type" `shouldMatch` "user.client-add" testConsumeEventsAcks :: (HasCallStack) => App () -testConsumeEventsAcks = do - alice <- randomUser OwnDomain def +testConsumeEventsAcks = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def client <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 clientId <- objId client @@ -355,8 +357,8 @@ testConsumeEventsAcks = do assertNoEvent_ ws testConsumeEventsMultipleAcks :: (HasCallStack) => App () -testConsumeEventsMultipleAcks = do - alice <- randomUser OwnDomain def +testConsumeEventsMultipleAcks = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def client <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 clientId <- objId client @@ -379,8 +381,8 @@ testConsumeEventsMultipleAcks = do assertNoEvent_ ws testConsumeEventsAckNewEventWithoutAckingOldOne :: (HasCallStack) => App () -testConsumeEventsAckNewEventWithoutAckingOldOne = do - alice <- randomUser OwnDomain def +testConsumeEventsAckNewEventWithoutAckingOldOne = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def client <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 clientId <- objId client @@ -415,7 +417,7 @@ testConsumeEventsAckNewEventWithoutAckingOldOne = do testEventsDeadLettered :: (HasCallStack) => App () testEventsDeadLettered = do let notifTTL = 1 # Second - withModifiedBackend (def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)}) $ \domain -> do + withModifiedBackend (enableConsumableNotifications (def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)})) $ \domain -> do alice <- randomUser domain def -- This generates an event @@ -449,7 +451,7 @@ testEventsDeadLettered = do testEventsDeadLetteredWithReconnect :: (HasCallStack) => App () testEventsDeadLetteredWithReconnect = do let notifTTL = 1 # Second - startDynamicBackendsReturnResources [def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)}] $ \[resources] -> do + startDynamicBackendsReturnResources [enableConsumableNotifications (def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)})] $ \[resources] -> do let domain :: String = resources.berDomain alice <- randomUser domain def @@ -501,7 +503,7 @@ testEventsDeadLetteredWithReconnect = do testTransientEventsDoNotTriggerDeadLetters :: (HasCallStack) => App () testTransientEventsDoNotTriggerDeadLetters = do let notifTTL = 1 # Second - withModifiedBackend (def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)}) $ \domain -> do + withModifiedBackend (enableConsumableNotifications (def {gundeckCfg = setField "settings.notificationTTL" (notifTTL #> Second)})) $ \domain -> do alice <- randomUser domain def -- Creates a non-transient event client <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 @@ -527,9 +529,9 @@ testTransientEventsDoNotTriggerDeadLetters = do assertNoEvent_ ws testTransientEvents :: (HasCallStack) => App () -testTransientEvents = do - (alice, _, _) <- mkUserPlusClient - (bob, _, bobClient) <- mkUserPlusClient +testTransientEvents = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, _, _) <- mkUserPlusClientWithDomain domain + (bob, _, bobClient) <- mkUserPlusClientWithDomain domain connectTwoUsers alice bob bobClientId <- objId bobClient @@ -567,11 +569,13 @@ testTransientEvents = do testChannelLimit :: (HasCallStack) => App () testChannelLimit = withModifiedBackend - ( def - { cannonCfg = - setField "rabbitMqMaxChannels" (2 :: Int) - >=> setField "rabbitMqMaxConnections" (1 :: Int) - } + ( enableConsumableNotifications + ( def + { cannonCfg = + setField "rabbitMqMaxChannels" (2 :: Int) + >=> setField "rabbitMqMaxConnections" (1 :: Int) + } + ) ) $ \domain -> do alice <- randomUser domain def @@ -609,7 +613,7 @@ testChannelKilled = do void $ killAllRabbitMqConns backend waitUntilNoRabbitMqConns backend - runCodensity (startDynamicBackend backend def) $ \_ -> do + runCodensity (startDynamicBackend backend (enableConsumableNotifications def)) $ \_ -> do let domain = backend.berDomain alice <- randomUser domain def [c1, c2] <- @@ -643,8 +647,8 @@ testChannelKilled = do assertNoEventHelper ws `shouldMatch` WebSocketDied testSingleConsumer :: (HasCallStack) => App () -testSingleConsumer = do - alice <- randomUser OwnDomain def +testSingleConsumer = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + alice <- randomUser domain def clientId <- addClient alice def {acapabilities = Just ["consumable-notifications"]} >>= getJSON 201 @@ -682,8 +686,8 @@ testSingleConsumer = do lift $ assertNoEvent_ ws' testPrefetchCount :: (HasCallStack) => App () -testPrefetchCount = do - (alice, uid, cid) <- mkUserPlusClient +testPrefetchCount = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, uid, cid) <- mkUserPlusClientWithDomain domain emptyQueue alice cid for_ [1 :: Int .. 550] $ \i -> @@ -693,7 +697,7 @@ testPrefetchCount = do [ "recipients" .= [object ["user_id" .= uid, "clients" .= [cid], "route" .= "any"]], "payload" .= [object ["no" .= show i]] ] - GundeckInternal.postPush OwnDomain [event] >>= assertSuccess + GundeckInternal.postPush domain [event] >>= assertSuccess runCodensity (createEventsWebSocketWithSync alice (Just cid)) \(endMarker, ws) -> do es <- consumeAllEventsNoAck ws assertBool ("First 500 events expected, got " ++ show (length es)) $ length es == 500 @@ -704,11 +708,11 @@ testPrefetchCount = do assertBool "Receive at least one outstanding event" $ not (null es') testEndOfInitialSync :: (HasCallStack) => App () -testEndOfInitialSync = do - (alice, uid, cid) <- mkUserPlusClient +testEndOfInitialSync = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, uid, cid) <- mkUserPlusClientWithDomain domain let n = 20 replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess -- marker0 <- randomId runCodensity (createEventsWebSocketWithSync alice (Just cid)) \(endMarker, ws) -> do @@ -719,7 +723,7 @@ testEndOfInitialSync = do length (preExistingEvents <> otherEvents) `shouldMatchInt` (n + 2) -- more events should not be followed by the sync event - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess assertEvent ws $ \e -> do e %. "data.event.payload.0.type" `shouldMatch` "test" ackEvent ws e @@ -734,18 +738,18 @@ testEndOfInitialSync = do length events `shouldMatchInt` 1 -- more events should not be followed by synchronization event - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess assertEvent ws $ \e -> do e %. "data.event.payload.0.type" `shouldMatch` "test" ackEvent ws e assertNoEvent_ ws testEndOfInitialSyncMoreEventsAfterSyncMessage :: (HasCallStack) => App () -testEndOfInitialSyncMoreEventsAfterSyncMessage = do - (alice, uid, cid) <- mkUserPlusClient +testEndOfInitialSyncMoreEventsAfterSyncMessage = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, uid, cid) <- mkUserPlusClientWithDomain domain let n = 20 replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess runCodensity (createEventsWebSocketWithSync alice (Just cid)) \(endMarker, ws) -> do -- it seems this is needed to reduce flakiness, @@ -754,7 +758,7 @@ testEndOfInitialSyncMoreEventsAfterSyncMessage = do -- before consuming, we push n more events replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess preExistingEvents <- consumeEventsUntilEndOfInitialSync ws endMarker otherEvents <- consumeAllEvents ws @@ -765,14 +769,14 @@ testEndOfInitialSyncMoreEventsAfterSyncMessage = do `shouldMatch` True testEndOfInitialSyncIgnoreExpired :: (HasCallStack) => App () -testEndOfInitialSyncIgnoreExpired = do - (alice, uid, cid) <- mkUserPlusClient +testEndOfInitialSyncIgnoreExpired = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, uid, cid) <- mkUserPlusClientWithDomain domain let n = 20 replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid True] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid True] >>= assertSuccess -- Wait for transient events to expire Timeout.threadDelay (1 # Second) @@ -784,11 +788,11 @@ testEndOfInitialSyncIgnoreExpired = do length events `shouldMatchInt` (n + 2) -- +1 for the sync event, +1 for the client add event testEndOfInitialSyncAckMultiple :: (HasCallStack) => App () -testEndOfInitialSyncAckMultiple = do - (alice, uid, cid) <- mkUserPlusClient +testEndOfInitialSyncAckMultiple = withModifiedBackend (enableConsumableNotifications def) $ \domain -> do + (alice, uid, cid) <- mkUserPlusClientWithDomain domain let n = 20 replicateM_ n $ do - GundeckInternal.postPush OwnDomain [mkEvent uid cid False] >>= assertSuccess + GundeckInternal.postPush domain [mkEvent uid cid False] >>= assertSuccess runCodensity (createEventsWebSocketWithSync alice (Just cid)) $ \(endMarker, ws) -> do void $ assertEvent ws pure @@ -811,9 +815,9 @@ mkEvent uid cid transient = ] testTypingIndicatorIsNotSentToOwnClient :: (HasCallStack) => TaggedBool "federated" -> App () -testTypingIndicatorIsNotSentToOwnClient (TaggedBool federated) = do - (alice, _, aliceClient) <- mkUserPlusClientWithDomain OwnDomain - (bob, _, bobClient) <- mkUserPlusClientWithDomain (if federated then OtherDomain else OwnDomain) +testTypingIndicatorIsNotSentToOwnClient (TaggedBool federated) = startDynamicBackends [(enableConsumableNotifications def), (enableConsumableNotifications def)] $ \[domain, otherDomain] -> do + (alice, _, aliceClient) <- mkUserPlusClientWithDomain domain + (bob, _, bobClient) <- mkUserPlusClientWithDomain (if federated then otherDomain else domain) connectTwoUsers alice bob aliceClientId <- objId aliceClient bobClientId <- objId bobClient @@ -860,12 +864,14 @@ testBackendPusherRecoversFromQueueDeletion = do let remotesRefreshInterval = 10000 :: Int startDynamicBackendsReturnResources - [ def - { backgroundWorkerCfg = - setField - "backendNotificationPusher.remotesRefreshInterval" - remotesRefreshInterval - } + [ enableConsumableNotifications + ( def + { backgroundWorkerCfg = + setField + "backendNotificationPusher.remotesRefreshInterval" + remotesRefreshInterval + } + ) ] $ \[beResource] -> do let domain = beResource.berDomain @@ -1243,3 +1249,11 @@ mkRabbitMqAdminClientForResource backend = do opts <- asks (.rabbitMQConfig) servantClient <- liftIO $ mkRabbitMqAdminClientEnv opts {vHost = Text.pack backend.berVHost} pure . fromServant $ Servant.hoistClient (Proxy @(ToServant AdminAPI AsApi)) (liftIO @App) (toServant servantClient) + +enableConsumableNotifications :: ServiceOverrides -> ServiceOverrides +enableConsumableNotifications overrides = + overrides + <> def + { brigCfg = setField "optSettings.setConsumableNotifications" True, + gundeckCfg = setField "settings.consumableNotifications" True + } From 5626f687adf335431ef0d4a893056edf32de1dde Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 12 Mar 2026 15:52:55 +0000 Subject: [PATCH 06/14] changelog --- changelog.d/5-internal/WPB-23942 | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/5-internal/WPB-23942 diff --git a/changelog.d/5-internal/WPB-23942 b/changelog.d/5-internal/WPB-23942 new file mode 100644 index 00000000000..8b3d1ac5b06 --- /dev/null +++ b/changelog.d/5-internal/WPB-23942 @@ -0,0 +1 @@ +Make consumable notifications configureable and disable them by default From 63d1f862ce0e5a5edac84de9cd5597f80e7d99c8 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Fri, 13 Mar 2026 07:46:06 +0000 Subject: [PATCH 07/14] prevent no-op thread --- services/gundeck/src/Gundeck/Push.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gundeck/src/Gundeck/Push.hs b/services/gundeck/src/Gundeck/Push.hs index 7024e0057ae..9a7e8d5295c 100644 --- a/services/gundeck/src/Gundeck/Push.hs +++ b/services/gundeck/src/Gundeck/Push.hs @@ -255,7 +255,7 @@ pushAll pushes = do pushAllLegacy legacyNotifs allUserClients rabbitmqNotifs <- mapM mkNewNotification rabbitmqPushes - pushAllViaRabbitMq rabbitmqNotifs allUserClients + unless (null rabbitmqNotifs) $ pushAllViaRabbitMq rabbitmqNotifs allUserClients -- Note that Cells needs all notifications because it doesn't matter whether -- some recipients have rabbitmq clients or not. From 767f058008015a3ec2c77243af972a04258a0afd Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Fri, 13 Mar 2026 07:47:11 +0000 Subject: [PATCH 08/14] typo --- changelog.d/5-internal/WPB-23942 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/5-internal/WPB-23942 b/changelog.d/5-internal/WPB-23942 index 8b3d1ac5b06..3d131194e4f 100644 --- a/changelog.d/5-internal/WPB-23942 +++ b/changelog.d/5-internal/WPB-23942 @@ -1 +1 @@ -Make consumable notifications configureable and disable them by default +Make consumable notifications configurable and disable them by default From 33a54e3964cad7b41003f0fb90256a15809812ec Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Fri, 13 Mar 2026 07:55:05 +0000 Subject: [PATCH 09/14] added docs --- docs/src/developer/reference/config-options.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/src/developer/reference/config-options.md b/docs/src/developer/reference/config-options.md index 911594aac37..2ecd0158d25 100644 --- a/docs/src/developer/reference/config-options.md +++ b/docs/src/developer/reference/config-options.md @@ -2000,6 +2000,23 @@ gundeck: settings: cellsEventQueue: "cells_events" ``` + +## Configure consumable notifications + +The `consumableNotifications` flag controls whether the RabbitMQ-backed Events +API for clients with the `consumable-notifications` capability is operational. +When disabled, the legacy notification flow remains active. + +This is a root-level Helm `values.yaml` setting. It is rendered into both the +`brig` and `gundeck` service configs: + +```yaml +consumableNotifications: false +``` + +- In `brig`, it is rendered as `optSettings.setConsumableNotifications`. +- In `gundeck`, it is rendered as `settings.consumableNotifications`. + ## Background worker: Background jobs The background worker processes asynchronous jobs (conversation migrations, backend notifications). Configuration is supplied via Helm under `background-worker.config` and rendered into `background-worker.yaml`. From 49eb4b443bed2ebdc45afb612f65387f2e3c1a6d Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Fri, 13 Mar 2026 08:00:21 +0000 Subject: [PATCH 10/14] release notes --- changelog.d/0-release-notes/WPB-23942 | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/0-release-notes/WPB-23942 diff --git a/changelog.d/0-release-notes/WPB-23942 b/changelog.d/0-release-notes/WPB-23942 new file mode 100644 index 00000000000..4fa8907fb62 --- /dev/null +++ b/changelog.d/0-release-notes/WPB-23942 @@ -0,0 +1 @@ +A new root-level Helm value `consumableNotifications` was added to control whether RabbitMQ queues are created and used for clients with the `consumable-notifications` capability. The value is provided via the `wire-server` Helm chart defaults and defaults to `false`. From bba698dee4968758c2b21962b84ef66b178b76d2 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Fri, 13 Mar 2026 10:45:53 +0000 Subject: [PATCH 11/14] more efficient test --- integration/test/Test/Events.hs | 84 ++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/integration/test/Test/Events.hs b/integration/test/Test/Events.hs index 5f687d52a2a..a172cf2ff0f 100644 --- a/integration/test/Test/Events.hs +++ b/integration/test/Test/Events.hs @@ -815,44 +815,52 @@ mkEvent uid cid transient = ] testTypingIndicatorIsNotSentToOwnClient :: (HasCallStack) => TaggedBool "federated" -> App () -testTypingIndicatorIsNotSentToOwnClient (TaggedBool federated) = startDynamicBackends [(enableConsumableNotifications def), (enableConsumableNotifications def)] $ \[domain, otherDomain] -> do - (alice, _, aliceClient) <- mkUserPlusClientWithDomain domain - (bob, _, bobClient) <- mkUserPlusClientWithDomain (if federated then otherDomain else domain) - connectTwoUsers alice bob - aliceClientId <- objId aliceClient - bobClientId <- objId bobClient - conv <- postConversation alice defProteus {qualifiedUsers = [bob]} >>= getJSON 201 - - runCodensity (createEventWebSockets [(alice, Just aliceClientId), (bob, Just bobClientId)]) $ \[aliceWs, bobWs] -> do - -- consume all events to ensure we start with a clean slate - consumeAllEvents_ aliceWs - consumeAllEvents_ bobWs - - -- Alice is typing - sendTypingStatus alice conv "started" >>= assertSuccess - - -- Bob should receive the typing indicator for Alice - assertEvent bobWs $ \e -> do - e %. "data.event.payload.0.type" `shouldMatch` "conversation.typing" - e %. "data.event.payload.0.qualified_conversation" `shouldMatch` (conv %. "qualified_id") - e %. "data.event.payload.0.qualified_from" `shouldMatch` (alice %. "qualified_id") - ackEvent bobWs e - - -- Alice should not receive the typing indicator for herself - assertNoEvent_ aliceWs - - -- Bob is typing - sendTypingStatus bob conv "started" >>= assertSuccess - - -- Alice should receive the typing indicator for Bob - assertEvent aliceWs $ \e -> do - e %. "data.event.payload.0.type" `shouldMatch` "conversation.typing" - e %. "data.event.payload.0.qualified_conversation" `shouldMatch` (conv %. "qualified_id") - e %. "data.event.payload.0.qualified_from" `shouldMatch` (bob %. "qualified_id") - ackEvent aliceWs e - - -- Bob should not receive the typing indicator for himself - assertNoEvent_ bobWs +testTypingIndicatorIsNotSentToOwnClient (TaggedBool federated) = do + let runTest = + if federated + then startDynamicBackends [(enableConsumableNotifications def), (enableConsumableNotifications def)] + else \run -> startDynamicBackends [(enableConsumableNotifications def)] $ \[domain] -> run [domain, domain] + runTest $ \[domain, otherDomain] -> do + (alice, _, aliceClient) <- mkUserPlusClientWithDomain domain + (bob, _, bobClient) <- mkUserPlusClientWithDomain otherDomain + connectTwoUsers alice bob + aliceClientId <- objId aliceClient + bobClientId <- objId bobClient + conv <- postConversation alice defProteus {qualifiedUsers = [bob]} >>= getJSON 201 + + runCodensity (createEventWebSockets [(alice, Just aliceClientId), (bob, Just bobClientId)]) $ \[aliceWs, bobWs] -> do + -- consume all events to ensure we start with a clean slate + consumeAllEvents_ aliceWs + consumeAllEvents_ bobWs + + -- Alice is typing + sendTypingStatus alice conv "started" >>= assertSuccess + + -- Bob should receive the typing indicator for Alice + assertEvent bobWs $ \e -> do + e %. "data.event.payload.0.type" `shouldMatch` "conversation.typing" + e %. "data.event.payload.0.qualified_conversation" `shouldMatch` (conv %. "qualified_id") + e %. "data.event.payload.0.qualified_from" `shouldMatch` (alice %. "qualified_id") + ackEvent bobWs e + + -- Alice should not receive the typing indicator for herself + assertNoEvent_ aliceWs + + -- Bob is typing + sendTypingStatus bob conv "started" >>= assertSuccess + + -- Alice should receive the typing indicator for Bob + assertEvent aliceWs $ \e -> do + e %. "data.event.payload.0.type" `shouldMatch` "conversation.typing" + e %. "data.event.payload.0.qualified_conversation" `shouldMatch` (conv %. "qualified_id") + e %. "data.event.payload.0.qualified_from" `shouldMatch` (bob %. "qualified_id") + ackEvent aliceWs e + + -- Bob should not receive the typing indicator for himself + assertNoEvent_ bobWs + +-- convert :: ((HasCallStack) => (String -> App ()) -> App ()) -> ([String] -> App ()) -> App () +-- convert = undefined -- We only delete queues to clean up federated integration tests. So, we -- mostly want to ensure we don't get stuck there. From 002e5d86ea60aedcd550f5523b7d388311093d14 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 19 Mar 2026 08:55:44 +0000 Subject: [PATCH 12/14] clean up make target and script --- Makefile | 5 +++-- hack/bin/helm-render-ci-values.sh | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 3cfcc79a36a..7a4d6778f7a 100644 --- a/Makefile +++ b/Makefile @@ -692,8 +692,9 @@ diff-live-manifest: clean-charts charts-integration DIFF_OUTPUT_FILE="$(DIFF_OUTPUT_FILE)" ./hack/bin/diff-wire-server-manifests.sh "$(LIVE_MANIFEST_FILE)" /tmp/wire-server.yaml render-ci-manifest: clean-charts charts-integration - ./hack/bin/helm-render-ci-values.sh - ./hack/bin/render-manifest.sh /tmp/wire-server-test-a.yaml + VALUES_FILE="$${VALUES_FILE:-$$(mktemp).yaml}"; \ + ./hack/bin/helm-render-ci-values.sh \ + ./hack/bin/render-manifest.sh "$$VALUES_FILE" sbom.json: nix -Lv build '.#wireServer.bomDependencies' && \ diff --git a/hack/bin/helm-render-ci-values.sh b/hack/bin/helm-render-ci-values.sh index 09c8bd62077..a1f3a6babc2 100755 --- a/hack/bin/helm-render-ci-values.sh +++ b/hack/bin/helm-render-ci-values.sh @@ -4,6 +4,8 @@ set -euo pipefail +VALUES_FILE="${VALUES_FILE:-$(mktemp).yaml}" + # from repo root export NAMESPACE_1="${NAMESPACE_1:-test-a}" export NAMESPACE_2="${NAMESPACE_2:-test-b}" @@ -17,10 +19,8 @@ export ENTERPRISE_IMAGE_PULL_SECRET="${ENTERPRISE_IMAGE_PULL_SECRET:-{}}" helmfile -f hack/helmfile.yaml.gotmpl \ -e default \ --skip-deps \ - -l name=wire-server \ + -l name=wire-server,namespace="${NAMESPACE_1}" \ write-values \ - --output-file-template '/tmp/{{ .Release.Name }}-{{ .Release.Namespace }}.yaml' - -VALUES_FILE="/tmp/wire-server-${NAMESPACE_1}.yaml" + --output-file-template "${VALUES_FILE}" -echo "Rendered values: $VALUES_FILE" +echo "Rendered values: $VALUES_FILE" From 1e36f2a28435f4b9d547b1ec5b56c6c994ee0c82 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 19 Mar 2026 11:46:07 +0000 Subject: [PATCH 13/14] disable consumable notifications --- charts/wire-server/templates/brig/configmap.yaml | 2 +- charts/wire-server/templates/gundeck/configmap.yaml | 2 +- charts/wire-server/values.yaml | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/charts/wire-server/templates/brig/configmap.yaml b/charts/wire-server/templates/brig/configmap.yaml index 1d39fee9334..66435c8d799 100644 --- a/charts/wire-server/templates/brig/configmap.yaml +++ b/charts/wire-server/templates/brig/configmap.yaml @@ -394,6 +394,6 @@ data: {{- if hasKey . "setNomadProfiles" }} setNomadProfiles: {{ index . "setNomadProfiles" }} {{- end }} - setConsumableNotifications: {{ $.Values.consumableNotifications }} + setConsumableNotifications: false {{- end }} {{- end }} diff --git a/charts/wire-server/templates/gundeck/configmap.yaml b/charts/wire-server/templates/gundeck/configmap.yaml index 66af5c9f969..9f102742700 100644 --- a/charts/wire-server/templates/gundeck/configmap.yaml +++ b/charts/wire-server/templates/gundeck/configmap.yaml @@ -96,6 +96,6 @@ data: {{- if hasKey . "cellsEventQueue" }} cellsEventQueue: {{ .cellsEventQueue }} {{- end }} - consumableNotifications: {{ $.Values.consumableNotifications }} + consumableNotifications: false {{- end }} diff --git a/charts/wire-server/values.yaml b/charts/wire-server/values.yaml index 79e84d8fb35..f7afb73b550 100644 --- a/charts/wire-server/values.yaml +++ b/charts/wire-server/values.yaml @@ -12,8 +12,6 @@ tags: mlsstats: false integration: false -consumableNotifications: false - galley: replicaCount: 3 image: From a9ebde61a9c90324475cbd7ded007e9c24824628 Mon Sep 17 00:00:00 2001 From: Leif Battermann Date: Thu, 19 Mar 2026 11:38:24 +0000 Subject: [PATCH 14/14] updated changelog --- changelog.d/0-release-notes/WPB-23942 | 1 - changelog.d/5-internal/WPB-23942 | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 changelog.d/0-release-notes/WPB-23942 diff --git a/changelog.d/0-release-notes/WPB-23942 b/changelog.d/0-release-notes/WPB-23942 deleted file mode 100644 index 4fa8907fb62..00000000000 --- a/changelog.d/0-release-notes/WPB-23942 +++ /dev/null @@ -1 +0,0 @@ -A new root-level Helm value `consumableNotifications` was added to control whether RabbitMQ queues are created and used for clients with the `consumable-notifications` capability. The value is provided via the `wire-server` Helm chart defaults and defaults to `false`. diff --git a/changelog.d/5-internal/WPB-23942 b/changelog.d/5-internal/WPB-23942 index 3d131194e4f..e1723b0ee08 100644 --- a/changelog.d/5-internal/WPB-23942 +++ b/changelog.d/5-internal/WPB-23942 @@ -1 +1 @@ -Make consumable notifications configurable and disable them by default +Consumable notifications are now disabled