Skip to content

Commit f388a19

Browse files
committed
fix(deploy): run compose via remote-up-prod.sh; resilient setMyCommands
- Add scripts/remote-up-prod.sh so SSH runs a single bash in deploy dir (avoids quoting bugs; prints services and ps -a). - Write .deploy-revision via scp (git SHA + UTC time) for server verification. - Do not exit bot if setMyCommands fails so /gettoken still works; log error. Made-with: Cursor
1 parent 0a22464 commit f388a19

3 files changed

Lines changed: 47 additions & 9 deletions

File tree

scripts/deploy-prod.sh

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ print(username, end="")'
3838
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
3939
TMP_ARCHIVE="$(mktemp /tmp/spawndock-api.XXXXXX.tar.gz)"
4040
TMP_ENV="$(mktemp /tmp/spawndock-api.env.XXXXXX)"
41+
TMP_DEPLOY_REV="$(mktemp /tmp/spawndock-api.rev.XXXXXX)"
42+
BUNDLE_REV="$(git -C "$ROOT_DIR" rev-parse HEAD 2>/dev/null || echo unknown)"
4143

4244
tar \
4345
--exclude=".git" \
@@ -48,7 +50,7 @@ tar \
4850
.
4951

5052
cleanup() {
51-
rm -f "$TMP_ARCHIVE" "$TMP_ENV"
53+
rm -f "$TMP_ARCHIVE" "$TMP_ENV" "$TMP_DEPLOY_REV"
5254
}
5355
trap cleanup EXIT
5456

@@ -86,17 +88,18 @@ eval "$SCP '$TMP_ARCHIVE' $SSH_USER@$SSH_HOST:$TARGET_DIR/release.tar.gz"
8688
eval "$SCP '$TMP_ENV' $SSH_USER@$SSH_HOST:$TARGET_DIR/.env"
8789
eval "$SSH 'chmod 0600 $TARGET_DIR/.env'"
8890
eval "$SSH 'cd $TARGET_DIR && tar -xzf release.tar.gz && rm -f release.tar.gz'"
89-
# Fail fast if the bundle did not ship the sidecar stack (common cause: stale local checkout or wrong CWD).
90-
eval "$SSH 'cd $TARGET_DIR && grep -q \"^ qwen-search:\" docker-compose.prod.yml'"
91+
{
92+
printf '%s\n' "$BUNDLE_REV"
93+
date -u +%Y-%m-%dT%H:%M:%SZ
94+
} >"$TMP_DEPLOY_REV"
95+
eval "$SCP '$TMP_DEPLOY_REV' $SSH_USER@$SSH_HOST:$TARGET_DIR/.deploy-revision"
9196

92-
# Recreate everything so added services (e.g. qwen-search) are not skipped; print compose state for debugging.
93-
eval "$SSH 'cd $TARGET_DIR && docker compose -f docker-compose.prod.yml config --services'"
94-
eval "$SSH 'cd $TARGET_DIR && docker compose -f docker-compose.prod.yml build'"
95-
eval "$SSH 'cd $TARGET_DIR && docker compose -f docker-compose.prod.yml up -d --remove-orphans --force-recreate'"
96-
eval "$SSH 'cd $TARGET_DIR && docker compose -f docker-compose.prod.yml ps -a'"
97+
# One remote bash script avoids broken nested quoting and guarantees compose runs in the deploy directory.
98+
eval "$SSH 'cd $TARGET_DIR && bash scripts/remote-up-prod.sh'"
9799

98100
HEALTH_URL="${PUBLIC_ORIGIN%/}/health"
99101
eval "$SSH 'curl -fsS $HEALTH_URL'"
100102

101103
echo "Deployed SpawnDock API to $PUBLIC_ORIGIN (health: $HEALTH_URL)"
104+
echo "Bundle git: $BUNDLE_REV — verify remote-up-prod output lists qwen-search and ps -a shows it running or starting."
102105
echo "API_TOKEN stored in remote $TARGET_DIR/.env (use Telegram /gettoken or read file on host)."

scripts/remote-up-prod.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
# Run on the production host inside the extracted API tree (e.g. /srv/spawndock-api).
3+
set -euo pipefail
4+
5+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6+
cd "$ROOT"
7+
export COMPOSE_FILE=docker-compose.prod.yml
8+
9+
echo "=== remote-up-prod: ROOT=$ROOT ==="
10+
if [[ -f .deploy-revision ]]; then
11+
echo "=== bundle revision ==="
12+
cat .deploy-revision || true
13+
fi
14+
15+
if ! grep -q '^ qwen-search:' docker-compose.prod.yml; then
16+
echo "ERROR: docker-compose.prod.yml missing qwen-search (stale extract or wrong directory)." >&2
17+
exit 1
18+
fi
19+
20+
echo "=== docker compose config --services ==="
21+
docker compose config --services
22+
23+
echo "=== docker compose build ==="
24+
docker compose build
25+
26+
echo "=== docker compose up ==="
27+
docker compose up -d --remove-orphans --force-recreate
28+
29+
echo "=== docker compose ps -a ==="
30+
docker compose ps -a

src/bot/polling.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,12 @@ async function getLatestOffset(token: string): Promise<number> {
224224
async function main(): Promise<void> {
225225
const cfg = readBotConfig();
226226
await deleteWebhook(cfg.telegramBotToken);
227-
await setMyCommands(cfg.telegramBotToken);
227+
try {
228+
await setMyCommands(cfg.telegramBotToken);
229+
} catch (err: any) {
230+
// Do not exit: polling and typed commands still work; menu may stay stale until Telegram API succeeds.
231+
console.error(`setMyCommands failed (menu may be stale): ${err?.message ?? err}`);
232+
}
228233

229234
const startOffset = await getLatestOffset(cfg.telegramBotToken);
230235
console.log(`SpawnDock bot polling started against ${cfg.controlPlaneUrl} (offset=${startOffset})`);

0 commit comments

Comments
 (0)