Merge dev: v0.19.5~v0.19.6 (生成页慢速滚跳底根因修复 / CI retry 假绿色根因修复)
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m48s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m48s
- v0.19.5 (85aa024): 生成页慢速往上滚仍跳到底部 — 双层 anchor 叠加根因 CSS .contentArea 加 overflow-anchor: none 关掉浏览器自动 anchor + handleScroll 加 loadMoreInFlightRef 防 rAF 累加 - v0.19.6 (3f85825): CI deploy.yaml 6 处 retry 循环失败时正确 exit 1 根除 "for ... && break; done" 模式吞错误导致的 "假绿色钩" 误判 (v0.19.5 因此卡了 2 天没自动部署到测试服, 手动 patch 才上线) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
7267c0bce5
@ -49,45 +49,55 @@ jobs:
|
|||||||
id: build_backend
|
id: build_backend
|
||||||
run: |
|
run: |
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
echo "Build backend attempt $attempt/3..."
|
echo "Build backend attempt $attempt/3..."
|
||||||
DOCKER_BUILDKIT=0 docker build \
|
DOCKER_BUILDKIT=0 docker build \
|
||||||
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }} \
|
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }} \
|
||||||
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:latest \
|
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:latest \
|
||||||
./backend 2>&1 | tee /tmp/build.log && break
|
./backend 2>&1 | tee /tmp/build.log && { ok=1; break; }
|
||||||
echo "Attempt $attempt failed, retrying in 10s..." && sleep 10
|
echo "Attempt $attempt failed, retrying in 10s..." && sleep 10
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: backend build failed after 3 attempts"; exit 1; }
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }} && \
|
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:${{ env.IMAGE_TAG }} && \
|
||||||
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:latest && break
|
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-backend:latest && { ok=1; break; }
|
||||||
echo "Push attempt $attempt failed, retrying in 10s..." && sleep 10
|
echo "Push attempt $attempt failed, retrying in 10s..." && sleep 10
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: backend push failed after 3 attempts"; exit 1; }
|
||||||
|
|
||||||
- name: Build and Push Web
|
- name: Build and Push Web
|
||||||
id: build_web
|
id: build_web
|
||||||
run: |
|
run: |
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
echo "Build web attempt $attempt/3..."
|
echo "Build web attempt $attempt/3..."
|
||||||
DOCKER_BUILDKIT=0 docker build \
|
DOCKER_BUILDKIT=0 docker build \
|
||||||
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }} \
|
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }} \
|
||||||
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:latest \
|
--tag ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:latest \
|
||||||
./web 2>&1 | tee -a /tmp/build.log && break
|
./web 2>&1 | tee -a /tmp/build.log && { ok=1; break; }
|
||||||
echo "Attempt $attempt failed, retrying in 10s..." && sleep 10
|
echo "Attempt $attempt failed, retrying in 10s..." && sleep 10
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: web build failed after 3 attempts"; exit 1; }
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }} && \
|
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:${{ env.IMAGE_TAG }} && \
|
||||||
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:latest && break
|
docker push ${{ env.CR_SERVER_ACTIVE }}/${{ env.CR_ORG }}/video-web:latest && { ok=1; break; }
|
||||||
echo "Push attempt $attempt failed, retrying in 10s..." && sleep 10
|
echo "Push attempt $attempt failed, retrying in 10s..." && sleep 10
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: web push failed after 3 attempts"; exit 1; }
|
||||||
|
|
||||||
- name: Setup Kubectl
|
- name: Setup Kubectl
|
||||||
run: |
|
run: |
|
||||||
if ! command -v kubectl &>/dev/null; then
|
if ! command -v kubectl &>/dev/null; then
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3; do
|
for attempt in 1 2 3; do
|
||||||
curl -LO "https://files.m.daocloud.io/dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl" && break
|
curl -LO "https://files.m.daocloud.io/dl.k8s.io/release/v1.28.0/bin/linux/amd64/kubectl" && { ok=1; break; }
|
||||||
echo "Download attempt $attempt failed, retrying in 5s..." && sleep 5
|
echo "Download attempt $attempt failed, retrying in 5s..." && sleep 5
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: kubectl download failed after 3 attempts"; exit 1; }
|
||||||
chmod +x kubectl && mv kubectl /usr/bin/kubectl
|
chmod +x kubectl && mv kubectl /usr/bin/kubectl
|
||||||
fi
|
fi
|
||||||
kubectl version --client
|
kubectl version --client
|
||||||
@ -135,6 +145,7 @@ jobs:
|
|||||||
# All kubectl operations with retry (K3s 内网连接可能抖动)
|
# All kubectl operations with retry (K3s 内网连接可能抖动)
|
||||||
export KUBECTL_TIMEOUT="--request-timeout=4s"
|
export KUBECTL_TIMEOUT="--request-timeout=4s"
|
||||||
|
|
||||||
|
ok=0
|
||||||
for attempt in 1 2 3 4 5; do
|
for attempt in 1 2 3 4 5; do
|
||||||
echo "Deploy attempt $attempt/5..."
|
echo "Deploy attempt $attempt/5..."
|
||||||
{
|
{
|
||||||
@ -169,10 +180,11 @@ jobs:
|
|||||||
kubectl $KUBECTL_TIMEOUT rollout restart deployment/video-backend
|
kubectl $KUBECTL_TIMEOUT rollout restart deployment/video-backend
|
||||||
kubectl $KUBECTL_TIMEOUT rollout restart deployment/celery-worker
|
kubectl $KUBECTL_TIMEOUT rollout restart deployment/celery-worker
|
||||||
kubectl $KUBECTL_TIMEOUT rollout restart deployment/video-web
|
kubectl $KUBECTL_TIMEOUT rollout restart deployment/video-web
|
||||||
} 2>&1 | tee /tmp/deploy.log && break
|
} 2>&1 | tee /tmp/deploy.log && { ok=1; break; }
|
||||||
echo "Attempt $attempt failed, retrying in 30s..."
|
echo "Attempt $attempt failed, retrying in 30s..."
|
||||||
sleep 30
|
sleep 30
|
||||||
done
|
done
|
||||||
|
[ $ok -eq 1 ] || { echo "ERROR: deploy to K3s failed after 5 attempts — check /tmp/deploy.log"; exit 1; }
|
||||||
|
|
||||||
# ===== Log Center: failure reporting =====
|
# ===== Log Center: failure reporting =====
|
||||||
- name: Report failure to Log Center
|
- name: Report failure to Log Center
|
||||||
|
|||||||
@ -17,6 +17,10 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
/* 关掉浏览器自动 scroll anchoring:往上加载历史时由 handleScroll 里的
|
||||||
|
anchor 逻辑统一管,避免浏览器默认的 anchor 与我们手动 +diff 叠加,
|
||||||
|
导致慢速滚动 / 慢拖滑动条时页面被推到最底部。 */
|
||||||
|
overflow-anchor: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emptyArea {
|
.emptyArea {
|
||||||
|
|||||||
@ -22,6 +22,9 @@ export function VideoGenerationPage() {
|
|||||||
const scrollRef = useRef<HTMLDivElement>(null);
|
const scrollRef = useRef<HTMLDivElement>(null);
|
||||||
const prevLastIdRef = useRef<string | null>(null);
|
const prevLastIdRef = useRef<string | null>(null);
|
||||||
const initialLoadRef = useRef(true);
|
const initialLoadRef = useRef(true);
|
||||||
|
// 防重入 flag:loadMore + anchor 期间,handleScroll 多次触发不再 schedule 多个 rAF,
|
||||||
|
// 避免 anchor 累加把页面推到底(慢速滚轮 / 慢拖滑动条场景)。
|
||||||
|
const loadMoreInFlightRef = useRef(false);
|
||||||
const savedScrollTop = useGenerationStore((s) => s.savedScrollTop);
|
const savedScrollTop = useGenerationStore((s) => s.savedScrollTop);
|
||||||
const saveScrollPosition = useGenerationStore((s) => s.saveScrollPosition);
|
const saveScrollPosition = useGenerationStore((s) => s.saveScrollPosition);
|
||||||
const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
|
const [detailTaskId, setDetailTaskId] = useState<string | null>(null);
|
||||||
@ -76,15 +79,20 @@ export function VideoGenerationPage() {
|
|||||||
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
||||||
setShowScrollBottom(distanceFromBottom > 300);
|
setShowScrollBottom(distanceFromBottom > 300);
|
||||||
|
|
||||||
// Trigger loadMore when scrolled within 100px of the top
|
// Trigger loadMore when scrolled within 100px of the top.
|
||||||
if (scrollRef.current.scrollTop < 100) {
|
// ref flag 守卫:只有第一次进入分支时才 schedule loadMore + anchor;
|
||||||
|
// 后续 handleScroll(慢速操作下持续触发)直接跳过,避免多次 rAF 排队累加 +diff。
|
||||||
|
if (scrollRef.current.scrollTop < 100 && !loadMoreInFlightRef.current) {
|
||||||
|
loadMoreInFlightRef.current = true;
|
||||||
const el = scrollRef.current;
|
const el = scrollRef.current;
|
||||||
const prevHeight = el.scrollHeight;
|
const prevHeight = el.scrollHeight;
|
||||||
loadMore().then(() => {
|
loadMore().then(() => {
|
||||||
// After older tasks are prepended, restore visual position so user doesn't jump
|
// After older tasks are prepended, restore visual position so user doesn't jump.
|
||||||
|
// CSS overflow-anchor: none 已禁用浏览器自动 anchor,由这里独立完成。
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const diff = el.scrollHeight - prevHeight;
|
const diff = el.scrollHeight - prevHeight;
|
||||||
if (diff > 0) el.scrollTop += diff;
|
if (diff > 0) el.scrollTop += diff;
|
||||||
|
loadMoreInFlightRef.current = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user