| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  | from typing import Any, Union | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | import redis | 
					
						
							| 
									
										
										
										
											2024-11-20 13:44:35 +08:00
										 |  |  | from redis.cluster import ClusterNode, RedisCluster | 
					
						
							| 
									
										
										
										
											2024-01-12 12:34:01 +08:00
										 |  |  | from redis.connection import Connection, SSLConnection | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  | from redis.sentinel import Sentinel | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  | from configs import dify_config | 
					
						
							| 
									
										
										
										
											2024-11-30 23:05:22 +08:00
										 |  |  | from dify_app import DifyApp | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-20 13:44:35 +08:00
										 |  |  | class RedisClientWrapper: | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     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() | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-30 23:05:22 +08:00
										 |  |  | def init_app(app: DifyApp): | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |     global redis_client | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |     connection_class: type[Union[Connection, SSLConnection]] = Connection | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |     if dify_config.REDIS_USE_SSL: | 
					
						
							| 
									
										
										
										
											2023-05-17 15:40:21 +08:00
										 |  |  |         connection_class = SSLConnection | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |     redis_params: dict[str, Any] = { | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |         "username": dify_config.REDIS_USERNAME, | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |         "password": dify_config.REDIS_PASSWORD or None,  # Temporary fix for empty password | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |         "db": dify_config.REDIS_DB, | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |         "encoding": "utf-8", | 
					
						
							|  |  |  |         "encoding_errors": "strict", | 
					
						
							|  |  |  |         "decode_responses": False, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |     if dify_config.REDIS_USE_SENTINEL: | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |         assert dify_config.REDIS_SENTINELS is not None, "REDIS_SENTINELS must be set when REDIS_USE_SENTINEL is True" | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |         sentinel_hosts = [ | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |             (node.split(":")[0], int(node.split(":")[1])) for node in dify_config.REDIS_SENTINELS.split(",") | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |         ] | 
					
						
							|  |  |  |         sentinel = Sentinel( | 
					
						
							|  |  |  |             sentinel_hosts, | 
					
						
							|  |  |  |             sentinel_kwargs={ | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |                 "socket_timeout": dify_config.REDIS_SENTINEL_SOCKET_TIMEOUT, | 
					
						
							|  |  |  |                 "username": dify_config.REDIS_SENTINEL_USERNAME, | 
					
						
							|  |  |  |                 "password": dify_config.REDIS_SENTINEL_PASSWORD, | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |         master = sentinel.master_for(dify_config.REDIS_SENTINEL_SERVICE_NAME, **redis_params) | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |         redis_client.initialize(master) | 
					
						
							| 
									
										
										
										
											2024-11-20 13:44:35 +08:00
										 |  |  |     elif dify_config.REDIS_USE_CLUSTERS: | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |         assert dify_config.REDIS_CLUSTERS is not None, "REDIS_CLUSTERS must be set when REDIS_USE_CLUSTERS is True" | 
					
						
							| 
									
										
										
										
											2024-11-20 13:44:35 +08:00
										 |  |  |         nodes = [ | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |             ClusterNode(host=node.split(":")[0], port=int(node.split(":")[1])) | 
					
						
							| 
									
										
										
										
											2024-11-20 13:44:35 +08:00
										 |  |  |             for node in dify_config.REDIS_CLUSTERS.split(",") | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2024-12-03 09:15:51 +08:00
										 |  |  |         # FIXME: mypy error here, try to figure out how to fix it | 
					
						
							|  |  |  |         redis_client.initialize(RedisCluster(startup_nodes=nodes, password=dify_config.REDIS_CLUSTERS_PASSWORD))  # type: ignore | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |     else: | 
					
						
							|  |  |  |         redis_params.update( | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2024-10-22 11:01:32 +08:00
										 |  |  |                 "host": dify_config.REDIS_HOST, | 
					
						
							|  |  |  |                 "port": dify_config.REDIS_PORT, | 
					
						
							| 
									
										
										
										
											2024-09-08 13:23:51 +08:00
										 |  |  |                 "connection_class": connection_class, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         pool = redis.ConnectionPool(**redis_params) | 
					
						
							|  |  |  |         redis_client.initialize(redis.Redis(connection_pool=pool)) | 
					
						
							| 
									
										
										
										
											2023-05-15 08:51:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-15 12:54:05 +08:00
										 |  |  |     app.extensions["redis"] = redis_client |