1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-16 13:21:51 +03:00
Commit Graph

280 Commits

Author SHA1 Message Date
1f4537559a feat: implement client-side caching with Redis invalidation support
Add comprehensive client-side caching functionality that leverages the push notification
infrastructure for automatic cache invalidation.

Core Features:
- Local in-memory cache with configurable size and TTL
- Automatic Redis CLIENT TRACKING integration
- Real-time cache invalidation via push notifications
- LRU eviction policy for memory management
- Thread-safe operations with RWMutex
- Comprehensive statistics and monitoring

API Components:
- ClientSideCache: Main cache implementation
- ClientSideCacheOptions: Configuration options
- Client integration methods: EnableClientSideCache, DisableClientSideCache
- Convenience methods: CachedGet, CachedSet, CachedDel
- Statistics: GetStats with hits, misses, evictions, hit ratio

Implementation Details:
- Uses existing push notification system for invalidation
- Integrates with Redis CLIENT TRACKING (RESP3 required)
- Supports BCAST mode for prefix-based tracking
- Non-blocking invalidation processing
- Graceful fallback to Redis on cache misses
- Automatic cleanup on client close

Benefits:
- Significant performance improvements for read-heavy workloads
- Reduced Redis server load and network traffic
- Automatic cache coherence with real-time invalidation
- Transparent integration with existing Redis operations
- Zero configuration required (sensible defaults)

Test Coverage:
- Comprehensive unit tests for all cache operations
- Integration tests with real Redis instances
- Edge cases: expiration, eviction, invalidation
- Statistics verification and cache management
- Error handling and graceful degradation

Example Usage:
```go
// Enable client-side caching
client.EnableClientSideCache(&redis.ClientSideCacheOptions{
    MaxSize: 1000,
    DefaultTTL: 5 * time.Minute,
})

// Use cached operations
value, err := client.CachedGet(ctx, "key").Result()
err = client.CachedSet(ctx, "key", "value", time.Hour).Err()
```

Files Added:
- client_side_cache.go: Core implementation
- client_side_cache_test.go: Comprehensive tests
- examples/client-side-cache/: Working example with documentation

Integration:
- Leverages existing push notification infrastructure
- Updates shouldSkipNotification filtering (invalidate now processed)
- Maintains backward compatibility
- No breaking changes to existing APIs
2025-06-28 13:53:26 +03:00
f4ff2d667c feat: expand notification filtering to include streams, keyspace, and client tracking
- Rename isPubSubMessage to shouldSkipNotification for broader scope
- Add filtering for stream notifications (xread-from, xreadgroup-from)
- Add filtering for client tracking notifications (invalidate)
- Add filtering for keyspace notifications (expired, evicted, set, del, etc.)
- Add filtering for sharded pub/sub notifications (ssubscribe, sunsubscribe)
- Update comprehensive test coverage for all notification types

Notification types now filtered:
- Pub/Sub: message, pmessage, subscribe, unsubscribe, psubscribe, punsubscribe
- Sharded Pub/Sub: smessage, ssubscribe, sunsubscribe
- Streams: xread-from, xreadgroup-from
- Client tracking: invalidate
- Keyspace events: expired, evicted, set, del, rename, move, copy, restore, sort, flushdb, flushall

Benefits:
- Comprehensive separation of notification systems
- Prevents interference between specialized handlers
- Ensures notifications reach their intended systems
- Better system reliability and performance
- Clear boundaries between different Redis features

Implementation:
- Efficient switch statement with O(1) lookup
- Case-sensitive matching for precise filtering
- Comprehensive documentation for each notification type
- Applied to all processing points (WithReader, Pool.Put, isHealthyConn)

Test coverage:
- TestShouldSkipNotification with categorized test cases
- All notification types tested (pub/sub, streams, keyspace, client tracking)
- Cluster notifications verified as non-filtered
- Edge cases and boundary conditions covered
2025-06-28 02:07:48 +03:00
f66518cf3a feat: add pub/sub message filtering to push notification processor
- Add isPubSubMessage() function to identify pub/sub message types
- Filter out pub/sub messages in ProcessPendingNotifications
- Allow pub/sub system to handle its own messages without interference
- Process only cluster/system push notifications (MOVING, MIGRATING, etc.)
- Add comprehensive test coverage for filtering logic

