From 4c430112221e8f701b9abcd44c7efec74c6b0b69 Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Wed, 7 Oct 2026 15:00:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8F=91=E5=B8=83=E6=9B=BF=E6=8D=A2?= =?UTF-8?q?=E5=AE=B9=E5=99=A8=E5=89=8D=E7=AD=89=E5=BE=85=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/activate-incremental-release.sh | 8 +++ deploy/activate-release.sh | 8 +++ .../Deployment/DeploymentSyncLockTest.php | 57 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/Unit/Deployment/DeploymentSyncLockTest.php diff --git a/deploy/activate-incremental-release.sh b/deploy/activate-incremental-release.sh index 038b0f15..08949bad 100644 --- a/deploy/activate-incremental-release.sh +++ b/deploy/activate-incremental-release.sh @@ -65,6 +65,14 @@ if ! flock -n 9; then exit 1 fi +# 容器替换会终止其中的同步进程;与生产刷新任务共享同一把锁。 +exec 8>/run/caiwu-upstream-sync.lock +echo "Waiting for active upstream synchronization before replacing the application container" +if ! flock -w 1800 8; then + echo "Upstream synchronization is still running; application container was not replaced" >&2 + exit 1 +fi + PREVIOUS_IMAGE="$(docker inspect caiwu_app --format '{{.Config.Image}}' 2>/dev/null || true)" PREVIOUS_SHA="$(cat "$REMOTE_DIR/.deployed-sha" 2>/dev/null || true)" diff --git a/deploy/activate-release.sh b/deploy/activate-release.sh index 6260783d..84a97c2f 100644 --- a/deploy/activate-release.sh +++ b/deploy/activate-release.sh @@ -69,6 +69,14 @@ if ! flock -n 9; then exit 1 fi +# 容器替换会终止其中的同步进程;与生产刷新任务共享同一把锁。 +exec 8>/run/caiwu-upstream-sync.lock +echo "Waiting for active upstream synchronization before replacing the application container" +if ! flock -w 1800 8; then + echo "Upstream synchronization is still running; application container was not replaced" >&2 + exit 1 +fi + PREVIOUS_IMAGE="$(docker inspect caiwu_app --format '{{.Config.Image}}' 2>/dev/null || true)" PREVIOUS_SHA="$(cat "$REMOTE_DIR/.deployed-sha" 2>/dev/null || true)" diff --git a/tests/Unit/Deployment/DeploymentSyncLockTest.php b/tests/Unit/Deployment/DeploymentSyncLockTest.php new file mode 100644 index 00000000..2e6b71f4 --- /dev/null +++ b/tests/Unit/Deployment/DeploymentSyncLockTest.php @@ -0,0 +1,57 @@ +/run/caiwu-upstream-sync.lock'); + $end = strpos($contents, 'PREVIOUS_IMAGE=', $start ?: 0); + $this->assertNotFalse($start, $script); + $this->assertNotFalse($end, $script); + $this->assertLessThan(strpos($contents, 'docker compose -f compose.jiangling.yml up'), $end); + $guard = substr($contents, $start, $end - $start); + + $directory = sys_get_temp_dir() . '/caiwu-deploy-lock-' . bin2hex(random_bytes(8)); + mkdir($directory, 0700); + $holder = new Process(['sh', '-c', 'exec 8>"$1"; flock 8; touch "$2"; sleep 2', 'holder', $directory . '/sync.lock', $directory . '/held']); + try { + $holder->start(); + $deadline = microtime(true) + 3; + while (! file_exists($directory . '/held') && microtime(true) < $deadline) { + usleep(10000); + } + $this->assertFileExists($directory . '/held'); + $guard = str_replace('/run/caiwu-upstream-sync.lock', $directory . '/sync.lock', $guard); + $guard .= "touch '$directory/activated'\n"; + + $timeout = new Process(['sh', '-c', str_replace('-w 1800', '-w 0', $guard)]); + $timeout->run(); + $this->assertSame(1, $timeout->getExitCode()); + $this->assertStringContainsString('application container was not replaced', $timeout->getErrorOutput()); + $this->assertFileDoesNotExist($directory . '/activated'); + + $release = new Process(['sh', '-c', $guard]); + $release->start(); + usleep(100000); + $this->assertTrue($release->isRunning()); + $this->assertFileDoesNotExist($directory . '/activated'); + $release->wait(); + $this->assertTrue($release->isSuccessful(), $release->getErrorOutput()); + $this->assertFileExists($directory . '/activated'); + } finally { + $holder->stop(); + foreach (glob($directory . '/*') as $file) { + unlink($file); + } + rmdir($directory); + } + } + } +} -- 2.47.2