From 2ec509bebe3eb7ab06d4f59cfb4abaa26623c163 Mon Sep 17 00:00:00 2001 From: snowron Date: Thu, 2 Nov 2023 15:15:27 +0300 Subject: [PATCH 1/3] feat: add redis sentinel support Signed-off-by: snowron --- sdk/python/feast/infra/online_stores/redis.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sdk/python/feast/infra/online_stores/redis.py b/sdk/python/feast/infra/online_stores/redis.py index 83922068ac4..f928f7ff493 100644 --- a/sdk/python/feast/infra/online_stores/redis.py +++ b/sdk/python/feast/infra/online_stores/redis.py @@ -43,6 +43,7 @@ try: from redis import Redis from redis.cluster import ClusterNode, RedisCluster + from redis.sentinel import Sentinel except ImportError as e: from feast.errors import FeastExtrasDependencyImportError @@ -54,6 +55,7 @@ class RedisType(str, Enum): redis = "redis" redis_cluster = "redis_cluster" + redis_sentinel = "redis_sentinel" class RedisOnlineStoreConfig(FeastConfigBaseModel): @@ -65,6 +67,9 @@ class RedisOnlineStoreConfig(FeastConfigBaseModel): redis_type: RedisType = RedisType.redis """Redis type: redis or redis_cluster""" + sentinel_master: StrictStr = "mymaster" + """Sentinel's master name""" + connection_string: StrictStr = "localhost:6379" """Connection string containing the host, port, and configuration parameters for Redis format: host:port,parameter1,parameter2 eg. redis:6379,db=0 """ @@ -178,6 +183,19 @@ def _get_client(self, online_store_config: RedisOnlineStoreConfig): ClusterNode(**node) for node in startup_nodes ] self._client = RedisCluster(**kwargs) + elif online_store_config.redis_type == RedisType.redis_sentinel: + sentinel_hosts = [] + + for item in startup_nodes: + sentinel_hosts.append((item['host'], int(item['port']))) + + sentinel = Sentinel( + sentinel_hosts, + **kwargs + ) + + master = sentinel.master_for(online_store_config.sentinel_master) + self._client = master else: kwargs["host"] = startup_nodes[0]["host"] kwargs["port"] = startup_nodes[0]["port"] From 117ca9230bc26559b9d0a4c79a92cb5d6fca8112 Mon Sep 17 00:00:00 2001 From: snowron Date: Thu, 2 Nov 2023 15:22:55 +0300 Subject: [PATCH 2/3] feat: add redis sentinel support Signed-off-by: snowron --- docs/reference/online-stores/redis.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/reference/online-stores/redis.md b/docs/reference/online-stores/redis.md index c08cef2a3e1..ae7f8b4c5ca 100644 --- a/docs/reference/online-stores/redis.md +++ b/docs/reference/online-stores/redis.md @@ -45,6 +45,21 @@ online_store: ``` {% endcode %} +Connecting to a Redis Sentinel with SSL enabled and password authentication: + +{% code title="feature_store.yaml" %} +```yaml +project: my_feature_repo +registry: data/registry.db +provider: local +online_store: + type: redis + redis_type: redis_sentinel + sentinel_master: mymaster + connection_string: "redis1:26379,ssl=true,password=my_password" +``` +{% endcode %} + Additionally, the redis online store also supports automatically deleting data via a TTL mechanism. The TTL is applied at the entity level, so feature values from any associated feature views for an entity are removed together. This TTL can be set in the `feature_store.yaml`, using the `key_ttl_seconds` field in the online store. For example: From 107a1d3e173d74cae51f7ef607309468ff1655cb Mon Sep 17 00:00:00 2001 From: snowron Date: Thu, 2 Nov 2023 16:20:42 +0300 Subject: [PATCH 3/3] feat: add redis sentinel support format lint Signed-off-by: snowron --- sdk/python/feast/infra/online_stores/redis.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sdk/python/feast/infra/online_stores/redis.py b/sdk/python/feast/infra/online_stores/redis.py index f928f7ff493..9561705aaac 100644 --- a/sdk/python/feast/infra/online_stores/redis.py +++ b/sdk/python/feast/infra/online_stores/redis.py @@ -187,13 +187,9 @@ def _get_client(self, online_store_config: RedisOnlineStoreConfig): sentinel_hosts = [] for item in startup_nodes: - sentinel_hosts.append((item['host'], int(item['port']))) + sentinel_hosts.append((item["host"], int(item["port"]))) - sentinel = Sentinel( - sentinel_hosts, - **kwargs - ) - + sentinel = Sentinel(sentinel_hosts, **kwargs) master = sentinel.master_for(online_store_config.sentinel_master) self._client = master else: