mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 22:55:41 +00:00
CRITICAL: Fix save() to merge with existing games.e0es (#5233)
* Fix critical bug: save() now merges with existing games.e0es CRITICAL BUG FIX: With lazy loading, gameControllerInfos only contains games that have been loaded into memory. The old save() would overwrite games.e0es with only the loaded games, losing all unloaded games. This caused complete data loss of user-to-game mappings when: 1. New server started (empty gameControllerInfos) 2. Any operation triggered save() 3. games.e0es was overwritten with empty data Fix: save() now reads existing games.e0es first and merges: - Unloaded games are preserved from disk - Loaded games use fresh in-memory state Also adds logging to diagnose games.e0es read failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add S3 backup of games.e0es during blue-green deployment After stopping the old container (which flushes state to storage), create a timestamped backup in S3 before switching nginx traffic. This provides a recovery point if something goes wrong during deployment. Backups are stored at: s3://eagle0/eagle/save/backups/games.e0es.<timestamp> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Fix blue-green deployment dependencies and auth routing 1. docker-compose.prod.yml: - Remove eagle-blue from nginx depends_on (use EAGLE_ADDR variable instead) - Remove eagle-blue from admin depends_on (use EAGLE_ADDR variable instead) - Add TODO note about jfr-sidecar limitation during green deployments 2. nginx/nginx.conf: - Fix auth.Auth location on port 443 to route to auth:40033 instead of eagle_backend. This was causing auth failures when clients connected via the main HTTPS port. These changes allow blue-green deployments to work without hard dependencies that cause docker-compose to recreate stopped containers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Add jfr-sidecar-green for blue-green JFR profiling support - Add jfr-sidecar-green service that shares PID namespace with eagle-green - Make admin's jfr-sidecar address configurable via JFR_SIDECAR_ADDR env var - Update deploy script to: - Start appropriate jfr-sidecar with each eagle instance - Update .env with EAGLE_ADDR and JFR_SIDECAR_ADDR after switching - Restart admin service to pick up new addresses - Clean up old jfr-sidecar when removing old eagle instance This ensures the JFR button in admin console works regardless of whether blue or green is the active instance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Sync config files from GitHub at start of deployment Downloads docker-compose.prod.yml and nginx.conf from the main branch before starting deployment. This ensures new services (like jfr-sidecar-green) are available when the deploy script runs. - Preserves the current active instance in nginx.conf - Creates .bak backups before overwriting - Continues with existing files if GitHub fetch fails 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,38 @@ log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# GitHub raw URL base for fetching config files
|
||||
GITHUB_RAW_BASE="https://raw.githubusercontent.com/nolen777/eagle0/main"
|
||||
|
||||
# Sync config files from GitHub to ensure we have the latest versions
|
||||
sync_config_files() {
|
||||
log_info "Syncing config files from GitHub..."
|
||||
|
||||
# Backup and update docker-compose.prod.yml
|
||||
if curl -fsSL "${GITHUB_RAW_BASE}/docker-compose.prod.yml" -o "${COMPOSE_FILE}.new"; then
|
||||
cp "${COMPOSE_FILE}" "${COMPOSE_FILE}.bak"
|
||||
mv "${COMPOSE_FILE}.new" "${COMPOSE_FILE}"
|
||||
log_info "Updated docker-compose.prod.yml"
|
||||
else
|
||||
log_warn "Failed to fetch docker-compose.prod.yml, using existing"
|
||||
fi
|
||||
|
||||
# Backup and update nginx.conf, preserving current active instance
|
||||
if curl -fsSL "${GITHUB_RAW_BASE}/nginx/nginx.conf" -o "${NGINX_CONF}.new"; then
|
||||
# Preserve the current eagle_backend setting (which instance is active)
|
||||
local current_backend
|
||||
current_backend=$(grep -o 'default "eagle-[a-z]*:40032"' "${NGINX_CONF}" | head -1 || echo 'default "eagle-blue:40032"')
|
||||
|
||||
cp "${NGINX_CONF}" "${NGINX_CONF}.bak"
|
||||
# Update the new config with the current active instance
|
||||
sed -i "s/default \"eagle-blue:40032\"/${current_backend}/g" "${NGINX_CONF}.new"
|
||||
mv "${NGINX_CONF}.new" "${NGINX_CONF}"
|
||||
log_info "Updated nginx.conf (preserved active: ${current_backend})"
|
||||
else
|
||||
log_warn "Failed to fetch nginx.conf, using existing"
|
||||
fi
|
||||
}
|
||||
|
||||
# Determine which instance is currently active
|
||||
get_active_instance() {
|
||||
if grep -q "eagle-blue:40032" "${NGINX_CONF}"; then
|
||||
@@ -119,6 +151,9 @@ main() {
|
||||
|
||||
cd "${APP_DIR}"
|
||||
|
||||
# Sync config files from GitHub before deployment
|
||||
sync_config_files
|
||||
|
||||
# Determine current active instance
|
||||
local active=$(get_active_instance)
|
||||
local staging
|
||||
@@ -137,12 +172,12 @@ main() {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start staging instance with new image
|
||||
# Start staging instance with new image (and its jfr-sidecar)
|
||||
log_info "Starting eagle-${staging} with new image..."
|
||||
if [ "$staging" = "green" ]; then
|
||||
EAGLE_IMAGE_NEW="${new_image}" docker compose -f "${COMPOSE_FILE}" --profile blue-green up -d eagle-green
|
||||
EAGLE_IMAGE_NEW="${new_image}" docker compose -f "${COMPOSE_FILE}" --profile blue-green up -d eagle-green jfr-sidecar-green
|
||||
else
|
||||
EAGLE_IMAGE="${new_image}" docker compose -f "${COMPOSE_FILE}" up -d eagle-blue
|
||||
EAGLE_IMAGE="${new_image}" docker compose -f "${COMPOSE_FILE}" up -d eagle-blue jfr-sidecar
|
||||
fi
|
||||
|
||||
# Wait for staging to be healthy
|
||||
@@ -178,6 +213,21 @@ main() {
|
||||
log_info "Stopping eagle-${active} (flushing state to storage)..."
|
||||
docker compose -f "${COMPOSE_FILE}" stop "eagle-${active}"
|
||||
|
||||
# Backup games.e0es to S3 before switching traffic
|
||||
# This creates a point-in-time backup we can recover from if something goes wrong
|
||||
local backup_timestamp
|
||||
backup_timestamp=$(date +%Y%m%d_%H%M%S)
|
||||
log_info "Creating S3 backup of games.e0es (backup_${backup_timestamp})..."
|
||||
if command -v s3cmd &> /dev/null; then
|
||||
if s3cmd put "${APP_DIR}/saves/games.e0es" "s3://eagle0/eagle/save/backups/games.e0es.${backup_timestamp}" 2>/dev/null; then
|
||||
log_info "Backup created: s3://eagle0/eagle/save/backups/games.e0es.${backup_timestamp}"
|
||||
else
|
||||
log_warn "S3 backup failed (s3cmd put), continuing deployment"
|
||||
fi
|
||||
else
|
||||
log_warn "s3cmd not found, skipping S3 backup"
|
||||
fi
|
||||
|
||||
# Note: No need to explicitly reload games - Eagle uses lazy loading.
|
||||
# Games are loaded on-demand when users reconnect after nginx switches traffic.
|
||||
# This ensures games are always loaded from the freshest storage state.
|
||||
@@ -194,24 +244,35 @@ main() {
|
||||
log_info "Reloading nginx..."
|
||||
docker compose -f "${COMPOSE_FILE}" exec nginx nginx -s reload
|
||||
|
||||
# Clean up old instance
|
||||
# Clean up old instance and its jfr-sidecar
|
||||
log_info "Removing old eagle-${active} container..."
|
||||
docker compose -f "${COMPOSE_FILE}" rm -f "eagle-${active}"
|
||||
|
||||
# Update the staging instance's restart policy and image var
|
||||
# For blue, we need to update EAGLE_IMAGE; for green, update EAGLE_IMAGE_NEW
|
||||
if [ "$staging" = "blue" ]; then
|
||||
log_info "Updating EAGLE_IMAGE to ${new_image} for future restarts"
|
||||
# User should update their .env file
|
||||
if [ "$active" = "green" ]; then
|
||||
docker compose -f "${COMPOSE_FILE}" rm -f "jfr-sidecar-green" 2>/dev/null || true
|
||||
else
|
||||
log_info "Green is now active. Consider switching to blue on next deployment."
|
||||
docker compose -f "${COMPOSE_FILE}" rm -f "jfr-sidecar" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Update .env with new EAGLE_ADDR and JFR_SIDECAR_ADDR for admin service
|
||||
local env_file="${APP_DIR}/.env"
|
||||
if [ "$staging" = "green" ]; then
|
||||
log_info "Updating .env for green instance..."
|
||||
sed -i.bak '/^EAGLE_ADDR=/d; /^JFR_SIDECAR_ADDR=/d' "${env_file}" 2>/dev/null || true
|
||||
echo "EAGLE_ADDR=eagle-green:40032" >> "${env_file}"
|
||||
echo "JFR_SIDECAR_ADDR=jfr-sidecar-green:8081" >> "${env_file}"
|
||||
else
|
||||
log_info "Updating .env for blue instance..."
|
||||
sed -i.bak '/^EAGLE_ADDR=/d; /^JFR_SIDECAR_ADDR=/d' "${env_file}" 2>/dev/null || true
|
||||
echo "EAGLE_ADDR=eagle-blue:40032" >> "${env_file}"
|
||||
echo "JFR_SIDECAR_ADDR=jfr-sidecar:8081" >> "${env_file}"
|
||||
fi
|
||||
|
||||
# Restart admin to pick up new EAGLE_ADDR and JFR_SIDECAR_ADDR
|
||||
log_info "Restarting admin service..."
|
||||
docker compose -f "${COMPOSE_FILE}" up -d admin
|
||||
|
||||
log_info "Deployment complete!"
|
||||
log_info "Active instance: eagle-${staging}"
|
||||
log_info ""
|
||||
log_info "Note: Update your .env file with EAGLE_IMAGE=${new_image}"
|
||||
log_info " if you want future 'docker compose up' to use this version."
|
||||
}
|
||||
|
||||
# Check for required tools
|
||||
|
||||
Reference in New Issue
Block a user