fix(core,installer): dev vendor 설치본의 코어 업데이트 중단 수정 — stale 패키지 매니페스트 3계층
Laravel PackageManifest 는 bootstrap/cache/packages.php 가 있으면 stale 여부를 검사하지 않고 그대로 읽어 등재된 provider 를 new 한다. 코어 업데이트는 Step 6/8 에서 vendor 를 --no-dev 로 교체하지만 그 파일은 Step 11 까지 이전 설치본의 것이 남으므로, 옵션 없는 `composer install` 로 깔린 사이트에서는 Step 10 spawn 자식이 새 vendor 에 없는 provider 를 찾다 부팅 단계에서 죽는다. 부팅 전이라 앱 로그에 흔적이 없고 부모에게는 자식의 비정상 종료로만 보여, 운영자에게는 「Class ... not found」 와 수동 재개 안내만 남는다. (sir.kr 커뮤니티 제보, 7.0.9 → 7.0.10) 3계층으로 막는다. 1. 부모 — spawn 직전 PackageManifestCacheHelper::clear 2. 자식 — bootstrap/app.php 가 G7_UPDATE_IN_PROGRESS 를 보고 스스로 정리한다. 이미 배포된 7.0.9·7.0.10 부모는 고칠 수 없으므로 그 아래에서 도는 신버전 자식의 유일한 방어다. App\ 클래스를 참조하지 않고 실패는 무시한다. 3. 범위 — CoreVersionChecker 의 env APP_VERSION 우선을 CoreUpdateContext 트리 안으로 축소한다. 업데이트 전에 뜬 artisan serve·큐 워커가 옛 값을 물고 확장을 incompatible_core 로 끄던 경로를 닫는다(관리자 템플릿이 대상이면 복구 UI 자체에 도달할 수 없다). 업데이트 트리 판정은 App\Support\CoreUpdateContext 가 단독 소유하고 CoreServiceProvider::isCoreUpdateInProgress 는 위임으로 남는다. bootstrap/app.php 의 복제본은 부팅 전이라 불가피한 예외이며, 두 조건의 동형성을 테스트가 단언한다. 실측 중 드러난 결함 2건을 함께 고쳤다. - ConfigCacheHelper::withPreservedContainer 가 파사드 애플리케이션을 되돌리지 않아 Step 11 이 `Target class [command.tinker] does not exist` 로 실패·롤백했다. - updateVersionInEnv 가 프로세스 환경을 갱신하지 않아 config 캐시에 이전 버전이 구워졌다 (Laravel env 저장소가 불변이라 재부팅으로도 덮이지 않는다). 인스톨러는 재사용 vendor 의 개발용 패키지를 installed.json 으로 감지해 설치 환경 확인 카드·설치 로그로 알리되 설치를 차단하지 않고( 결정 D1), 재사용 경로에서도 컴파일 캐시를 정리한다. 실행되는 명령만이 아니라 실패 시 안내하는 수동 명령까지 --no-dev 로 맞췄다. 코어 업데이트 완료·핸드오프·단독 재개 사후 단계에서 queue:restart 신호를 보낸다(D3). 코어 7.0.10 → 7.0.11.
This commit is contained in:
1 parent
21177c8e17
commit
ffab451b4a
42 files changed
+2660
-82
No files matched your search
@@ -23,6 +23,7 @@ use App\Extension\Vendor\VendorInstallContext;
|
||||
use App\Extension\Vendor\VendorInstallResult;
|
||||
use App\Extension\Vendor\VendorMode;
|
||||
use App\Extension\Vendor\VendorResolver;
|
||||
use App\Support\PackageManifestCacheHelper;
|
||||
use Database\Seeders\IdentityMessageDefinitionSeeder;
|
||||
use Database\Seeders\IdentityPolicySeeder;
|
||||
use Database\Seeders\NotificationDefinitionSeeder;
|
||||
@@ -1835,6 +1836,20 @@ class CoreUpdateService
|
||||
}
|
||||
|
||||
File::put($envPath, $content);
|
||||
|
||||
// 프로세스 환경도 함께 갱신한다.
|
||||
//
|
||||
// 부모가 config 캐시 **없이** 부팅했다면 Dotenv 가 `.env` 를 읽어 `$_ENV['APP_VERSION']` 에
|
||||
// 이전 버전을 채워 두었고, Laravel 의 env 저장소는 불변(immutable)이라 뒤이어 부팅하는
|
||||
// 프로세스가 `.env` 를 다시 읽어도 그 값을 덮지 않는다. 그래서 Step 11 의 `config:cache` 가
|
||||
// 굽는 `bootstrap/cache/config.php` 에 **이전 버전**이 박제되고, 이후 모든 웹 요청이 옛 버전으로
|
||||
// 판정한다 — 새 코어를 요구하는 확장이 `incompatible_core` 로 꺼지는 경로다
|
||||
// (2026-09-07 실측: `config:clear` 후 7.0.10 → 7.0.11 업데이트가 config 캐시에 7.0.10 을 구웠다).
|
||||
//
|
||||
// 캐시 부팅에서는 Dotenv 가 아예 돌지 않아 이 값이 비어 있을 수 있으므로 세 채널 모두 세운다.
|
||||
$_ENV['APP_VERSION'] = $version;
|
||||
$_SERVER['APP_VERSION'] = $version;
|
||||
putenv('APP_VERSION='.$version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2074,7 +2089,8 @@ class CoreUpdateService
|
||||
* 모든 캐시를 초기화하고 패키지 목록을 재생성합니다.
|
||||
*
|
||||
* vendor 교체 후 bootstrap/cache의 컴파일 캐시가 stale 상태일 수 있으므로
|
||||
* services.php/packages.php 삭제 후 package:discover로 재생성합니다.
|
||||
* services.php/packages.php 삭제 후 package:discover로 재생성합니다
|
||||
* (`PackageManifestCacheHelper::rebuild()` — spawn 직전 선정리와 같은 삭제 로직을 공유).
|
||||
* 이는 composer install의 post-autoload-dump 후속 작업(clearCompiled + package:discover)을 재현합니다.
|
||||
*/
|
||||
public function clearAllCaches(): void
|
||||
@@ -2085,14 +2101,10 @@ class CoreUpdateService
|
||||
Artisan::call('route:clear');
|
||||
Artisan::call('view:clear');
|
||||
|
||||
// 2. 컴파일 캐시 삭제 (composer postAutoloadDump → clearCompiled 재현)
|
||||
// services.php, packages.php가 교체 전 vendor를 참조할 수 있음
|
||||
$app = app();
|
||||
@unlink($app->getCachedServicesPath());
|
||||
@unlink($app->getCachedPackagesPath());
|
||||
|
||||
// 3. 현재 vendor 기반으로 packages.php 재생성
|
||||
Artisan::call('package:discover');
|
||||
// 2~3. 컴파일 캐시 삭제 후 현재 vendor 기반으로 재생성
|
||||
// (composer postAutoloadDump → clearCompiled + package:discover 재현).
|
||||
// services.php, packages.php 가 교체 전 vendor 를 참조할 수 있다.
|
||||
PackageManifestCacheHelper::rebuild();
|
||||
|
||||
// 4. 확장 오토로드 재생성 (코어 업데이트로 _bundled 변경 가능)
|
||||
Artisan::call('extension:update-autoload');
|
||||
@@ -2108,6 +2120,29 @@ class CoreUpdateService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 상주 중인 큐 워커에 정상 종료 후 재시작 신호를 보냅니다.
|
||||
*
|
||||
* 큐 워커는 부팅이 한 번뿐이라 코어 코드·config·확장 목록을 기동 시점 상태로 물고 있다.
|
||||
* 코어 업데이트가 파일을 전부 교체해도 워커는 옛 코드로 잡을 계속 처리하며, 그 사실이
|
||||
* 오류로 드러나지 않는다 — 운영자가 워커를 손수 재시작할 때까지 조용히 어긋난 채 돈다.
|
||||
*
|
||||
* 캐시가 새 코드 기준으로 정리된 뒤(`clearAllCaches()` 직후) 호출해야 워커가 새 캐시로
|
||||
* 재기동한다. 신호 전송 실패는 업데이트 결과를 되돌리지 않는다 (경고 로깅 후 계속).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function signalQueueRestart(): void
|
||||
{
|
||||
try {
|
||||
Artisan::call('queue:restart');
|
||||
} catch (\Throwable $e) {
|
||||
Log::channel('upgrade')->warning('queue:restart 실행 실패 (업데이트는 계속 진행)', [
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 코어 업그레이드 컨텍스트의 번들 확장 업데이트 감지.
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user