Enhancement: Update TTL settings for client records and implement periodic refresh during active streaming

This commit is contained in:
SergeantPanda 2025-10-31 11:53:16 -05:00
parent 9d4fd63cde
commit 6715bc7c5c
2 changed files with 24 additions and 7 deletions

View file

@ -26,7 +26,7 @@ class BaseConfig:
now = time.time() now = time.time()
if cls._proxy_settings_cache is not None and (now - cls._proxy_settings_cache_time) < cls._proxy_settings_cache_ttl: 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 return cls._proxy_settings_cache
# Cache miss or expired - fetch from database # Cache miss or expired - fetch from database
try: try:
from core.models import CoreSettings from core.models import CoreSettings
@ -34,7 +34,7 @@ class BaseConfig:
cls._proxy_settings_cache = settings cls._proxy_settings_cache = settings
cls._proxy_settings_cache_time = now cls._proxy_settings_cache_time = now
return settings return settings
except Exception: except Exception:
# Return defaults if database query fails # Return defaults if database query fails
return { return {
@ -44,7 +44,7 @@ class BaseConfig:
"channel_shutdown_delay": 0, "channel_shutdown_delay": 0,
"channel_init_grace_period": 5, "channel_init_grace_period": 5,
} }
finally: finally:
# Always close the connection after reading settings # Always close the connection after reading settings
try: try:
@ -94,10 +94,10 @@ class TSConfig(BaseConfig):
CLEANUP_INTERVAL = 60 # Check for inactive channels every 60 seconds CLEANUP_INTERVAL = 60 # Check for inactive channels every 60 seconds
# Client tracking settings # 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) CLEANUP_CHECK_INTERVAL = 1 # How often to check for disconnected clients (seconds)
CLIENT_HEARTBEAT_INTERVAL = 1 # How often to send client heartbeats (seconds) CLIENT_HEARTBEAT_INTERVAL = 5 # 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) 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 CLIENT_WAIT_TIMEOUT = 30 # Seconds to wait for client to connect
# Stream health and recovery settings # Stream health and recovery settings

View file

@ -52,6 +52,10 @@ class StreamGenerator:
self.last_stats_bytes = 0 self.last_stats_bytes = 0
self.current_rate = 0.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): def generate(self):
""" """
Generator function that produces the stream content for the client. Generator function that produces the stream content for the client.
@ -336,7 +340,20 @@ class StreamGenerator:
ChannelMetadataField.STATS_UPDATED_AT: str(current_time) ChannelMetadataField.STATS_UPDATED_AT: str(current_time)
} }
proxy_server.redis_client.hset(client_key, mapping=stats) 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: except Exception as e:
logger.warning(f"[{self.client_id}] Failed to store stats in Redis: {e}") logger.warning(f"[{self.client_id}] Failed to store stats in Redis: {e}")