Pub/sub message types filtered:
- message (regular pub/sub)
- pmessage (pattern pub/sub)
- subscribe/unsubscribe (subscription management)
- psubscribe/punsubscribe (pattern subscription management)
- smessage (sharded pub/sub, Redis 7.0+)

Benefits:
- Clear separation of concerns between pub/sub and push notifications
- Prevents interference between the two messaging systems
- Ensures pub/sub messages reach their intended handlers
- Eliminates message loss due to incorrect interception
- Improved system reliability and performance
- Better resource utilization and message flow

Implementation:
- Efficient O(1) switch statement for message type lookup
- Case-sensitive matching for precise filtering
- Early return to skip unnecessary processing
- Maintains processing of other notifications in same batch
- Applied to all processing points (WithReader, Pool.Put, isHealthyConn)

Test coverage:
- TestIsPubSubMessage - Function correctness and edge cases
- TestPubSubFiltering - End-to-end integration testing
- Mixed message scenarios and handler verification
2025-06-28 01:16:24 +03:00
b6e712b41a feat: add proactive push notification processing to WithReader
- Add push notification processing to Conn.WithReader method
- Process notifications immediately before every read operation
- Provides proactive notification handling vs reactive processing
- Add proper error handling with internal.Logger
- Non-blocking implementation that doesn't break Redis operations
- Complements existing processing in Pool.Put and isHealthyConn

Benefits:
- Immediate processing when notifications arrive
- Called before every read operation for optimal timing
- Prevents notification backlog accumulation
- More responsive to Redis cluster changes
- Better user experience during migrations
- Optimal placement for catching asynchronous notifications

Implementation:
- Type-safe interface assertion for processor
- Context-aware error handling with logging
- Maintains backward compatibility
- Consistent with existing pool patterns
- Three-layer processing strategy: WithReader (proactive) + Pool.Put + isHealthyConn (reactive)

Use cases:
- MOVING/MIGRATING/MIGRATED notifications for slot migrations
- FAILING_OVER/FAILED_OVER notifications for failover scenarios
- Real-time cluster topology change awareness
- Improved connection utilization efficiency
2025-06-27 22:56:04 +03:00
d820ade9e4 test: add comprehensive test coverage for pushnotif package
- Add 100% test coverage for Registry (NewRegistry, RegisterHandler, UnregisterHandler, GetHandler, GetRegisteredPushNotificationNames)
- Add 100% test coverage for Processor (NewProcessor, GetHandler, RegisterHandler, UnregisterHandler)
- Add 100% test coverage for VoidProcessor (NewVoidProcessor, GetHandler, RegisterHandler, UnregisterHandler, ProcessPendingNotifications)
- Add comprehensive tests for ProcessPendingNotifications with mock reader testing all code paths
- Add missing UnregisterHandler method to VoidProcessor
- Remove HandleNotification method reference from RegistryInterface
- Create TestHandler, MockReader, and test helper functions for comprehensive testing

Test coverage achieved:
- Registry: 100% coverage on all methods
- VoidProcessor: 100% coverage on all methods
- Processor: 100% coverage except ProcessPendingNotifications (complex RESP3 parsing)
- Overall package coverage: 71.7% (limited by complex protocol parsing logic)

Test scenarios covered:
- All constructor functions and basic operations
- Handler registration with duplicate detection
- Protected handler unregistration prevention
- Empty and invalid notification handling
- Error handling for all edge cases
- Mock reader testing for push notification processing logic
- Real proto.Reader testing for basic scenarios

