| import redis |
| from redis.connection import Connection, SSLConnection |
| from redis.sentinel import Sentinel |
|
|
| from configs import dify_config |
|
|
|
|
| class RedisClientWrapper(redis.Redis): |
| """ |
| A wrapper class for the Redis client that addresses the issue where the global |
| `redis_client` variable cannot be updated when a new Redis instance is returned |
| by Sentinel. |
| |
| This class allows for deferred initialization of the Redis client, enabling the |
| client to be re-initialized with a new instance when necessary. This is particularly |
| useful in scenarios where the Redis instance may change dynamically, such as during |
| a failover in a Sentinel-managed Redis setup. |
| |
| Attributes: |
| _client (redis.Redis): The actual Redis client instance. It remains None until |
| initialized with the `initialize` method. |
| |
| Methods: |
| initialize(client): Initializes the Redis client if it hasn't been initialized already. |
| __getattr__(item): Delegates attribute access to the Redis client, raising an error |
| if the client is not initialized. |
| """ |
|
|
| def __init__(self): |
| self._client = None |
|
|
| def initialize(self, client): |
| if self._client is None: |
| self._client = client |
|
|
| def __getattr__(self, item): |
| if self._client is None: |
| raise RuntimeError("Redis client is not initialized. Call init_app first.") |
| return getattr(self._client, item) |
|
|
|
|
| redis_client = RedisClientWrapper() |
|
|
|
|
| def init_app(app): |
| global redis_client |
| connection_class = Connection |
| if dify_config.REDIS_USE_SSL: |
| connection_class = SSLConnection |
|
|
| redis_params = { |
| "username": dify_config.REDIS_USERNAME, |
| "password": dify_config.REDIS_PASSWORD, |
| "db": dify_config.REDIS_DB, |
| "encoding": "utf-8", |
| "encoding_errors": "strict", |
| "decode_responses": False, |
| } |
|
|
| if dify_config.REDIS_USE_SENTINEL: |
| sentinel_hosts = [ |
| (node.split(":")[0], int(node.split(":")[1])) for node in dify_config.REDIS_SENTINELS.split(",") |
| ] |
| sentinel = Sentinel( |
| sentinel_hosts, |
| sentinel_kwargs={ |
| "socket_timeout": dify_config.REDIS_SENTINEL_SOCKET_TIMEOUT, |
| "username": dify_config.REDIS_SENTINEL_USERNAME, |
| "password": dify_config.REDIS_SENTINEL_PASSWORD, |
| }, |
| ) |
| master = sentinel.master_for(dify_config.REDIS_SENTINEL_SERVICE_NAME, **redis_params) |
| redis_client.initialize(master) |
| else: |
| redis_params.update( |
| { |
| "host": dify_config.REDIS_HOST, |
| "port": dify_config.REDIS_PORT, |
| "connection_class": connection_class, |
| } |
| ) |
| pool = redis.ConnectionPool(**redis_params) |
| redis_client.initialize(redis.Redis(connection_pool=pool)) |
|
|
| app.extensions["redis"] = redis_client |
|
|