From 6715bc7c5cb91ec75b85ad7c7574fb69497c8cc7 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Fri, 31 Oct 2025 11:53:16 -0500 Subject: [PATCH] Enhancement: Update TTL settings for client records and implement periodic refresh during active streaming --- apps/proxy/config.py | 12 ++++++------ apps/proxy/ts_proxy/stream_generator.py | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/proxy/config.py b/apps/proxy/config.py index 74bfc61f..3b1ce967 100644 --- a/apps/proxy/config.py +++ b/apps/proxy/config.py @@ -26,7 +26,7 @@ class BaseConfig: now = time.time() if cls._proxy_settings_cache is not None and (now - cls._proxy_settings_cache_time) < cls._proxy_settings_cache_ttl: return cls._proxy_settings_cache - + # Cache miss or expired - fetch from database try: from core.models import CoreSettings @@ -34,7 +34,7 @@ class BaseConfig: cls._proxy_settings_cache = settings cls._proxy_settings_cache_time = now return settings - + except Exception: # Return defaults if database query fails return { @@ -44,7 +44,7 @@ class BaseConfig: "channel_shutdown_delay": 0, "channel_init_grace_period": 5, } - + finally: # Always close the connection after reading settings try: @@ -94,10 +94,10 @@ class TSConfig(BaseConfig): CLEANUP_INTERVAL = 60 # Check for inactive channels every 60 seconds # Client tracking settings - CLIENT_RECORD_TTL = 5 # How long client records persist in Redis (seconds). Client will be considered MIA after this time. + CLIENT_RECORD_TTL = 60 # How long client records persist in Redis (seconds). Client will be considered MIA after this time. CLEANUP_CHECK_INTERVAL = 1 # How often to check for disconnected clients (seconds) - CLIENT_HEARTBEAT_INTERVAL = 1 # How often to send client heartbeats (seconds) - GHOST_CLIENT_MULTIPLIER = 5.0 # How many heartbeat intervals before client considered ghost (5 would mean 5 secondsif heartbeat interval is 1) + CLIENT_HEARTBEAT_INTERVAL = 5 # How often to send client heartbeats (seconds) + GHOST_CLIENT_MULTIPLIER = 6.0 # How many heartbeat intervals before client considered ghost (6 would mean 36 seconds if heartbeat interval is 6) CLIENT_WAIT_TIMEOUT = 30 # Seconds to wait for client to connect # Stream health and recovery settings diff --git a/apps/proxy/ts_proxy/stream_generator.py b/apps/proxy/ts_proxy/stream_generator.py index 368691b8..5d4f661f 100644 --- a/apps/proxy/ts_proxy/stream_generator.py +++ b/apps/proxy/ts_proxy/stream_generator.py @@ -52,6 +52,10 @@ class StreamGenerator: self.last_stats_bytes = 0 self.current_rate = 0.0 + # TTL refresh tracking + self.last_ttl_refresh = time.time() + self.ttl_refresh_interval = 3 # Refresh TTL every 3 seconds of active streaming + def generate(self): """ Generator function that produces the stream content for the client. @@ -336,7 +340,20 @@ class StreamGenerator: ChannelMetadataField.STATS_UPDATED_AT: str(current_time) } proxy_server.redis_client.hset(client_key, mapping=stats) - # No need to set expiration as client heartbeat will refresh this key + + # Refresh TTL periodically while actively streaming + # This provides proof-of-life independent of heartbeat thread + if current_time - self.last_ttl_refresh > self.ttl_refresh_interval: + try: + # Refresh TTL on client key + proxy_server.redis_client.expire(client_key, Config.CLIENT_RECORD_TTL) + # Also refresh the client set TTL + client_set_key = f"ts_proxy:channel:{self.channel_id}:clients" + proxy_server.redis_client.expire(client_set_key, Config.CLIENT_RECORD_TTL) + self.last_ttl_refresh = current_time + logger.debug(f"[{self.client_id}] Refreshed client TTL (active streaming)") + except Exception as ttl_error: + logger.debug(f"[{self.client_id}] Failed to refresh TTL: {ttl_error}") except Exception as e: logger.warning(f"[{self.client_id}] Failed to store stats in Redis: {e}")