LibreChat/scripts/redis-mode.sh
Danny Avila b807292997
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
📉 perf: Bound Early Event Buffering for Detached Generations (#14612)
* 📉 perf: Bound Early Event Buffering for Detached Generations

A generation streaming with no attached subscriber re-entered buffering
mode on every disconnect and retained each emitted event in
earlyEventBuffer for its remaining duration. A single 26-minute detached
run (~58,800 tool-argument deltas) grew the heap past 2 GiB with GC cost
climbing alongside it, while client reconnects always resume from
durable state and discard that local buffer anyway.

- Close the early buffer after the first attachment drains it in Redis
  mode; the durable chunk log and pub/sub own recovery from then on,
  matching how cross-replica subscribers already attach.
- Enforce hard bounds (5,000 events / 8 MB estimated) in both modes; on
  overflow the buffer is discarded and closed, with recovery falling back
  to the durable chunk log (Redis) or resume snapshot (in-memory).
- Add a generation_stream_early_buffer_overflows_total counter and
  earlyBufferedEvents/Bytes gauges on getRuntimeStats() for visibility.
- Add incident-shaped regression tests and update specs that pinned the
  old post-disconnect re-buffering contract.

* fix: redirect post-overflow first attachments to resume recovery

A buffer discarded by the overflow guard left the initial non-resume
SSE attachment with nothing to replay, silently omitting pre-attach
output until the final event. Track the overflow on the runtime and
close such attachments with the existing reconnect signal instead: the
client already re-attaches with resume=true on transport failure and
its sync frame reconstructs the discarded output from durable/snapshot
state. Adds no per-event work; the check is one boolean per attachment.

* fix: enforce buffer bounds when restoring canceled resume captures

Captured emissions restored by a resume canceled before activation
bypassed the early-buffer hard cap, so one oversized restoration could
persist past the limits with no later emission to trip the guard.
Restoration now applies the same overflow-and-close behavior through a
shared helper, and the restore-cap spec fails before this change
(5 events / ~10MB retained) and passes after.

* chore: add Redis management scripts and update package.json for Redis commands
2026-08-03 19:03:37 -04:00

60 lines
No EOL
1.2 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CLUSTER_DIR="$ROOT_DIR/redis-config"
require_redis() {
if command -v redis-server >/dev/null && command -v redis-cli >/dev/null; then
return
fi
echo "Redis is required. Install it with: sudo apt-get install redis-server redis-tools"
exit 1
}
redis_is_running() {
redis-cli -p "$1" ping >/dev/null 2>&1
}
stop_single() {
if redis_is_running 6379; then
redis-cli -p 6379 shutdown nosave >/dev/null 2>&1 || true
fi
}
start_single() {
mkdir -p "$CLUSTER_DIR/data/6379"
if redis_is_running 6379; then
echo "Redis single node is already running on port 6379."
return
fi
redis-server --port 6379 --dir "$CLUSTER_DIR/data/6379" --save '' --appendonly no --daemonize yes
redis-cli -p 6379 ping >/dev/null
echo "Redis single node is ready on port 6379."
}
case "${1:-}" in
single)
require_redis
"$CLUSTER_DIR/stop-cluster.sh" >/dev/null 2>&1 || true
start_single
;;
cluster)
require_redis
stop_single
exec "$CLUSTER_DIR/start-cluster.sh"
;;
stop)
require_redis
stop_single
exec "$CLUSTER_DIR/stop-cluster.sh"
;;
*)
echo "Usage: $0 {single|cluster|stop}"
exit 1
;;
esac