5809ad3adb
Shared runtime - One agent entry point (runtime.invoke_agent_for_user / prepare_agent_turn) for web, email, iMessage, WhatsApp, scheduled and cron, so identity, permissions, memories, summaries and metrics match across channels. - Serialize turns per checkpoint thread; /query validates input and returns 409 while a durable run owns the conversation. Reconnectable chat (durable runs) - POST /runs creates an idempotent, owner-scoped run; GET .../events replays an ordered SSE log by cursor, so generation survives refresh and device switches. Stop cancels; disconnect only detaches. /stream-query is a compatibility adapter. - Coalesce streamed deltas (150 ms) and wake same-process subscribers instead of polling; keep buffered text when a run is stopped. - Drain runs on shutdown; serve via Hypercorn with a shutdown timeout covering the drain (and no longer in debug mode). CHAT_RUN_* settings are forwarded. Scheduled messages and cron - Atomic delivery claims, attempt history and explicit retries; ambiguous sends become "uncertain" and are never resent automatically. - Cron triggers need a run_id/Idempotency-Key; legacy jobs need an explicit owner. - Cancelling never rewrites a started delivery; series stop via tombstones. Legacy sent rows are not forked into new series. Malformed bodies return 400. History, integrations and retrieval - Message-content search, pinned conversations, JSON/Markdown export and a memory editor. - Integration status panel and YNAB data-freshness provenance. - Date-filtered document/note search with stable citations and a source viewer. Migration 20 is generated by aerich. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
1.9 KiB
Bash
Executable File
51 lines
1.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Zero-downtime blue-green deploy.
|
|
#
|
|
# Builds the inactive color, starts it, waits for its healthcheck to pass,
|
|
# then gracefully stops the old color. Caddy health-checks both ports
|
|
# (8080 = blue, 8081 = green) and routes traffic to whichever is healthy,
|
|
# so the swap is invisible to clients.
|
|
#
|
|
# Caveats:
|
|
# - Migrations run on the new container's startup while the old one still
|
|
# serves, so they must be backward-compatible (additive changes only;
|
|
# destructive changes need a two-step deploy).
|
|
# - During the brief overlap both containers run pull-only Obsidian sync
|
|
# against the shared ./obvault mount.
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
running_services=$(docker compose ps --status running --services)
|
|
|
|
if echo "$running_services" | grep -qx "raggr-blue"; then
|
|
OLD=blue NEW=green
|
|
elif echo "$running_services" | grep -qx "raggr-green"; then
|
|
OLD=green NEW=blue
|
|
else
|
|
OLD="" NEW=blue
|
|
fi
|
|
|
|
echo "==> Active: ${OLD:-none} | Deploying: $NEW"
|
|
|
|
echo "==> Building raggr-$NEW..."
|
|
docker compose --profile "$NEW" build "raggr-$NEW"
|
|
|
|
echo "==> Starting raggr-$NEW and waiting for healthy..."
|
|
if ! docker compose --profile "$NEW" up -d --wait "raggr-$NEW"; then
|
|
echo "!! raggr-$NEW failed to become healthy${OLD:+; raggr-$OLD is still serving}" >&2
|
|
docker compose --profile "$NEW" logs --tail 50 "raggr-$NEW" >&2 || true
|
|
docker compose --profile "$NEW" stop -t 5 "raggr-$NEW" || true
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$OLD" ]; then
|
|
# Allow application run draining plus cleanup; override for operational needs.
|
|
STOP_SECONDS=${DEPLOY_STOP_SECONDS:-$(( ${CHAT_RUN_DRAIN_SECONDS:-1800} + 60 ))}
|
|
echo "==> raggr-$NEW healthy; draining raggr-$OLD (${STOP_SECONDS}s grace)..."
|
|
docker compose --profile "$OLD" stop -t "$STOP_SECONDS" "raggr-$OLD"
|
|
docker compose --profile "$OLD" rm -f "raggr-$OLD"
|
|
fi
|
|
|
|
echo "==> Deploy complete: raggr-$NEW is live"
|