fix: socket.io Invalid origin + dev mode PYTHONPATH + sync-assets improvements

- compose.local-origin.yaml: patch nginx to forward Host: $http_host (not
  websocket:9000) in /socket.io block so authenticate.js host==origin check passes
- compose.picking-dev.yaml: add PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app
  to all services so picking_app is importable without pip install in dev mode
- images/custom/Containerfile: fix Frappe bug — add missing return after
  next(new Error("Invalid namespace")) in socket.io authenticate middleware
- Makefile: recreate-frontend target; sync-assets clears cache before copy and
  uses --force-recreate instead of restart; dev-up force-recreates frontend to
  flush stale backend IPs from nginx cache

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
abounoone 2026-03-20 10:21:20 +00:00
parent 21a39e88e8
commit 4e2516cdd7
4 changed files with 41 additions and 17 deletions

View file

@ -30,7 +30,7 @@ DIST_APPS := frappe erpnext hrms lms print_designer webshop education lending ne
COMPOSE_PROJECT := $(notdir $(CURDIR))
ASSETS_VOL := $(COMPOSE_PROJECT)_assets
.PHONY: help build up down restart update migrate assets sync-assets backup logs ps shell
.PHONY: help build up down restart recreate-frontend update migrate assets sync-assets backup logs ps shell
# ── Справка ─────────────────────────────────────────────────
help:
@ -51,7 +51,7 @@ help:
@echo " make update — rebuild образа + up + migrate + assets"
@echo " make migrate — bench migrate на сайте $(SITE)"
@echo " make assets — пересобрать JS/CSS бандлы и синхронизировать"
@echo " make sync-assets — только скопировать dist в assets volume (без rebuild)"
@echo " make sync-assets — скопировать dist в assets volume (очищает кэш, затем копирует)"
@echo ""
@echo " Обслуживание:"
@echo " make backup — создать резервную копию сайта"
@ -81,6 +81,9 @@ down:
restart:
docker compose $(COMPOSE_OVERRIDES) restart backend frontend websocket
recreate-frontend:
docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend
ps:
docker compose $(COMPOSE_OVERRIDES) ps
@ -113,6 +116,14 @@ assets:
# bench build пишет файлы в overlay-слой backend-контейнера, а nginx
# читает из именованного тома. Эта цель копирует dist-файлы туда.
sync-assets:
@echo "→ Сброс кэша перед синхронизацией (предотвращает пересоздание симлинков)..."
@docker compose $(COMPOSE_OVERRIDES) exec backend \
bench --site $(SITE) clear-cache
@docker compose $(COMPOSE_OVERRIDES) exec backend bash -c \
". /home/frappe/frappe-bench/env/bin/activate && \
python -c \"import redis; r=redis.Redis(host='redis-cache'); \
deleted=r.delete('assets_json'); \
print('assets_json удалён из Redis' if deleted else 'assets_json отсутствовал')\""
@echo "→ Синхронизация dist-файлов в $(ASSETS_VOL)..."
@TMPDIR=$$(mktemp -d) && \
trap "rm -rf $$TMPDIR" EXIT && \
@ -135,20 +146,13 @@ sync-assets:
for d in /src/*-dist; do \
[ -d "$$d" ] || continue; \
app=$$(basename "$$d" -dist); \
rm -f /assets/$$app; \
mkdir -p /assets/$$app/dist; \
cp -rf "$$d/." /assets/$$app/dist/; \
if [ -L "/assets/$$app" ]; then rm -f "/assets/$$app"; \
elif [ -d "/assets/$$app" ]; then rm -rf "/assets/$$app"; fi; \
mkdir -p "/assets/$$app/dist"; \
cp -rf "$$d/." "/assets/$$app/dist/"; \
done \
'
@echo "→ Сброс кэша assets_json в Redis..."
@docker compose $(COMPOSE_OVERRIDES) exec backend \
bench --site $(SITE) clear-cache
@docker compose $(COMPOSE_OVERRIDES) exec backend bash -c \
". /home/frappe/frappe-bench/env/bin/activate && \
python -c \"import redis; r=redis.Redis(host='redis-cache'); \
deleted=r.delete('assets_json'); \
print('assets_json удалён из Redis' if deleted else 'assets_json отсутствовал')\""
@docker compose $(COMPOSE_OVERRIDES) restart frontend
@docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend
@echo "✓ Синхронизация завершена"
# ── Резервная копия ──────────────────────────────────────────
@ -164,8 +168,8 @@ backup:
dev-up:
docker compose $(COMPOSE_DEV) up -d --no-deps --force-recreate \
backend websocket queue-short queue-long scheduler
@echo "→ Перезапуск frontend (обновление IP backend в nginx)..."
docker compose $(COMPOSE_OVERRIDES) restart frontend
@echo "→ Пересоздаём frontend (сброс кешированных IP backend)..."
docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend
@echo "✓ Dev-режим активен. Исходники: /home/mkr/picking_app"
@echo " Страница: http://localhost:8090/app/picking-mobile"

View file

@ -133,7 +133,11 @@ RUN export APP_INSTALL_ARGS="" && \
/home/frappe/frappe-bench && \
cd /home/frappe/frappe-bench && \
echo "{}" > sites/common_site_config.json && \
find apps -mindepth 1 -path "*/.git" | xargs rm -fr
find apps -mindepth 1 -path "*/.git" | xargs rm -fr && \
# Fix: Frappe bug — missing return after invalid namespace check in socket.io authenticate.js
# Without this, next() is called twice causing "Invalid origin" false positives
sed -i '/next(new Error("Invalid namespace"))/a\\t\treturn;' \
/home/frappe/frappe-bench/apps/frappe/realtime/middlewares/authenticate.js
FROM base AS backend

View file

@ -14,5 +14,11 @@ services:
sleep 1
sed -i 's|proxy_set_header Origin .*|proxy_set_header Origin $$http_origin;|' \
/etc/nginx/conf.d/frappe.conf
sed -i '/location \/socket\.io/,/proxy_pass/{s|proxy_set_header Host .*|proxy_set_header Host $$http_host;|}' \
/etc/nginx/conf.d/frappe.conf
sed -i 's|listen 8080;|listen 8080;\n\tresolver 127.0.0.11 valid=30s;|' \
/etc/nginx/conf.d/frappe.conf
sed -i 's|proxy_pass http://socketio-server;|set $$sock websocket:9000;\n\t\tproxy_pass http://$$sock;|' \
/etc/nginx/conf.d/frappe.conf
nginx -s reload
wait $$NGINX_PID

View file

@ -2,19 +2,29 @@ services:
backend:
volumes:
- /home/mkr/picking_app:/home/frappe/frappe-bench/apps/picking_app/picking_app:ro
environment:
- PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app
websocket:
volumes:
- /home/mkr/picking_app:/home/frappe/frappe-bench/apps/picking_app/picking_app:ro
environment:
- PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app
queue-short:
volumes:
- /home/mkr/picking_app:/home/frappe/frappe-bench/apps/picking_app/picking_app:ro
environment:
- PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app
queue-long:
volumes:
- /home/mkr/picking_app:/home/frappe/frappe-bench/apps/picking_app/picking_app:ro
environment:
- PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app
scheduler:
volumes:
- /home/mkr/picking_app:/home/frappe/frappe-bench/apps/picking_app/picking_app:ro
environment:
- PYTHONPATH=/home/frappe/frappe-bench/apps/picking_app