Benefits:
- Comprehensive test coverage for all public APIs
- Edge case testing for error conditions
- Mock-based testing for complex protocol logic
- Regression prevention for core functionality
- Documentation through test examples
2025-06-27 22:41:29 +03:00
3473c1e998 fix: simplify api 2025-06-27 22:27:32 +03:00
f7948b5c5c fix: address pr review 2025-06-27 18:26:15 +03:00
e31987f25e Fixes tests:
- TestClientWithoutPushNotifications: Now expects error instead of nil
- TestClientPushNotificationEdgeCases: Now expects error instead of nil
2025-06-27 17:08:36 +03:00
91805bc506 refactor: remove handlerWrapper and use separate maps in registry
- Remove unnecessary handlerWrapper complexity from push notifications
- Use separate maps for handlers and protection status in registry
- Store handlers directly without indirection layer
- Maintain same instance identity for registered/retrieved handlers
- Preserve all protected handler functionality with cleaner implementation

Changes:
- internal/pushnotif/registry.go: Use separate handlers and protected maps
- push_notifications.go: Remove handlerWrapper, store handlers directly
- Maintain thread-safe operations with simplified code structure

Benefits:
- Reduced memory overhead (no wrapper objects)
- Direct handler storage without type conversion
- Cleaner, more maintainable code
- Same functionality with better performance
- Eliminated unnecessary complexity layer
- Preserved all existing behavior and safety guarantees
2025-06-27 16:38:31 +03:00
ada72cefcd refactor: move push notification logic to pusnotif package 2025-06-27 16:27:23 +03:00
be9b6dd6a0 refactor: remove unnecessary enabled field and IsEnabled/SetEnabled methods
- Remove enabled field from PushNotificationProcessor struct
- Remove IsEnabled() and SetEnabled() methods from processor interface
- Remove enabled parameter from NewPushNotificationProcessor()
- Update all interfaces in pool package to remove IsEnabled requirement
- Simplify processor logic - if processor exists, it works
- VoidPushNotificationProcessor handles disabled case by discarding notifications
- Update all tests to use simplified interface without enable/disable logic

Benefits:
- Simpler, cleaner interface with less complexity
- No unnecessary state management for enabled/disabled
- VoidPushNotificationProcessor pattern handles disabled case elegantly
- Reduced cognitive overhead - processors just work when set
- Eliminates redundant enabled checks throughout codebase
- More predictable behavior - set processor = it works
2025-06-27 01:36:38 +03:00
d7fbe18214 feat: fix connection health check interference with push notifications
- Add PushNotificationProcessor field to pool.Conn for connection-level processing
- Modify connection pool Put() and isHealthyConn() to handle push notifications
- Process pending push notifications before discarding connections
- Pass push notification processor to connections during creation
- Update connection pool options to include push notification processor
- Add comprehensive test for connection health check integration

