mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-07-18 00:55:50 +00:00
Enhancement: Cache channel names to reduce repeated DB queries in StreamManager and StreamGenerator. This improves performance by avoiding unnecessary database calls during retries and logging events. (Fixes #1138)
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
Some checks are pending
CI Pipeline / prepare (push) Waiting to run
CI Pipeline / docker (amd64, ubuntu-24.04) (push) Blocked by required conditions
CI Pipeline / docker (arm64, ubuntu-24.04-arm) (push) Blocked by required conditions
CI Pipeline / create-manifest (push) Blocked by required conditions
Build and Push Multi-Arch Docker Image / build-and-push (push) Waiting to run
This commit is contained in:
parent
9914e65c4c
commit
d676903825
4 changed files with 32 additions and 22 deletions
|
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Performance
|
||||
|
||||
- Eliminated repeated DB queries in the `ts_proxy` hot path. `StreamManager`, `StreamGenerator`, and `ProxyServer` were each calling `Channel.objects.get(uuid=...)` on every retry, reconnect, failover, and buffering event solely to retrieve `channel.name` for log events. `StreamManager` and `StreamGenerator` now fetch the channel name once at construction via a lightweight `values_list` query and store it as `self.channel_name`. `ProxyServer` caches the name in a `_channel_names` dict keyed by channel ID at channel-start time and pops it at channel-stop time. (Fixes #1138)
|
||||
|
||||
## [0.23.0] - 2026-04-17
|
||||
|
||||
### Security
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class ProxyServer:
|
|||
self.stream_managers = {}
|
||||
self.stream_buffers = {}
|
||||
self.client_managers = {}
|
||||
self._channel_names = {}
|
||||
|
||||
# Generate a unique worker ID
|
||||
import socket
|
||||
|
|
@ -672,7 +673,9 @@ class ProxyServer:
|
|||
|
||||
# Log channel start event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=channel_id)
|
||||
_name = Channel.objects.filter(uuid=channel_id).values_list('name', flat=True).first()
|
||||
channel_name = _name if _name else str(channel_id)
|
||||
self._channel_names[channel_id] = channel_name
|
||||
|
||||
# Get stream name if stream_id is available
|
||||
stream_name = None
|
||||
|
|
@ -686,7 +689,7 @@ class ProxyServer:
|
|||
log_system_event(
|
||||
'channel_start',
|
||||
channel_id=channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=channel_name,
|
||||
stream_name=stream_name,
|
||||
stream_id=channel_stream_id
|
||||
)
|
||||
|
|
@ -941,7 +944,7 @@ class ProxyServer:
|
|||
|
||||
# Log channel stop event (after cleanup, before releasing ownership section ends)
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=channel_id)
|
||||
channel_name = self._channel_names.pop(channel_id, None) or str(channel_id)
|
||||
|
||||
# Calculate runtime and get total bytes from metadata
|
||||
runtime = None
|
||||
|
|
@ -967,7 +970,7 @@ class ProxyServer:
|
|||
log_system_event(
|
||||
'channel_stop',
|
||||
channel_id=channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=channel_name,
|
||||
runtime=runtime,
|
||||
total_bytes=total_bytes
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@ class StreamGenerator:
|
|||
self.client_user_agent = client_user_agent
|
||||
self.channel_initializing = channel_initializing
|
||||
self.user = user
|
||||
# Cache channel name once to avoid repeated DB queries for logging
|
||||
try:
|
||||
_name = Channel.objects.filter(uuid=channel_id).values_list('name', flat=True).first()
|
||||
self.channel_name = _name if _name else str(channel_id)
|
||||
except Exception:
|
||||
self.channel_name = str(channel_id)
|
||||
|
||||
# Performance and state tracking
|
||||
self.stream_start_time = time.time()
|
||||
|
|
@ -107,11 +113,10 @@ class StreamGenerator:
|
|||
|
||||
# Log client connect event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'client_connect',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
client_ip=self.client_ip,
|
||||
client_id=self.client_id,
|
||||
user_agent=self.client_user_agent[:100] if self.client_user_agent else None,
|
||||
|
|
@ -587,11 +592,10 @@ class StreamGenerator:
|
|||
|
||||
# Log client disconnect event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'client_disconnect',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
client_ip=self.client_ip,
|
||||
client_id=self.client_id,
|
||||
user_agent=self.client_user_agent[:100] if self.client_user_agent else None,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ class StreamManager:
|
|||
def __init__(self, channel_id, url, buffer, user_agent=None, transcode=False, stream_id=None, worker_id=None):
|
||||
# Basic properties
|
||||
self.channel_id = channel_id
|
||||
# Cache channel name once to avoid repeated DB queries in hot retry/reconnect loops
|
||||
try:
|
||||
_name = Channel.objects.filter(uuid=channel_id).values_list('name', flat=True).first()
|
||||
self.channel_name = _name if _name else str(channel_id)
|
||||
except Exception:
|
||||
self.channel_name = str(channel_id)
|
||||
self.url = url
|
||||
self.buffer = buffer
|
||||
self.running = True
|
||||
|
|
@ -274,11 +280,10 @@ class StreamManager:
|
|||
# Log reconnection event if this is a retry (not first attempt)
|
||||
if self.retry_count > 0:
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_reconnect',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
attempt=self.retry_count + 1,
|
||||
max_attempts=self.max_retries
|
||||
)
|
||||
|
|
@ -317,11 +322,10 @@ class StreamManager:
|
|||
|
||||
# Log connection error event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_error',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
error_type='connection_failed',
|
||||
url=self.url[:100] if self.url else None,
|
||||
attempts=self.max_retries
|
||||
|
|
@ -344,11 +348,10 @@ class StreamManager:
|
|||
|
||||
# Log connection error event with exception details
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_error',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
error_type='connection_exception',
|
||||
error_message=str(e)[:200],
|
||||
url=self.url[:100] if self.url else None,
|
||||
|
|
@ -826,11 +829,10 @@ class StreamManager:
|
|||
|
||||
# Log failover event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_failover',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
reason='buffering_timeout',
|
||||
duration=buffering_duration
|
||||
)
|
||||
|
|
@ -846,11 +848,10 @@ class StreamManager:
|
|||
|
||||
# Log system event for buffering
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_buffering',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
speed=ffmpeg_speed
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
@ -1172,11 +1173,10 @@ class StreamManager:
|
|||
|
||||
# Log stream switch event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'stream_switch',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
new_url=new_url[:100] if new_url else None,
|
||||
stream_id=stream_id
|
||||
)
|
||||
|
|
@ -1304,11 +1304,10 @@ class StreamManager:
|
|||
|
||||
# Log reconnection event
|
||||
try:
|
||||
channel_obj = Channel.objects.get(uuid=self.channel_id)
|
||||
log_system_event(
|
||||
'channel_reconnect',
|
||||
channel_id=self.channel_id,
|
||||
channel_name=channel_obj.name,
|
||||
channel_name=self.channel_name,
|
||||
reason='health_monitor'
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue