How do you cancel a Redis pattern subscription created with PSUBSCRIBE, and what happens if you instead call UNSUBSCRIBE with a channel name that the pattern matched?
answer
- PUNSUBSCRIBE for patterns, UNSUBSCRIBE for channels
- exact string match, no glob evaluation
- no args = remove all patterns, one reply each
- count = channels + patterns on the connection
- disconnect drops every subscription
basics
~10 sUse PUNSUBSCRIBE with the exact pattern string, byte-for-byte. UNSUBSCRIBE only removes exact-channel subscriptions and never touches patterns, so the pmessage deliveries keep arriving. PUNSUBSCRIBE with no arguments removes every pattern on the connection.
solid answer
~50 sPatterns and exact channels are cancelled through separate commands, and they are matched literally, not semantically. `PUNSUBSCRIBE news.*` removes that pattern only if the stored string is identical; `news.\*` or `News.*` will not match it. `PUNSUBSCRIBE` with no arguments removes **all** patterns on the connection, emitting one confirmation per removed pattern (or a single confirmation with a null pattern if there were none). `UNSUBSCRIBE news.sports` searches only the exact-channel registry. Since the pattern subscription lives in the pattern list, nothing is removed and `pmessage` deliveries continue. This is a common bug when a consumer 'unsubscribes' from a topic and keeps receiving it. Each confirmation reply carries the connection's **total** remaining subscription count across exact channels and patterns. The client leaves subscriber mode only when that total reaches zero; under RESP2 that matters, because until then it cannot issue ordinary commands on the connection. `RESET` clears everything and exits subscriber mode in one step.
code
text · 13 linesSUBSCRIBE news.sports # exact subscription, total = 1
PSUBSCRIBE news.* # pattern subscription, total = 2
UNSUBSCRIBE news.sports # removes the EXACT one only
1) "unsubscribe" 2) "news.sports" 3) (integer) 1
# pmessage deliveries for news.sports STILL arrive via news.*
PUNSUBSCRIBE news.football # pattern was never registered
1) "punsubscribe" 2) "news.football" 3) (integer) 1 # no error, nothing removed
PUNSUBSCRIBE # no args: removes ALL patterns
1) "punsubscribe" 2) "news.*" 3) (integer) 0
# total now 0 -> connection leaves subscriber mode (RESP2)go deeper
Say PUNSUBSCRIBE with the exact pattern string cancels it, and that UNSUBSCRIBE only affects exact channel subscriptions.
Add literal string matching, the no-argument form that clears all patterns with one reply each, and the cumulative count in the confirmation.
Cover the operational edges: subscriber mode until the total hits zero, RESET as a clean escape, subscriptions dying with the connection, and tracking registered pattern strings so teardown cannot mismatch.
Focus on consumer lifecycle design: re-registration and gap handling on reconnect, whether subscription state should live in a managed client wrapper, and RESP3 versus RESP2 connection budgeting.
## Two registries, two commands A connection's subscriptions live in two independent places: exact channel names and glob patterns (plus shard channels in a cluster, a third, separate set). The unsubscribe commands are aligned one-to-one with those registries: - `UNSUBSCRIBE [channel ...]` - exact channels only. - `PUNSUBSCRIBE [pattern ...]` - patterns only. - `SUNSUBSCRIBE [shardchannel ...]` - shard channels only (Redis 7.0+). There is no command that removes 'whatever delivers this channel to me'. Cancellation is by the literal string you registered, in the registry you registered it in. ## Literal, not semantic, matching `PUNSUBSCRIBE` compares the argument to stored patterns as raw bytes. Consequences worth stating in an interview: - `PUNSUBSCRIBE news.sports` does **not** remove the pattern `news.*`, even though the pattern matches that channel. Redis does not evaluate globs during unsubscription. - Case matters, whitespace matters, and escaping matters: `news.\*` is a different pattern string from `news.*`, and only the exact one is removed. - Unsubscribing from a pattern you never registered is not an error. Redis replies with a confirmation carrying that pattern and the unchanged count, so a 'success' reply is not evidence anything was removed. ## The no-argument forms `PUNSUBSCRIBE` with no arguments removes every pattern on the connection and emits one `punsubscribe` confirmation per removed pattern, each with the decreasing total count. If the connection had no patterns, you still get one confirmation with a null pattern element. `UNSUBSCRIBE` with no arguments behaves the same way for exact channels. Clients that read a fixed number of replies get out of sync here, since the reply count depends on server-side state - another reason to let the driver manage subscription bookkeeping. ## The count field Every subscribe and unsubscribe confirmation ends with an integer that is the connection's **total** subscription count: exact channels plus patterns together (shard channels are tracked separately). So after `SUBSCRIBE a` and `PSUBSCRIBE b.*`, a `PUNSUBSCRIBE b.*` confirmation reports `1`, not `0`, because the exact subscription to `a` remains. Reading that number as 'patterns remaining' is a frequent misreading; use `PUBSUB NUMPAT` for the server-wide pattern count instead. ## Subscriber mode and getting out of it Under RESP2, a connection holding any subscription is restricted to subscribe/unsubscribe commands plus `PING`, `RESET` and `QUIT`. It leaves that mode only when the total count returns to zero, which is why forgetting that a pattern is still registered leaves a connection apparently 'stuck' and unable to run a `GET`. `RESET` (Redis 6.2+) is the blunt instrument: it unsubscribes everything, discards any `MULTI` state and `WATCH`es, and returns the connection to a clean state. Under RESP3 (`HELLO 3`, Redis 6.0+) the restriction does not apply, since pushes are a separate protocol type, but the subscriptions themselves still need explicit cancellation. ## Lifecycle in practice - **Disconnection cancels everything.** Subscriptions are connection state; closing the socket drops all of them, and nothing is restored on reconnect. A reconnecting client must re-issue its `PSUBSCRIBE` calls, and messages published during the gap are gone for good. - **Track what you registered.** Because cancellation needs the exact string, consumers should keep the pattern strings they used rather than reconstructing them, especially when patterns are built from configuration or interpolation. - **Prefer the no-argument form when tearing down.** For a consumer shutting down a whole feed, `PUNSUBSCRIBE` with no arguments avoids string-mismatch bugs entirely. ## What an interviewer is listening for That pattern and exact subscriptions are separate registries with separate commands, that matching on unsubscribe is literal rather than glob-evaluated, that the confirmation count is the connection total, and that unsubscribing a pattern you never had still returns success.
- What does the integer in a punsubscribe confirmation reply represent?It is the connection's total remaining subscription count, combining exact channel subscriptions and pattern subscriptions, not the number of patterns alone. So it can be non-zero after removing every pattern if exact subscriptions remain. Under RESP2 the connection stays in subscriber mode until that total reaches zero.
saying these in an interview costs you the question
- Expecting UNSUBSCRIBE with a matching channel name to cancel a pattern
- Thinking PUNSUBSCRIBE evaluates the glob to decide what to remove
- Reading the confirmation count as 'patterns remaining' rather than total subscriptions
- Assuming a success reply means a pattern was actually removed
- Believing subscriptions survive a reconnect and do not need re-registering