mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
refactor: Hub二进制改为Docker构建时下载,优化部署流程与worker初始化
- Dockerfile: 移除COPY预编译二进制,改为构建时通过HUB_TAG从GitHub Release下载 - CI: 移除artifact上传/下载步骤,通过build-args传递Hub tag - deploy.sh: 重构参数解析,支持--hub-tag指定版本,跟踪tag变化触发重建 - build.sh: 新增--image模式支持构建并推送Hub Docker镜像 - hub.rs: worker连接时同步所有节点在线状态,避免状态不一致 - proxy_nodes: 启动时主动建立Hub worker连接,消除懒连接窗口期 - docker-compose.yml: app镜像支持APP_IMAGE环境变量配置 - README: 更新部署文档,推荐本地构建方式
This commit is contained in:
@@ -32,6 +32,9 @@ ADMIN_PASSWORD=admin123456
|
||||
# 应用端口(默认 8084)
|
||||
# APP_PORT=8084
|
||||
|
||||
# 生产部署镜像(deploy.sh 会读取)
|
||||
# APP_IMAGE=ghcr.io/fawney19/aether:latest
|
||||
|
||||
# Gunicorn Worker 数量(默认 2)
|
||||
# Docker 部署下 Tunnel Hub 为容器内部固定服务,可安全使用多 worker。
|
||||
# 非 Docker 运行时若使用 ProxyNode tunnel,建议设置为 1。
|
||||
|
||||
77
.github/workflows/docker-publish.yml
vendored
77
.github/workflows/docker-publish.yml
vendored
@@ -179,20 +179,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
hub_tag: ${{ steps.hub-tag.outputs.tag }}
|
||||
steps:
|
||||
- name: Get latest hub release tag
|
||||
id: hub-tag
|
||||
run: |
|
||||
TAG=$(curl -sL "https://api.github.com/repos/${{ env.GITHUB_REPO }}/releases" | \
|
||||
python3 -c "
|
||||
import json, sys
|
||||
releases = json.load(sys.stdin)
|
||||
for r in releases:
|
||||
tag = r.get('tag_name', '')
|
||||
if tag.startswith('hub-v') and not r.get('draft') and not r.get('prerelease'):
|
||||
print(tag)
|
||||
break
|
||||
")
|
||||
TAG=$(
|
||||
curl -sL "https://api.github.com/repos/${{ env.GITHUB_REPO }}/releases" | \
|
||||
python3 - <<'PY'
|
||||
import json, sys
|
||||
releases = json.load(sys.stdin)
|
||||
for r in releases:
|
||||
tag = r.get('tag_name', '')
|
||||
if tag.startswith('hub-v') and not r.get('draft') and not r.get('prerelease'):
|
||||
print(tag)
|
||||
break
|
||||
PY
|
||||
)
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "No hub release found"
|
||||
exit 1
|
||||
@@ -200,28 +204,6 @@ for r in releases:
|
||||
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
||||
echo "Hub release tag: $TAG"
|
||||
|
||||
- name: Download hub binaries
|
||||
run: |
|
||||
TAG="${{ steps.hub-tag.outputs.tag }}"
|
||||
BASE_URL="https://github.com/${{ env.GITHUB_REPO }}/releases/download/$TAG"
|
||||
mkdir -p hub-binaries/amd64 hub-binaries/arm64
|
||||
curl -L --fail -o hub-binaries/amd64/aether-hub-linux-amd64.tar.gz "$BASE_URL/aether-hub-linux-amd64.tar.gz"
|
||||
curl -L --fail -o hub-binaries/arm64/aether-hub-linux-arm64.tar.gz "$BASE_URL/aether-hub-linux-arm64.tar.gz"
|
||||
tar xzf hub-binaries/amd64/aether-hub-linux-amd64.tar.gz -C hub-binaries/amd64
|
||||
tar xzf hub-binaries/arm64/aether-hub-linux-arm64.tar.gz -C hub-binaries/arm64
|
||||
|
||||
- name: Upload amd64 binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hub-binary-amd64
|
||||
path: hub-binaries/amd64/aether-hub
|
||||
|
||||
- name: Upload arm64 binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hub-binary-arm64
|
||||
path: hub-binaries/arm64/aether-hub
|
||||
|
||||
build-app:
|
||||
needs: [check-base-changes, build-base, download-hub]
|
||||
if: always() && (needs.build-base.result == 'success' || needs.build-base.result == 'skipped') && needs.download-hub.result == 'success'
|
||||
@@ -291,25 +273,9 @@ for r in releases:
|
||||
version_tuple = __version_tuple__
|
||||
EOF
|
||||
|
||||
- name: Download hub binary for amd64
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: hub-binary-amd64
|
||||
path: aether-hub/dist-amd64
|
||||
|
||||
- name: Download hub binary for arm64
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: hub-binary-arm64
|
||||
path: aether-hub/dist-arm64
|
||||
|
||||
- name: Prepare hub binary for build
|
||||
- name: Resolve hub release for build args
|
||||
run: |
|
||||
# 为当前构建平台准备二进制(多架构构建每个平台分别运行)
|
||||
# 使用 amd64 作为默认,Buildx 会处理多架构
|
||||
mkdir -p aether-hub/dist
|
||||
cp aether-hub/dist-amd64/aether-hub aether-hub/dist/aether-hub
|
||||
chmod +x aether-hub/dist/aether-hub
|
||||
echo "Hub release tag: ${{ needs.download-hub.outputs.hub_tag }}"
|
||||
|
||||
- name: Build and push app image (amd64)
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -322,13 +288,11 @@ for r in releases:
|
||||
no-cache-filters: builder
|
||||
cache-from: type=gha,scope=app-amd64
|
||||
cache-to: type=gha,mode=min,scope=app-amd64
|
||||
build-args: |
|
||||
HUB_RELEASE_REPO=${{ env.GITHUB_REPO }}
|
||||
HUB_TAG=${{ needs.download-hub.outputs.hub_tag }}
|
||||
platforms: linux/amd64
|
||||
|
||||
- name: Swap hub binary for arm64
|
||||
run: |
|
||||
cp aether-hub/dist-arm64/aether-hub aether-hub/dist/aether-hub
|
||||
chmod +x aether-hub/dist/aether-hub
|
||||
|
||||
- name: Build and push app image (arm64)
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
@@ -340,4 +304,7 @@ for r in releases:
|
||||
no-cache-filters: builder
|
||||
cache-from: type=gha,scope=app-arm64
|
||||
cache-to: type=gha,mode=min,scope=app-arm64
|
||||
build-args: |
|
||||
HUB_RELEASE_REPO=${{ env.GITHUB_REPO }}
|
||||
HUB_TAG=${{ needs.download-hub.outputs.hub_tag }}
|
||||
platforms: linux/arm64
|
||||
|
||||
@@ -12,6 +12,11 @@ RUN cd frontend && npm run build
|
||||
# ==================== 运行时镜像 ====================
|
||||
FROM python:3.13-slim
|
||||
WORKDIR /app
|
||||
|
||||
ARG HUB_RELEASE_REPO=fawney19/Aether
|
||||
ARG HUB_TAG
|
||||
ARG TARGETARCH
|
||||
|
||||
# 运行时依赖(无 gcc/nodejs/npm,使用 BuildKit 缓存加速)
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
@@ -26,9 +31,32 @@ COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/pytho
|
||||
COPY --from=builder /usr/local/bin/gunicorn /usr/local/bin/
|
||||
COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/
|
||||
COPY --from=builder /usr/local/bin/alembic /usr/local/bin/
|
||||
# Hub 预编译二进制(从 GitHub Release 下载)
|
||||
COPY aether-hub/dist/aether-hub /usr/local/bin/aether-hub
|
||||
RUN chmod +x /usr/local/bin/aether-hub
|
||||
# Hub 预编译二进制(构建时从 GitHub Release 下载)
|
||||
RUN set -eux; \
|
||||
tag="${HUB_TAG:-}"; \
|
||||
if [ -z "$tag" ]; then \
|
||||
tag="$(curl -sL "https://api.github.com/repos/${HUB_RELEASE_REPO}/releases" | python3 -c "import json,sys;print(next((r['tag_name'] for r in json.load(sys.stdin) if r.get('tag_name','').startswith('hub-v') and not r.get('draft') and not r.get('prerelease')),''))")"; \
|
||||
fi; \
|
||||
if [ -z "$tag" ]; then \
|
||||
echo "Failed to resolve hub release tag"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
arch="${TARGETARCH:-}"; \
|
||||
if [ -z "$arch" ]; then \
|
||||
arch="$(dpkg --print-architecture)"; \
|
||||
fi; \
|
||||
case "$arch" in \
|
||||
amd64|arm64) ;; \
|
||||
x86_64) arch="amd64" ;; \
|
||||
aarch64) arch="arm64" ;; \
|
||||
*) echo "Unsupported architecture: $arch"; exit 1 ;; \
|
||||
esac; \
|
||||
echo "Using Hub release tag: $tag"; \
|
||||
url="https://github.com/${HUB_RELEASE_REPO}/releases/download/${tag}/aether-hub-linux-${arch}.tar.gz"; \
|
||||
curl -L --fail -o /tmp/aether-hub.tar.gz "$url"; \
|
||||
tar xzf /tmp/aether-hub.tar.gz -C /usr/local/bin; \
|
||||
chmod +x /usr/local/bin/aether-hub; \
|
||||
rm -f /tmp/aether-hub.tar.gz
|
||||
# 从 builder 阶段复制前端构建产物
|
||||
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
|
||||
RUN chmod -R 755 /usr/share/nginx/html
|
||||
|
||||
@@ -16,6 +16,10 @@ FROM python:3.13-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG HUB_RELEASE_REPO=fawney19/Aether
|
||||
ARG HUB_TAG
|
||||
ARG TARGETARCH
|
||||
|
||||
# 运行时依赖(使用清华镜像源 + BuildKit 缓存加速)
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
@@ -34,9 +38,32 @@ COPY --from=builder /usr/local/bin/gunicorn /usr/local/bin/
|
||||
COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/
|
||||
COPY --from=builder /usr/local/bin/alembic /usr/local/bin/
|
||||
|
||||
# Hub 预编译二进制(从 GitHub Release 下载)
|
||||
COPY aether-hub/dist/aether-hub /usr/local/bin/aether-hub
|
||||
RUN chmod +x /usr/local/bin/aether-hub
|
||||
# Hub 预编译二进制(构建时从 GitHub Release 下载)
|
||||
RUN set -eux; \
|
||||
tag="${HUB_TAG:-}"; \
|
||||
if [ -z "$tag" ]; then \
|
||||
tag="$(curl -sL "https://api.github.com/repos/${HUB_RELEASE_REPO}/releases" | python3 -c "import json,sys;print(next((r['tag_name'] for r in json.load(sys.stdin) if r.get('tag_name','').startswith('hub-v') and not r.get('draft') and not r.get('prerelease')),''))")"; \
|
||||
fi; \
|
||||
if [ -z "$tag" ]; then \
|
||||
echo "Failed to resolve hub release tag"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
arch="${TARGETARCH:-}"; \
|
||||
if [ -z "$arch" ]; then \
|
||||
arch="$(dpkg --print-architecture)"; \
|
||||
fi; \
|
||||
case "$arch" in \
|
||||
amd64|arm64) ;; \
|
||||
x86_64) arch="amd64" ;; \
|
||||
aarch64) arch="arm64" ;; \
|
||||
*) echo "Unsupported architecture: $arch"; exit 1 ;; \
|
||||
esac; \
|
||||
echo "Using Hub release tag: $tag"; \
|
||||
url="https://github.com/${HUB_RELEASE_REPO}/releases/download/${tag}/aether-hub-linux-${arch}.tar.gz"; \
|
||||
curl -L --fail -o /tmp/aether-hub.tar.gz "$url"; \
|
||||
tar xzf /tmp/aether-hub.tar.gz -C /usr/local/bin; \
|
||||
chmod +x /usr/local/bin/aether-hub; \
|
||||
rm -f /tmp/aether-hub.tar.gz
|
||||
|
||||
# 从 builder 阶段复制前端构建产物
|
||||
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
|
||||
|
||||
12
README.md
12
README.md
@@ -34,7 +34,7 @@ Aether 是一个自托管的 AI API 网关,为团队和个人提供多租户
|
||||
|
||||
## 部署
|
||||
|
||||
### Docker Compose(推荐:预构建镜像)
|
||||
### Docker Compose(预构建镜像,已废弃)
|
||||
|
||||
```bash
|
||||
# 1. 克隆代码
|
||||
@@ -45,14 +45,14 @@ cd Aether
|
||||
cp .env.example .env
|
||||
python generate_keys.py # 生成密钥, 并将生成的密钥填入 .env
|
||||
|
||||
# 3. 部署 / 更新(自动执行数据库迁移)
|
||||
docker compose pull && docker compose up -d
|
||||
# 3. 该模式已废弃,不再作为推荐部署方式
|
||||
# 现在统一使用下面的“本地构建部署”方式
|
||||
|
||||
# 4. 升级前备份
|
||||
docker compose exec postgres pg_dump -U postgres aether | gzip > backup_$(date +%Y%m%d_%H%M%S).sql.gz
|
||||
```
|
||||
|
||||
### Docker Compose(本地构建镜像)
|
||||
### Docker Compose(推荐:本地构建镜像)
|
||||
|
||||
```bash
|
||||
# 1. 克隆代码
|
||||
@@ -65,6 +65,9 @@ python generate_keys.py # 生成密钥, 并将生成的密钥填入 .env
|
||||
|
||||
# 3. 部署 / 更新(自动构建、启动、迁移)
|
||||
./deploy.sh
|
||||
|
||||
# 可选:固定 Hub release 版本
|
||||
./deploy.sh --hub-tag hub-v0.1.0
|
||||
```
|
||||
|
||||
### 本地开发
|
||||
@@ -180,4 +183,3 @@ docker compose up -d app
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#fawney19/Aether&Date)
|
||||
|
||||
|
||||
54
aether-hub/README.md
Normal file
54
aether-hub/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# aether-hub
|
||||
|
||||
`aether-hub` 是 Tunnel Hub 服务,负责在 proxy 与 worker 之间路由帧。
|
||||
|
||||
## 快速命令
|
||||
|
||||
### 1) 构建并上传 Hub 二进制(推荐生产)
|
||||
|
||||
```bash
|
||||
cd aether-hub
|
||||
./build.sh --upload hub-v0.1.0
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 默认会构建 `amd64 + arm64` 两个二进制并上传到 GitHub Release。
|
||||
- 如只需单架构,可先 `./build.sh amd64` 或 `./build.sh arm64`。
|
||||
|
||||
### 2) 部署端指定 Hub 版本并构建
|
||||
|
||||
```bash
|
||||
cd /path/to/Aether
|
||||
./deploy.sh --hub-tag hub-v0.1.0
|
||||
```
|
||||
|
||||
不指定 `--hub-tag` 时,`./deploy.sh` 会自动解析最新 `hub-v*` release,并在构建 app 镜像时从 GitHub Release 下载对应架构的 Hub 二进制。
|
||||
|
||||
### 3) 镜像模式(可选,调试/实验用)
|
||||
|
||||
仅本地加载镜像(单平台):
|
||||
|
||||
```bash
|
||||
cd aether-hub
|
||||
BUILDKIT_PROGRESS=plain ./build.sh --image --tag local-test --platforms linux/amd64 --load
|
||||
```
|
||||
|
||||
## build.sh 模式说明
|
||||
|
||||
- 默认是 `binary` 模式(`cross` 构建二进制)。
|
||||
- `--upload <hub-vX.Y.Z>` 会把构建产物上传到 GitHub Release。
|
||||
- 加 `--image` 后进入镜像模式(`docker buildx`,可选)。
|
||||
|
||||
常用参数:
|
||||
|
||||
- `--tag <tag>`: 镜像 tag
|
||||
- `--image-name <name>`: 镜像名(默认 `ghcr.io/fawney19/aether-hub`)
|
||||
- `--platforms <list>`: 例如 `linux/amd64,linux/arm64`
|
||||
- `--push`: 推送镜像
|
||||
- `--load`: 加载到本地 Docker(单平台)
|
||||
- `--latest`: 额外打 `latest` tag
|
||||
|
||||
## 与部署脚本关系
|
||||
|
||||
- `./deploy.sh`: 本地构建部署(会本地构建 app/base,并在构建 app 时从 GitHub Release 下载 Hub,可用 `--hub-tag` 固定版本)。
|
||||
@@ -1,131 +1,272 @@
|
||||
#!/bin/bash
|
||||
# 本地构建 aether-hub 多架构二进制
|
||||
# aether-hub 构建脚本
|
||||
#
|
||||
# 前置条件:
|
||||
# cargo install cross --git https://github.com/cross-rs/cross
|
||||
# Docker 或 Podman 运行中(cross 需要容器环境)
|
||||
# 支持两种模式:
|
||||
# 1) binary 模式(默认): 构建多架构二进制并可上传 GitHub Release
|
||||
# 2) image 模式: 构建并推送/加载 Docker 镜像(推荐生产发布用)
|
||||
#
|
||||
# 用法:
|
||||
# ./build.sh # 构建 linux/amd64 + linux/arm64
|
||||
# ./build.sh amd64 # 仅构建 linux/amd64
|
||||
# ./build.sh arm64 # 仅构建 linux/arm64
|
||||
# ./build.sh --upload v0.1.0 # 构建并上传到 GitHub Release(需要 gh CLI)
|
||||
# 示例:
|
||||
# # binary 模式(兼容旧行为)
|
||||
# ./build.sh
|
||||
# ./build.sh amd64
|
||||
# ./build.sh --upload hub-v0.1.0
|
||||
#
|
||||
# # image 模式(多架构推送)
|
||||
# ./build.sh --image --tag v0.2.5 --push --latest
|
||||
# ./build.sh --image --tag sha-abc123 --image-name ghcr.io/fawney19/aether-hub --push
|
||||
# ./build.sh --image --tag local-test --platforms linux/amd64 --load
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
DIST_DIR="$SCRIPT_DIR/dist"
|
||||
|
||||
# 解析参数
|
||||
# -------------------------------
|
||||
# Defaults
|
||||
# -------------------------------
|
||||
MODE="binary" # binary | image
|
||||
|
||||
# binary mode options
|
||||
UPLOAD=false
|
||||
TAG=""
|
||||
BUILD_TARGETS=""
|
||||
UPLOAD_TAG=""
|
||||
BINARY_TARGETS=""
|
||||
|
||||
# image mode options
|
||||
IMAGE_NAME="${IMAGE_NAME:-ghcr.io/fawney19/aether-hub}"
|
||||
IMAGE_TAG=""
|
||||
IMAGE_PLATFORMS="linux/amd64,linux/arm64"
|
||||
IMAGE_PUSH=false
|
||||
IMAGE_LOAD=false
|
||||
IMAGE_LATEST=false
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
./build.sh [binary-args]
|
||||
./build.sh --image [image-args]
|
||||
|
||||
binary 模式(默认):
|
||||
amd64|arm64 仅构建指定架构(可重复)
|
||||
--upload <hub-vX.Y.Z> 上传到 GitHub Release(需要 gh CLI)
|
||||
|
||||
image 模式:
|
||||
--image 启用镜像模式
|
||||
--tag <tag> 镜像 tag(默认自动从 git describe 推导)
|
||||
--image-name <name> 镜像名(默认 ghcr.io/fawney19/aether-hub)
|
||||
--platforms <list> 平台列表,逗号分隔(默认 linux/amd64,linux/arm64)
|
||||
--push 推送镜像到仓库
|
||||
--load 加载到本地 Docker(仅单平台)
|
||||
--latest 额外打 latest tag
|
||||
|
||||
通用:
|
||||
-h, --help 显示帮助
|
||||
EOF
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--image)
|
||||
MODE="image"
|
||||
shift
|
||||
;;
|
||||
--tag)
|
||||
IMAGE_TAG="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--image-name)
|
||||
IMAGE_NAME="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--platforms)
|
||||
IMAGE_PLATFORMS="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
--push)
|
||||
IMAGE_PUSH=true
|
||||
shift
|
||||
;;
|
||||
--load)
|
||||
IMAGE_LOAD=true
|
||||
shift
|
||||
;;
|
||||
--latest)
|
||||
IMAGE_LATEST=true
|
||||
shift
|
||||
;;
|
||||
--upload)
|
||||
UPLOAD=true
|
||||
TAG="$2"
|
||||
UPLOAD_TAG="${2:-}"
|
||||
shift 2
|
||||
;;
|
||||
amd64|arm64)
|
||||
BUILD_TARGETS="$BUILD_TARGETS $1"
|
||||
BINARY_TARGETS="$BINARY_TARGETS $1"
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 [amd64|arm64] [--upload <tag>]"
|
||||
echo "❌ 未知参数: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 默认构建所有平台
|
||||
if [ -z "$BUILD_TARGETS" ]; then
|
||||
BUILD_TARGETS="amd64 arm64"
|
||||
fi
|
||||
build_binary() {
|
||||
if [ -z "$BINARY_TARGETS" ]; then
|
||||
BINARY_TARGETS="amd64 arm64"
|
||||
fi
|
||||
|
||||
# 检查 cross 是否安装
|
||||
if ! command -v cross &> /dev/null; then
|
||||
echo "❌ 需要安装 cross: cargo install cross --git https://github.com/cross-rs/cross"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 创建输出目录
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
echo "🔨 开始构建 aether-hub..."
|
||||
echo " 目标平台: $BUILD_TARGETS"
|
||||
echo ""
|
||||
|
||||
ARTIFACTS=""
|
||||
|
||||
for arch in $BUILD_TARGETS; do
|
||||
# 映射架构到 Rust target
|
||||
case "$arch" in
|
||||
amd64) target="x86_64-unknown-linux-gnu" ;;
|
||||
arm64) target="aarch64-unknown-linux-gnu" ;;
|
||||
*) echo "❌ 未知架构: $arch"; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo ">>> 构建 $arch ($target)..."
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
cross build --release --target "$target" --locked
|
||||
|
||||
# 提取二进制
|
||||
BIN="target/$target/release/aether-hub"
|
||||
if [ ! -f "$BIN" ]; then
|
||||
echo "❌ 未找到二进制文件: $BIN"
|
||||
if ! command -v cross >/dev/null 2>&1; then
|
||||
echo "❌ 需要安装 cross: cargo install cross --git https://github.com/cross-rs/cross"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 打包
|
||||
ARCHIVE="$DIST_DIR/aether-hub-linux-$arch.tar.gz"
|
||||
tar czf "$ARCHIVE" -C "target/$target/release" aether-hub
|
||||
ARTIFACTS="$ARTIFACTS $ARCHIVE"
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
SIZE=$(du -h "$ARCHIVE" | cut -f1)
|
||||
echo "✅ $arch 构建完成: $ARCHIVE ($SIZE)"
|
||||
echo "🔨 开始构建 aether-hub 二进制..."
|
||||
echo " 目标平台: $BINARY_TARGETS"
|
||||
echo ""
|
||||
done
|
||||
|
||||
# 生成校验和
|
||||
cd "$DIST_DIR"
|
||||
shasum -a 256 aether-hub-*.tar.gz > SHA256SUMS.txt
|
||||
echo "📋 SHA256 校验和:"
|
||||
cat SHA256SUMS.txt
|
||||
echo ""
|
||||
ARTIFACTS=""
|
||||
for arch in $BINARY_TARGETS; do
|
||||
case "$arch" in
|
||||
amd64) target="x86_64-unknown-linux-gnu" ;;
|
||||
arm64) target="aarch64-unknown-linux-gnu" ;;
|
||||
*) echo "❌ 未知架构: $arch"; exit 1 ;;
|
||||
esac
|
||||
|
||||
# 上传到 GitHub Release
|
||||
if [ "$UPLOAD" = true ]; then
|
||||
if [ -z "$TAG" ]; then
|
||||
echo "❌ --upload 需要指定 tag,例如: ./build.sh --upload hub-v0.1.0"
|
||||
echo ">>> 构建 $arch ($target)..."
|
||||
cd "$SCRIPT_DIR"
|
||||
cross build --release --target "$target" --locked
|
||||
|
||||
BIN="target/$target/release/aether-hub"
|
||||
if [ ! -f "$BIN" ]; then
|
||||
echo "❌ 未找到二进制文件: $BIN"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCHIVE="$DIST_DIR/aether-hub-linux-$arch.tar.gz"
|
||||
tar czf "$ARCHIVE" -C "target/$target/release" aether-hub
|
||||
ARTIFACTS="$ARTIFACTS $ARCHIVE"
|
||||
|
||||
SIZE=$(du -h "$ARCHIVE" | cut -f1)
|
||||
echo "✅ $arch 构建完成: $ARCHIVE ($SIZE)"
|
||||
echo ""
|
||||
done
|
||||
|
||||
cd "$DIST_DIR"
|
||||
shasum -a 256 aether-hub-*.tar.gz > SHA256SUMS.txt
|
||||
echo "📋 SHA256 校验和:"
|
||||
cat SHA256SUMS.txt
|
||||
echo ""
|
||||
|
||||
if [ "$UPLOAD" = true ]; then
|
||||
if [ -z "$UPLOAD_TAG" ]; then
|
||||
echo "❌ --upload 需要指定 tag,例如: ./build.sh --upload hub-v0.1.0"
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v gh >/dev/null 2>&1; then
|
||||
echo "❌ 需要安装 GitHub CLI: brew install gh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📦 上传到 GitHub Release: $UPLOAD_TAG"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
if ! git rev-parse "$UPLOAD_TAG" >/dev/null 2>&1; then
|
||||
git tag "$UPLOAD_TAG"
|
||||
git push origin "$UPLOAD_TAG"
|
||||
fi
|
||||
|
||||
gh release create "$UPLOAD_TAG" \
|
||||
--title "aether-hub ${UPLOAD_TAG#hub-}" \
|
||||
--generate-notes \
|
||||
$ARTIFACTS \
|
||||
"$DIST_DIR/SHA256SUMS.txt"
|
||||
|
||||
echo "✅ 上传完成!"
|
||||
fi
|
||||
|
||||
echo "🎉 binary 模式完成!"
|
||||
}
|
||||
|
||||
build_image() {
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "❌ 未找到 docker,请先安装 Docker"
|
||||
exit 1
|
||||
fi
|
||||
if ! docker buildx version >/dev/null 2>&1; then
|
||||
echo "❌ 未找到 docker buildx,请先启用 buildx"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "❌ 需要安装 GitHub CLI: brew install gh"
|
||||
if [ "$IMAGE_PUSH" = true ] && [ "$IMAGE_LOAD" = true ]; then
|
||||
echo "❌ --push 与 --load 不能同时使用"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📦 上传到 GitHub Release: $TAG"
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# 创建 tag(如果不存在)
|
||||
if ! git rev-parse "$TAG" > /dev/null 2>&1; then
|
||||
git tag "$TAG"
|
||||
git push origin "$TAG"
|
||||
if [ "$IMAGE_PUSH" = false ] && [ "$IMAGE_LOAD" = false ]; then
|
||||
# image 模式默认走 push,符合发布场景
|
||||
IMAGE_PUSH=true
|
||||
fi
|
||||
|
||||
# 创建 Release 并上传
|
||||
gh release create "$TAG" \
|
||||
--title "aether-hub ${TAG#hub-}" \
|
||||
--generate-notes \
|
||||
$ARTIFACTS \
|
||||
"$DIST_DIR/SHA256SUMS.txt"
|
||||
if [ -z "$IMAGE_TAG" ]; then
|
||||
IMAGE_TAG=$(git -C "$PROJECT_DIR" describe --tags --always 2>/dev/null | sed 's/^v//')
|
||||
if [ -z "$IMAGE_TAG" ]; then
|
||||
IMAGE_TAG=$(date +%Y%m%d%H%M%S)
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ 上传完成!"
|
||||
if [ "$IMAGE_LOAD" = true ] && [[ "$IMAGE_PLATFORMS" == *,* ]]; then
|
||||
echo "❌ --load 仅支持单平台,请用 --platforms linux/amd64(或 arm64)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local ref="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
local cmd=(docker buildx build
|
||||
--platform "$IMAGE_PLATFORMS"
|
||||
-f "$SCRIPT_DIR/Dockerfile"
|
||||
-t "$ref"
|
||||
)
|
||||
|
||||
if [ "$IMAGE_LATEST" = true ]; then
|
||||
cmd+=(-t "${IMAGE_NAME}:latest")
|
||||
fi
|
||||
|
||||
if [ "$IMAGE_PUSH" = true ]; then
|
||||
cmd+=(--push)
|
||||
else
|
||||
cmd+=(--load)
|
||||
fi
|
||||
|
||||
cmd+=("$SCRIPT_DIR")
|
||||
|
||||
echo "🔨 开始构建 aether-hub 镜像..."
|
||||
echo " image: $ref"
|
||||
echo " platforms: $IMAGE_PLATFORMS"
|
||||
echo " mode: $([ "$IMAGE_PUSH" = true ] && echo push || echo load)"
|
||||
echo ""
|
||||
|
||||
"${cmd[@]}"
|
||||
|
||||
if [ "$IMAGE_PUSH" = true ]; then
|
||||
echo "✅ 镜像已推送: $ref"
|
||||
if [ "$IMAGE_LATEST" = true ]; then
|
||||
echo "✅ 镜像已推送: ${IMAGE_NAME}:latest"
|
||||
fi
|
||||
else
|
||||
echo "✅ 镜像已加载到本地: $ref"
|
||||
fi
|
||||
|
||||
echo "🎉 image 模式完成!"
|
||||
}
|
||||
|
||||
if [ "$MODE" = "image" ]; then
|
||||
build_image
|
||||
else
|
||||
build_binary
|
||||
fi
|
||||
|
||||
echo "🎉 全部完成!"
|
||||
|
||||
@@ -258,7 +258,8 @@ impl HubRouter {
|
||||
|
||||
pub fn register_worker(&self, conn: Arc<WorkerConn>) {
|
||||
info!(worker_id = conn.id, "worker connected");
|
||||
self.worker_conns.insert(conn.id, conn);
|
||||
self.worker_conns.insert(conn.id, conn.clone());
|
||||
self.sync_node_status_to_worker(&conn);
|
||||
}
|
||||
|
||||
pub fn unregister_worker(&self, conn_id: u64) {
|
||||
@@ -667,6 +668,28 @@ impl HubRouter {
|
||||
);
|
||||
}
|
||||
|
||||
/// When a worker connects, sync all current node statuses so worker state
|
||||
/// is consistent even if proxies connected before this worker came online.
|
||||
fn sync_node_status_to_worker(&self, worker: &Arc<WorkerConn>) {
|
||||
let snapshot: Vec<(String, usize)> = {
|
||||
let map = self.proxy_conns.read();
|
||||
map.iter()
|
||||
.map(|(node_id, conns)| (node_id.clone(), conns.len()))
|
||||
.collect()
|
||||
};
|
||||
|
||||
for (node_id, conn_count) in &snapshot {
|
||||
let frame = protocol::encode_node_status(node_id, *conn_count > 0, *conn_count);
|
||||
let _ = worker.send(Message::Binary(frame.into()));
|
||||
}
|
||||
|
||||
debug!(
|
||||
worker_id = worker.id,
|
||||
nodes_synced = snapshot.len(),
|
||||
"synced NODE_STATUS snapshot to worker"
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Stats
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
199
deploy.sh
199
deploy.sh
@@ -2,12 +2,13 @@
|
||||
# 智能部署脚本 - 自动检测依赖/代码/迁移变化
|
||||
#
|
||||
# 用法:
|
||||
# 部署/更新: ./deploy.sh (自动检测所有变化)
|
||||
# 强制重建: ./deploy.sh --rebuild-base
|
||||
# 更新 Hub: ./deploy.sh --update-hub
|
||||
# 强制全部重建: ./deploy.sh --force
|
||||
# 部署/更新: ./deploy.sh (自动检测所有变化)
|
||||
# 指定 Hub 版本: ./deploy.sh --hub-tag hub-v0.1.0
|
||||
# 更新 Hub: ./deploy.sh --update-hub
|
||||
# 强制重建: ./deploy.sh --rebuild-base
|
||||
# 强制全部重建: ./deploy.sh --force
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# 兼容 docker-compose 和 docker compose
|
||||
@@ -32,10 +33,69 @@ HASH_FILE=".deps-hash"
|
||||
CODE_HASH_FILE=".code-hash"
|
||||
MIGRATION_HASH_FILE=".migration-hash"
|
||||
|
||||
# Hub 二进制配置
|
||||
# Hub release 配置
|
||||
GITHUB_REPO="fawney19/Aether"
|
||||
HUB_DIST_DIR="aether-hub/dist"
|
||||
HUB_VERSION_FILE="$HUB_DIST_DIR/.version"
|
||||
HUB_TAG_STATE_FILE=".hub-tag"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: ./deploy.sh [options]
|
||||
|
||||
Options:
|
||||
--hub-tag <hub-vX.Y.Z> 指定 Hub Release tag(例如 hub-v0.1.0)
|
||||
--update-hub 强制刷新 Hub 版本标记(下次构建会重新下载)
|
||||
--rebuild-base, -r 仅重建 base 镜像
|
||||
--force, -f 强制重建全部(hub/base/app)并重启
|
||||
-h, --help 显示帮助
|
||||
EOF
|
||||
}
|
||||
|
||||
FORCE_REBUILD_ALL=false
|
||||
REBUILD_BASE_ONLY=false
|
||||
FORCE_UPDATE_HUB=false
|
||||
HUB_TAG="${HUB_TAG:-}"
|
||||
RESOLVED_HUB_TAG=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--hub-tag)
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "❌ --hub-tag 需要一个值,例如 hub-v0.1.0"
|
||||
exit 1
|
||||
fi
|
||||
HUB_TAG="$2"
|
||||
shift 2
|
||||
;;
|
||||
--update-hub)
|
||||
FORCE_UPDATE_HUB=true
|
||||
shift
|
||||
;;
|
||||
--rebuild-base|-r)
|
||||
REBUILD_BASE_ONLY=true
|
||||
shift
|
||||
;;
|
||||
--force|-f)
|
||||
FORCE_REBUILD_ALL=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "❌ 未知参数: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -n "$HUB_TAG" ]; then
|
||||
case "$HUB_TAG" in
|
||||
hub-v*) ;;
|
||||
*) echo "❌ --hub-tag 格式应为 hub-vX.Y.Z,例如 hub-v0.1.0"; exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 提取 pyproject.toml 中"会影响运行时依赖安装"的最小指纹(与 CI 保持一致):
|
||||
# - [build-system] requires / build-backend
|
||||
@@ -79,17 +139,6 @@ calc_code_hash() {
|
||||
} | md5sum | cut -d' ' -f1
|
||||
}
|
||||
|
||||
# 检测目标平台架构
|
||||
detect_arch() {
|
||||
local machine
|
||||
machine=$(uname -m)
|
||||
case "$machine" in
|
||||
x86_64|amd64) echo "amd64" ;;
|
||||
aarch64|arm64) echo "arm64" ;;
|
||||
*) echo "❌ 不支持的架构: $machine" >&2; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 获取最新 hub release tag
|
||||
get_latest_hub_tag() {
|
||||
curl -sL "https://api.github.com/repos/$GITHUB_REPO/releases" | \
|
||||
@@ -104,58 +153,45 @@ for r in releases:
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
# 下载 Hub 预编译二进制
|
||||
download_hub() {
|
||||
local tag="$1"
|
||||
local arch
|
||||
arch=$(detect_arch)
|
||||
# 解析当前应使用的 Hub release tag(优先使用指定值,否则拉取最新)
|
||||
resolve_hub_tag() {
|
||||
local requested_tag="${1:-}"
|
||||
local latest_tag
|
||||
|
||||
if [ -z "$tag" ]; then
|
||||
echo ">>> 正在查询最新 Hub 版本..."
|
||||
tag=$(get_latest_hub_tag)
|
||||
if [ -z "$tag" ]; then
|
||||
echo "❌ 无法获取最新 Hub Release,请检查网络或手动指定版本"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ">>> Hub 版本: $tag, 架构: $arch"
|
||||
|
||||
# 检查是否已下载
|
||||
if [ -f "$HUB_VERSION_FILE" ] && [ "$(cat "$HUB_VERSION_FILE")" = "$tag-$arch" ] && [ -f "$HUB_DIST_DIR/aether-hub" ]; then
|
||||
echo ">>> Hub 二进制已是最新 ($tag), 跳过下载."
|
||||
if [ -n "$requested_tag" ]; then
|
||||
echo "$requested_tag"
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$HUB_DIST_DIR"
|
||||
latest_tag="$(get_latest_hub_tag || true)"
|
||||
if [ -n "$latest_tag" ]; then
|
||||
echo "$latest_tag"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local archive="aether-hub-linux-$arch.tar.gz"
|
||||
local url="https://github.com/$GITHUB_REPO/releases/download/$tag/$archive"
|
||||
if [ -f "$HUB_TAG_STATE_FILE" ]; then
|
||||
echo "⚠️ 无法查询最新 Hub 版本,回退使用本地记录: $(cat "$HUB_TAG_STATE_FILE")" >&2
|
||||
cat "$HUB_TAG_STATE_FILE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ">>> 下载 Hub 二进制: $url"
|
||||
curl -L --fail -o "$HUB_DIST_DIR/$archive" "$url" || {
|
||||
echo "❌ 下载失败: $url"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 解压
|
||||
tar xzf "$HUB_DIST_DIR/$archive" -C "$HUB_DIST_DIR"
|
||||
chmod +x "$HUB_DIST_DIR/aether-hub"
|
||||
rm -f "$HUB_DIST_DIR/$archive"
|
||||
|
||||
# 记录版本
|
||||
echo "$tag-$arch" > "$HUB_VERSION_FILE"
|
||||
echo "✅ Hub 二进制下载完成."
|
||||
echo "❌ 无法获取 Hub Release tag,请检查网络或手动指定 --hub-tag" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 确保 Hub 二进制存在
|
||||
ensure_hub_binary() {
|
||||
if [ ! -f "$HUB_DIST_DIR/aether-hub" ]; then
|
||||
echo ">>> Hub 二进制不存在,正在下载..."
|
||||
download_hub
|
||||
return 0
|
||||
# 确保本次构建的 Hub tag 已解析(默认追踪最新 release,也可通过 --hub-tag 固定版本)
|
||||
ensure_hub_tag() {
|
||||
local requested_tag="${1:-}"
|
||||
RESOLVED_HUB_TAG="$(resolve_hub_tag "$requested_tag")"
|
||||
|
||||
if [ -f "$HUB_TAG_STATE_FILE" ] && [ "$(cat "$HUB_TAG_STATE_FILE")" = "$RESOLVED_HUB_TAG" ]; then
|
||||
echo ">>> Hub 版本未变化: $RESOLVED_HUB_TAG"
|
||||
return 1
|
||||
fi
|
||||
return 1
|
||||
|
||||
echo "$RESOLVED_HUB_TAG" > "$HUB_TAG_STATE_FILE"
|
||||
echo ">>> 使用 Hub 版本: $RESOLVED_HUB_TAG"
|
||||
return 0
|
||||
}
|
||||
|
||||
# 计算迁移文件的哈希值
|
||||
@@ -235,8 +271,17 @@ EOF
|
||||
# 构建应用镜像
|
||||
build_app() {
|
||||
echo ">>> Building app image (code only)..."
|
||||
if [ -z "${RESOLVED_HUB_TAG:-}" ]; then
|
||||
echo "❌ RESOLVED_HUB_TAG 为空,无法构建 app 镜像"
|
||||
exit 1
|
||||
fi
|
||||
echo ">>> Build args: HUB_TAG=$RESOLVED_HUB_TAG"
|
||||
generate_version_file
|
||||
docker build --pull=false -f Dockerfile.app.local -t aether-app:latest .
|
||||
docker build --pull=false \
|
||||
--build-arg HUB_RELEASE_REPO="$GITHUB_REPO" \
|
||||
--build-arg HUB_TAG="$RESOLVED_HUB_TAG" \
|
||||
-f Dockerfile.app.local \
|
||||
-t aether-app:latest .
|
||||
save_code_hash
|
||||
}
|
||||
|
||||
@@ -284,9 +329,12 @@ print('Old version cleared')
|
||||
}
|
||||
|
||||
# 强制全部重建
|
||||
if [ "$1" = "--force" ] || [ "$1" = "-f" ]; then
|
||||
if [ "$FORCE_REBUILD_ALL" = true ]; then
|
||||
echo ">>> Force rebuilding everything..."
|
||||
download_hub
|
||||
if [ "$FORCE_UPDATE_HUB" = true ]; then
|
||||
rm -f "$HUB_TAG_STATE_FILE"
|
||||
fi
|
||||
ensure_hub_tag "$HUB_TAG" || true
|
||||
build_base
|
||||
build_app
|
||||
compose_up --force-recreate
|
||||
@@ -299,17 +347,18 @@ if [ "$1" = "--force" ] || [ "$1" = "-f" ]; then
|
||||
fi
|
||||
|
||||
# 强制重建基础镜像
|
||||
if [ "$1" = "--rebuild-base" ] || [ "$1" = "-r" ]; then
|
||||
if [ "$REBUILD_BASE_ONLY" = true ]; then
|
||||
build_base
|
||||
echo ">>> Base image rebuilt. Run ./deploy.sh to deploy."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 更新 Hub 二进制
|
||||
if [ "$1" = "--update-hub" ]; then
|
||||
rm -f "$HUB_VERSION_FILE"
|
||||
download_hub
|
||||
echo ">>> Hub binary updated. Run ./deploy.sh to deploy."
|
||||
# 更新 Hub 版本标记
|
||||
if [ "$FORCE_UPDATE_HUB" = true ]; then
|
||||
rm -f "$HUB_TAG_STATE_FILE"
|
||||
ensure_hub_tag "$HUB_TAG" || true
|
||||
echo ">>> Hub tag updated: $RESOLVED_HUB_TAG"
|
||||
echo ">>> Run ./deploy.sh to build app image with the new Hub release."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -337,12 +386,12 @@ else
|
||||
echo ">>> Dependencies unchanged."
|
||||
fi
|
||||
|
||||
# 确保 Hub 二进制存在
|
||||
if ensure_hub_binary; then
|
||||
# 解析/检查 Hub 版本(构建时由 Dockerfile 从 GitHub Release 下载)
|
||||
if ensure_hub_tag "$HUB_TAG"; then
|
||||
HUB_UPDATED=true
|
||||
NEED_RESTART=true
|
||||
else
|
||||
echo ">>> Hub binary present."
|
||||
echo ">>> Hub version unchanged."
|
||||
fi
|
||||
|
||||
# 检查代码或迁移是否变化,或者 base 重建了(app 依赖 base)
|
||||
@@ -361,7 +410,7 @@ elif [ "$BASE_REBUILT" = true ]; then
|
||||
build_app
|
||||
NEED_RESTART=true
|
||||
elif [ "$HUB_UPDATED" = true ]; then
|
||||
echo ">>> Hub binary updated, rebuilding app image..."
|
||||
echo ">>> Hub version updated, rebuilding app image..."
|
||||
build_app
|
||||
NEED_RESTART=true
|
||||
elif check_code_changed; then
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# Aether 部署配置 - 本地构建
|
||||
# 使用方法:
|
||||
# 首次构建 base: docker build -f Dockerfile.base -t aether-base:latest .
|
||||
# Hub 二进制: cd aether-hub && ./build.sh 或 deploy.sh 自动下载
|
||||
# Hub 二进制: cd aether-hub && ./build.sh(默认 binary 模式)供发布;deploy.sh 构建 app 时会自动下载
|
||||
# Hub 镜像发布: cd aether-hub && ./build.sh --image --tag <tag> --push(可选)
|
||||
# 启动服务: docker compose -f docker-compose.build.yml up -d --build
|
||||
# 或使用: ./deploy.sh
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
||||
@@ -33,7 +33,7 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
app:
|
||||
image: ghcr.io/fawney19/aether:latest
|
||||
image: ${APP_IMAGE:-ghcr.io/fawney19/aether:latest}
|
||||
container_name: aether-app
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
@@ -97,6 +97,19 @@ async def _on_startup() -> None:
|
||||
config.worker_processes,
|
||||
)
|
||||
|
||||
# Hub 模式下,worker 启动时主动建立 /worker 长连接:
|
||||
# - 立即接收 NODE_STATUS 广播,避免“proxy 已连但 UI 仍显示离线”的窗口期
|
||||
# - 确保后续 tunnel 请求不需要首请求触发懒连接
|
||||
if hub_enabled:
|
||||
from src.services.proxy_node.hub_transport import get_hub_connection_manager
|
||||
|
||||
try:
|
||||
await get_hub_connection_manager().ensure_connected()
|
||||
logger.info("Hub worker channel initialized on startup")
|
||||
except Exception as e:
|
||||
# ensure_connected 失败时内部会启动重连循环,这里仅记录告警不阻塞启动
|
||||
logger.warning("Hub worker channel init failed, reconnecting in background: {}", e)
|
||||
|
||||
from src.clients import get_redis_client
|
||||
|
||||
redis_client = await get_redis_client()
|
||||
|
||||
Reference in New Issue
Block a user