mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
feat: support redis xstream (#32586)
This commit is contained in:
@ -38,6 +38,13 @@ if TYPE_CHECKING:
|
||||
class AppGenerateService:
|
||||
@staticmethod
|
||||
def _build_streaming_task_on_subscribe(start_task: Callable[[], None]) -> Callable[[], None]:
|
||||
"""
|
||||
Build a subscription callback that coordinates when the background task starts.
|
||||
|
||||
- streams transport: start immediately (events are durable; late subscribers can replay).
|
||||
- pubsub/sharded transport: start on first subscribe, with a short fallback timer so the task
|
||||
still runs if the client never connects.
|
||||
"""
|
||||
started = False
|
||||
lock = threading.Lock()
|
||||
|
||||
@ -54,10 +61,18 @@ class AppGenerateService:
|
||||
started = True
|
||||
return True
|
||||
|
||||
# XXX(QuantumGhost): dirty hacks to avoid a race between publisher and SSE subscriber.
|
||||
# The Celery task may publish the first event before the API side actually subscribes,
|
||||
# causing an "at most once" drop with Redis Pub/Sub. We start the task on subscribe,
|
||||
# but also use a short fallback timer so the task still runs if the client never consumes.
|
||||
channel_type = dify_config.PUBSUB_REDIS_CHANNEL_TYPE
|
||||
if channel_type == "streams":
|
||||
# With Redis Streams, we can safely start right away; consumers can read past events.
|
||||
_try_start()
|
||||
|
||||
# Keep return type Callable[[], None] consistent while allowing an extra (no-op) call.
|
||||
def _on_subscribe_streams() -> None:
|
||||
_try_start()
|
||||
|
||||
return _on_subscribe_streams
|
||||
|
||||
# Pub/Sub modes (at-most-once): subscribe-gated start with a tiny fallback.
|
||||
timer = threading.Timer(SSE_TASK_START_FALLBACK_MS / 1000.0, _try_start)
|
||||
timer.daemon = True
|
||||
timer.start()
|
||||
|
||||
Reference in New Issue
Block a user