Skip to content

Commit d61ec88

Browse files
committed
fix(redis): find a workaround to socket timeout
1 parent 91a9152 commit d61ec88

14 files changed

Lines changed: 176 additions & 128 deletions

File tree

.devcontainer/conf/redis/redis.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
protected-mode yes
44
user default on >default
55
user sogo on >sogo ~* &* +@all -SELECT
6+
7+
loglevel debug

app/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from json import loads, dumps
55
from json.decoder import JSONDecodeError
66

7-
87
from flask import Flask, request, g, Response, current_app
98
from flask.typing import ResponseReturnValue
109
from flask_smorest import Api, Blueprint
@@ -22,7 +21,7 @@
2221
import app.utils.errors as err
2322
from app.utils.api.ApiBaseResponse import create_api_base_response, ApiBaseResponse
2423
from app.utils import constants as cs
25-
from app.utils.logger.logger import logger
24+
from app.utils.logger.logger import logger, logger_api
2625
from app.utils.exceptions import AggravatedException
2726

2827
#Apis
@@ -102,6 +101,16 @@ def register_before_request(base_blueprint: Blueprint, kind: str, sogo_state: in
102101
:rtype: _type_
103102
"""
104103

104+
@base_blueprint.before_request
105+
def log_entry() -> ResponseReturnValue | None: # pylint: disable=too-many-return-statements
106+
"""
107+
Only used in debug to log request received
108+
"""
109+
110+
# Log the information
111+
logger_api.info("Received: \"%s %s %s\"", request.method, request.path, request.environ.get('SERVER_PROTOCOL', 'Unknown'))
112+
return None
113+
105114
@base_blueprint.before_request
106115
def check_content_type() -> ResponseReturnValue | None: # pylint: disable=too-many-return-statements
107116
"""

app/api/v1/admin/ApiAdminConfig.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from flask.typing import ResponseReturnValue
77
from flask_smorest import Blueprint
88

9-
from app.service import sogo_cache
109
from app.interface.admin.InterfaceApiAdminConfig import InterfaceApiAdminConfig
1110
from app.utils.logger.logger import logger_api
1211
from app.utils.api.paginate_sort_filter import collection_paginate, CustomPaginateResponse
@@ -30,7 +29,6 @@ def init_admin_config() -> None:
3029
process : ProcessSetting = g.process_settings
3130
interface_api = InterfaceApiAdminConfig(process_setting=process)
3231
g.inter = interface_api
33-
sogo_cache().set("test", "banane", 500)
3432

3533
@blp.route("/dynamic-form")
3634
class ApiAdminConfig(MethodView):

app/auth/service/VoucherAdminService.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ def generate_voucher_from_admin(self, admin_uid: str) -> Any:
5757
cs.SESSION_LAST_SEEN: int(time.time())
5858
}
5959

60-
sogo_cache().hashset(f"admin_session:{admin_session_id}", admin_session, 30 * 60)
60+
cache = sogo_cache()
61+
cache.hashset(f"admin_session:{admin_session_id}", admin_session, 30 * 60)
62+
cache.close()
6163

6264
# Generate the voucher
6365
voucher_payload = {
@@ -139,14 +141,16 @@ def generate_admin_from_voucher(self, voucher_data: Any) -> Admin:
139141
try:
140142
admin_uid, redis_key = self.get_redis_session_key_from_voucher(voucher_data)
141143

142-
session_data = sogo_cache().hashget(redis_key)
144+
cache = sogo_cache()
145+
session_data = cache.hashget(redis_key)
143146
if not session_data:
144147
return AdminAnonymous()
145148
if not admin_uid == session_data[cs.USER_UID]:
146149
return AdminAnonymous()
147150

148151
#Update ttl and lest seen
149-
sogo_cache().hashset(redis_key, {cs.SESSION_LAST_SEEN: int(time.time())}, ttl=30*60)
152+
cache.hashset(redis_key, {cs.SESSION_LAST_SEEN: int(time.time())}, ttl=30*60)
153+
cache.close()
150154

151155
logger_auth.info("Admin authenticated with uid: %s", admin_uid)
152156
return Admin(uid=admin_uid)

app/auth/service/VoucherUserService.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,28 @@ def generate_voucher_from_user(self, user:User) -> Any:
6262
cs.SESSION_SENSITIVE: sensitive_data,
6363
cs.SESSION_LAST_SEEN: int(time.time())
6464
}
65-
66-
sogo_cache().hashset(f"user_session:{user_session_id}", user_session, cs.TTL_1D)
65+
cache = sogo_cache()
66+
cache.hashset(f"user_session:{user_session_id}", user_session, cs.TTL_1D)
6767
# Index the session in the sorted set so that we can paginate / sort
6868
# active sessions by last-activity without scanning all keys.
69-
sogo_cache().zset_add(
69+
cache.zset_add(
7070
cs.ZSET_USER_SESSIONS_ACTIVITY,
7171
f"user_session:{user_session_id}",
7272
int(time.time()),
7373
)
7474
# Index the session by uid score so that sessions can be sorted / filtered by uid.
75-
sogo_cache().zset_add(
75+
cache.zset_add(
7676
cs.ZSET_USER_SESSIONS_UID,
7777
f"user_session:{user_session_id}",
7878
string_to_sort_score(user.uid),
7979
)
8080
# Index the session by domain score so that sessions can be sorted / filtered by domain.
81-
sogo_cache().zset_add(
81+
cache.zset_add(
8282
cs.ZSET_USER_SESSIONS_DOMAIN,
8383
f"user_session:{user_session_id}",
8484
string_to_sort_score(user.domain),
8585
)
86+
cache.close()
8687

8788
#Generate the voucher
8889
voucher_payload = user.get_voucher_payload()
@@ -201,16 +202,17 @@ def _get_user_session_from_payload(self, payload:dict) -> User:
201202
except ValueError as e:
202203
raise RequestException("Session key from Voucher is not valid") from e
203204

204-
user_session_data = sogo_cache().hashget(f"user_session:{session_id}")
205+
cache = sogo_cache()
206+
user_session_data = cache.hashget(f"user_session:{session_id}")
205207
if not user_session_data:
206208
# The hash has expired but sorted-set entries may linger – clean them up.
207-
sogo_cache().zset_remove(
209+
cache.zset_remove(
208210
cs.ZSET_USER_SESSIONS_ACTIVITY, f"user_session:{session_id}"
209211
)
210-
sogo_cache().zset_remove(
212+
cache.zset_remove(
211213
cs.ZSET_USER_SESSIONS_UID, f"user_session:{session_id}"
212214
)
213-
sogo_cache().zset_remove(
215+
cache.zset_remove(
214216
cs.ZSET_USER_SESSIONS_DOMAIN, f"user_session:{session_id}"
215217
)
216218
logger_auth.info("User session for %s is expired or does not exist", voucher_user_uid)
@@ -238,28 +240,29 @@ def _get_user_session_from_payload(self, payload:dict) -> User:
238240
# Update the last activity timestamp in both the hash and the sorted set
239241
new_last_seen = int(time.time())
240242
logger.debug("Updating last_activity for session %s: %s -> %s", session_id, user_session_data.get(cs.SESSION_LAST_SEEN), new_last_seen)
241-
sogo_cache().hashset(
243+
cache.hashset(
242244
f"user_session:{session_id}",
243245
{cs.SESSION_LAST_SEEN: new_last_seen},
244246
ttl=0
245247
)
246-
sogo_cache().zset_add(
248+
cache.zset_add(
247249
cs.ZSET_USER_SESSIONS_ACTIVITY,
248250
f"user_session:{session_id}",
249251
new_last_seen,
250252
)
251253
# Keep the uid score index in sync.
252-
sogo_cache().zset_add(
254+
cache.zset_add(
253255
cs.ZSET_USER_SESSIONS_UID,
254256
f"user_session:{session_id}",
255257
string_to_sort_score(user.uid),
256258
)
257259
# Keep the domain score index in sync.
258-
sogo_cache().zset_add(
260+
cache.zset_add(
259261
cs.ZSET_USER_SESSIONS_DOMAIN,
260262
f"user_session:{session_id}",
261263
string_to_sort_score(user.domain),
262264
)
263265
logger.info("From voucher get user: %s", user)
266+
cache.close()
264267

265268
return user

app/manager/cache/ClientRedis.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
from json import dumps as json_dumps, loads as json_loads
33
from json.decoder import JSONDecodeError
44
from typing import cast, Type
5+
import logging
56

6-
from redis import Redis, exceptions as rexc
7+
from redis import Redis, exceptions as rexc, ConnectionPool
78
from redis.cache import CacheConfig
89
from yarl import URL
910

@@ -21,6 +22,9 @@
2122
cs.USER_DOMAIN: cs.ZSET_USER_SESSIONS_DOMAIN,
2223
}
2324

25+
# redis_logger = logging.getLogger("redis")
26+
# redis_logger.setLevel(logging.DEBUG)
27+
2428
class ClientRedis():
2529
"""
2630
Client for redis, the cache system
@@ -165,7 +169,7 @@ def hashset(self, key:str, data: dict, ttl: int) -> bool:
165169
:param ttl: _description_
166170
:type ttl: int
167171
"""
168-
172+
logger_cache.info("Hashset cached for key '%s'", key)
169173
self.redis.hset(key, mapping=data)
170174
if ttl > 0:
171175
self.redis.expire(key, ttl)
@@ -181,6 +185,7 @@ def hashget(self, key:str) -> dict|None:
181185
:return: _description_
182186
:rtype: dict|None
183187
"""
188+
logger_cache.info("Hashget cached for key '%s'", key)
184189
ret = cast(dict|None, self.redis.hgetall(key))
185190
if ret:
186191
logger_cache.info("Hashget cached value '%s' for key '%s'", ret, key)
@@ -534,3 +539,9 @@ def revoke_user_sessions_by_activity(self, timestamp: int) -> int:
534539
revoked_count, timestamp,
535540
)
536541
return revoked_count
542+
543+
def close(self) -> None:
544+
"""
545+
_summary_
546+
"""
547+
self.redis.close()

app/module/admin/ModuleAdminAuth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,4 @@ def logout_admin(self, voucher_data: str) -> None:
7373

7474
cache = sogo_cache()
7575
cache.revoke_user_sessions_by_key([redis_key])
76+
cache.close()

app/module/admin/ModuleAdminUser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def get_active_users(self, collection_param: CollectionPaginateArgs) -> tuple[in
4747
sort_by=collection_param.sort_by,
4848
sort_order=collection_param.sort_order
4949
)
50+
cache.close()
5051

5152
logger.debug("%d active user session(s) (total: %d)", len(active_users), total_count)
5253
return total_count, active_users
@@ -85,10 +86,13 @@ def revoke_users(self, uids: list[str] | None = None, redis_keys: list[str] | No
8586
logger.debug("Revoked %d session(s) for redis key(s): %s", revoked_count, redis_keys)
8687
return revoked_count
8788

89+
cache.close()
90+
8891
raise RequestException(
8992
"Exactly one of 'uid' or 'redis_key' must be provided",
9093
error=err.ERROR_REVOKE_BODY_INVALID,
9194
)
95+
9296

9397
def revoke_inactive_users(self, timestamp: int) -> int:
9498
"""
@@ -105,5 +109,7 @@ def revoke_inactive_users(self, timestamp: int) -> int:
105109

106110
revoked_count = cache.revoke_user_sessions_by_activity(timestamp)
107111

112+
cache.close()
113+
108114
logger.debug("Revoked %d inactive session(s) older than %d", revoked_count, timestamp)
109115
return revoked_count

app/module/auth/ModuleAuth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from app.auth.service.VoucherUserService import VoucherUserService
77
from app.config.db import tables as tbl
88
from app.config.settings.DomainSettings import AuthSettings, AuthSettingsObj, UserSourceSettings, UserSourceSettingsObj
9+
from app.service import sogo_cache
910
from app.utils.db.Condition import EqualCondition
1011
from app.utils.exceptions import RequestException
1112
from app.utils.strings import get_domain_from_mail
@@ -166,6 +167,6 @@ def logout_user(self, voucher_data: str) -> None:
166167
voucher_user_service = VoucherUserService(self.process_settings)
167168
redis_key = voucher_user_service.get_redis_session_key_from_voucher(voucher_data)
168169

169-
from app.service import sogo_cache
170170
cache = sogo_cache()
171171
cache.revoke_user_sessions_by_key([redis_key])
172+
cache.close()

app/service.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from app.config.settings.ProcessSetting import process_config
12
from app.manager.agent.ClientAgent import ClientAgent
23
from app.manager.cache.ClientRedis import ClientRedis
34
from app.utils import exceptions as exc
@@ -13,8 +14,13 @@ def sogo_cache() -> ClientRedis:
1314
Using this method instead of "from app import cache_client" avoid the warning
1415
for potential None value.
1516
"""
16-
if isinstance(cache_client, ClientRedis):
17-
return cache_client
17+
#TODO there is a bug with one instance of the client, fallbacl to instaniate each time
18+
# if isinstance(cache_client, ClientRedis):
19+
# return cache_client
20+
21+
#Init a fresh redis client each time
22+
redis_conf = process_config.get_redis_settings()
23+
return ClientRedis(**redis_conf)
1824
raise exc.AggravatedException("Cache not instantiated when needed")
1925

2026
def set_cache(new_cache: ClientRedis) -> None:

0 commit comments

Comments
 (0)