This prevents connections with buffered push notification data from being
incorrectly discarded by the connection health check, ensuring push
notifications are properly processed and connections are reused.
2025-06-27 01:36:20 +03:00
4ac591c7c4 Set correct cluster slot for scan commands, similarly to Java's Jedis client (#2623)
- At present, the `scan` command is dispatched to a random slot.
- As far as I can tell, the scanX family of commands are not cluster aware (e.g. don't redirect the client to the correct slot).
- You can see [here](869dc0bb66/src/main/java/redis/clients/jedis/ShardedCommandObjects.java (L101)), the Jedis client calling `processKey` on the match argument, and this is what this PR also does.

We've had this patch running in production, and it seems to work well for us.

For further thought:
- Continuing looking at other Redis clients (e.g. Jedis), they outright [reject as invalid](869dc0bb66/src/main/java/redis/clients/jedis/ShardedCommandObjects.java (L98)) any scan command that does not include a hash-tag. Presumably this has the advantage of users not being surprised when their scan produces no results when a random server is picked.
- Perhaps it would be sensible for go-redis to do the same also?

Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
2025-06-24 13:43:03 +03:00
7d97cc1c59 feat: optimize connection pool waitTurn (#3412) 2025-06-20 12:07:14 +03:00
eb40ac8328 perf: reduce unnecessary memory allocation (#3399)
Signed-off-by: fukua95 <fukua95@gmail.com>
Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
2025-06-09 11:59:58 +03:00
86d418f940 feat: Introducing StreamingCredentialsProvider for token based authentication (#3320)
* wip

* update documentation

* add streamingcredentialsprovider in options

* fix: put back option in pool creation

* add package level comment

* Initial re authentication implementation

Introduces the StreamingCredentialsProvider as the CredentialsProvider
with the highest priority.

TODO: needs to be tested

* Change function type name

Change CancelProviderFunc to UnsubscribeFunc

* add tests

* fix race in tests

* fix example tests

* wip, hooks refactor

* fix build

* update README.md

* update wordlist

* update README.md

* refactor(auth): early returns in cred listener

* fix(doctest): simulate some delay

* feat(conn): add close hook on conn

* fix(tests): simulate start/stop in mock credentials provider

* fix(auth): don't double close the conn

* docs(README): mark streaming credentials provider as experimental

* fix(auth): streamline auth err proccess

* fix(auth): check err on close conn

* chore(entraid): use the repo under redis org
2025-05-27 16:25:20 +03:00
c149644da7 Unit test for pool acquisition timeout (#3381)
Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
2025-05-19 19:46:19 +03:00
3af2cc5783 chore: optimize function ReplaceSpaces (#3383)
* chore: optimize function `ReplaceSpaces`

Signed-off-by: fukua95 <fukua95@gmail.com>

* trigger CI again because the bug of docker

Signed-off-by: fukua95 <fukua95@gmail.com>

* trigger CI again because the bug of docker

Signed-off-by: fukua95 <fukua95@gmail.com>

---------

Signed-off-by: fukua95 <fukua95@gmail.com>
2025-05-19 19:21:17 +03:00
43e7fb5eef test(util): add unit tests for Atoi, ParseInt, ParseUint, and ParseFloat (#3377) 2025-05-15 14:53:54 +03:00
42c32846e6 utils: export ParseFloat and MustParseFloat wrapping internal utils (#3371)
* utils: expose ParseFloat via new public utils package

* add tests for special float values in vector search
2025-05-09 12:24:36 +03:00
8ba559ca5d feat: add connection waiting statistics (#2804)
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2025-05-07 15:54:26 +03:00
9762559c75 Bound connection pool background dials to configured dial timeout (#3089) 2025-03-24 15:45:43 +02:00
ebe11d06ca feat: Enable CI for Redis CE 8.0 (#3274)
* chore: extract benchmark tests

* wip

* enable pubsub tests

* enable ring tests

* stop tests with build redis from source

* start all tests

* mix of makefile and action

* add sentinel configs

* fix example test

* stop debug on re

* wip

* enable gears for redis 7.2

* wip

* enable sentinel, they are expected to fail

* fix: linter configuration

* chore: update re versions

* return older redis enterprise version

* add basic codeql

* wip: increase timeout, focus only sentinel tests

* sentinels with docker network host

* enable all tests

* fix flanky test

* enable example tests

* tidy docker compose

* add debug output

* stop shutingdown masters

* don't test sentinel for re

* skip unsuported addscores

* Update README

bump go version in CI

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update CONTRIBUTING.md

add information about new test setup

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-02-28 12:49:00 +02:00
37accb4b28 fix: nil pointer dereferencing in writeArg (#3271)
* fixed bug with nil dereferencing in writeArg, added hset struct example, added tests

* removed password from example

* added omitempty

* reverted xxhash versioning

* reverted xxhash versioning

* removed password

* removed password

---------

Co-authored-by: Nedyalko Dyakov <nedyalko.dyakov@gmail.com>
2025-02-20 16:54:11 +02:00
e7868623ac Remove direct read from TLS underlying conn (#3138) 2024-10-07 12:23:11 +03:00
0858ed24e6 add test for tls connCheck #3025 (#3047)
* add a check for TLS connections.
2024-07-12 11:16:21 +08:00
244a3e22da RediSearch Support (#2801)
* Add RediSearch Support

* searach

* Add RediSearch commands and tests

* Adding more tests and fixing commands

* Remove unnecessary additions

* fixing tests

* fixing tests

* fixing tests

* fixing FTConfig dialect test

* fix commects

* make enum for field types

* Support resp 2

* fix golang ci

* fix ftinfo

---------

Co-authored-by: Chayim <chayim@users.noreply.github.com>
2024-06-26 13:13:06 +03:00
b64d9deef3 Handle IPv6 in isMovedError (#2981)
* Handle IPv6 in isMovedError

* Simplify GetAddr

---------

Co-authored-by: Monkey <golang@88.com>
2024-04-28 12:37:44 +08:00
5da49b1aba bug: Fix SETINFO ensuring it is set-and-forget (#2915)
* Exexcute set-info without validation

* Fix tests

* Remove spaces from runtime.Version

* fix typo

* Send setinfo after auth

* Add pipline

* fix golangci

* revert fixing typo

* support sentinel
2024-02-20 17:34:35 +02:00
9133749cd3 test: add ut for util_test (#2840)
Signed-off-by: rfyiamcool <rfyiamcool@163.com>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2024-02-14 22:16:50 +02:00
36bab9c8dc fix ConnPool race in newConn (#2885)
Co-authored-by: Oleg Stotskiy <ostotsky@ordercapital.com>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2024-02-14 22:14:50 +02:00
c828764336 Allow scanning redis values into pointer fields (#2787)
* Allow scanning redis values into pointer fields

* Formatting

---------

Co-authored-by: Ilia Personal <iliapersonal@Ilyas-MBP.station>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2023-12-17 17:42:45 +02:00
631deaf25f test: fix WriteArg test (#2808) 2023-12-17 12:13:01 +02:00
15682e3227 feat: support write the types of pointer of simple data types (#2745) (#2753)
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2023-10-31 07:17:22 +02:00
4408f8cfb2 free turn when leave with error (#2658)
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2023-10-30 17:42:26 +02:00
e23ea028bd Added MaxActiveConns (#2646)
* Added the ability to set a connection growth limit when there are not enough connections in the pool using MaxActiveConns

* fix comment

* fix

* fix

---------

Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2023-09-20 14:55:23 +03:00
e8ad794e96 Format code and fix go vet (#2696)
* run go fix ./...

Signed-off-by: Tiago Peczenyj <tpeczenyj@weborama.com>

* run make fmt

Signed-off-by: Tiago Peczenyj <tpeczenyj@weborama.com>

* fix go vet ./... issues

* Update README.md

Reorder imports with the rules defined in the Makefile 

as if we run `make fmt`

* run gofumpt -w .

* update Makefile to use gofumpt instead gofmt

* increment makefile

* format test

* format tests

Signed-off-by: Tiago Peczenyj <tpeczenyj@weborama.com>

---------

Signed-off-by: Tiago Peczenyj <tpeczenyj@weborama.com>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
2023-09-20 14:03:44 +03:00
c0ab7815ea chore: fix staticcheck (#2631) 2023-07-02 14:38:52 +03:00
46f245075e fix: reader float parser (#2513) 2023-04-04 21:50:07 +08:00
6ec458549e Pointer -> Ptr (#2458) 2023-02-24 13:47:58 +08:00
3532f2a414 fix: limit the number of connections created (#2441)
* fix: limit the number of connections created

Signed-off-by: monkey92t <golang@88.com>
2023-02-14 18:01:53 +08:00
08b4cc5f4b feat: remove pool unused fields (#2438)
Signed-off-by: monkey92t <golang@88.com>
2023-02-12 18:50:25 +08:00
8db6eeed27 feat(scan): scan time.Time sets the default decoding (#2413)
* feat(scan): scan time.Time uses `UnmarshalText(RFC3339)` interface decoding by default
2023-02-07 20:23:39 +08:00
0023b80d82 chore: release v9.0.0 (release.sh) 2023-01-30 08:59:17 +02:00
7fa451c740 chore: fewer test dependencies 2023-01-27 15:01:50 +00:00
97b491aace chore: update import path 2023-01-23 08:48:54 +02:00
e314cd9846 Merge pull request #2356 from go-redis/fix/cursor-uint64
fix: read cursor as uint64
2023-01-20 15:15:43 +02:00
b88bd93662 fix: read cursor as uint64 2023-01-20 13:09:00 +02:00
d42dd1007c docs: add a description of the hook
Signed-off-by: monkey92t <golang@88.com>
2023-01-07 16:30:56 +08:00
a4336cbd43 feat(scan): add Scanner interface (#2317)
Signed-off-by: monkey92t <golang@88.com>
2022-12-24 22:29:45 +08:00