fix(extension): 확장 토글 시 config 캐시 재생성을 동기 실행 (큐 지연 제거)

ExtensionConfigCacheListener 가 config 캐시 재생성을 큐로 디스패치해,
워커 미가동 환경·CLI 커맨드(plugin:deactivate 등)에서 재생성이 지연/누락되던
결함을 수정한다. 훅 Action 리스너의 기본 등록 정책이 큐 디스패치이므로,
getSubscribedHooks 각 훅에 'sync' => true 를 추가해 동기 실행한다.

- 회귀 테스트 test_all_hooks_are_synchronous 추가
- docs/backend/service-provider.md 에 sync 요구사항 명문화
- 2브라우저(Chrome MCP + Playwright MCP) 회귀 검증 중 발견
This commit is contained in:
HeuJung committed 2026-07-03 18:40:19 +09:00
1 parent c08dae7cb0
commit 710f8e9135
3 files changed
+23

No files matched your search

@@ -46,6 +46,12 @@ class ExtensionConfigCacheListener implements HookListenerInterface
$hooks[$hookName] = [
'method' => 'onExtensionToggled',
'priority' => 30,
// config 캐시 재생성은 인프라 작업이라 큐로 미루면 안 된다. Action 훅의 기본
// 등록은 큐 디스패치(HookListenerRegistrar) 이므로, sync 를 명시하지 않으면
// 워커 미가동 환경에서 config:cache 가 재생성되지 않는다. 또한 확장 토글은
// CLI 커맨드(plugin:deactivate 등)로도 수행되며, 커맨드 프로세스는 실행 후
// 즉시 종료되어 큐에 쌓인 작업을 처리할 주체가 없다. 반드시 동기 실행한다.
'sync' => true,
];
}
+2
View File
@@ -456,6 +456,8 @@ config 소스(`config/*.php`, `.env`, `storage/app/settings/*.json`, 활성 확
| 확장 설치/삭제/업데이트 | `ExtensionManager::updateComposerAutoload()` (오토로드·훅 캐시와 동일 생명주기) |
| 확장 활성화/비활성화 | `ExtensionConfigCacheListener` (`core.*.activated` / `core.*.after_deactivate` 훅 구독) |
`ExtensionConfigCacheListener` 의 구독 훅은 `getSubscribedHooks()` 에서 `'sync' => true` 로 선언한다. 훅 Action 리스너의 기본 등록 정책은 큐 디스패치(`HookListenerRegistrar`)인데, config 캐시 재생성을 큐로 미루면 (1) 워커 미가동 환경에서 영영 재생성되지 않고, (2) 확장 토글을 수행하는 CLI 커맨드(`plugin:deactivate` 등)는 실행 후 프로세스가 종료되어 큐 작업을 처리할 주체가 없다. config 캐시 재생성은 인프라 부수효과이므로 반드시 동기 실행한다. 회귀 방지 테스트: `ExtensionConfigCacheListenerTest::test_all_hooks_are_synchronous`.
**확장별 개별 환경설정 저장(board/ecommerce/plugin SettingsService)은 재생성 대상이 아니다.** 확장 설정은 `config/*.php` 가 아니라 settings JSON 에 저장되고, 매 요청 `CoreServiceProvider::boot` 의 `loadModule/PluginSettingsToConfig` 가 런타임 `Config::set('g7_settings.*', 최신값)` 으로 config 캐시에 박제된 값을 덮어쓴다. 따라서 값 stale 이 없고(즉시 반영), config 캐시를 clear 하지도 않으므로(성능 손실 없음) 재생성이 실효가 없다.
---
@@ -66,4 +66,19 @@ class ExtensionConfigCacheListenerTest extends TestCase
$this->assertArrayHasKey('priority', $config);
}
}
public function test_all_hooks_are_synchronous(): void
{
// config 캐시 재생성은 인프라 작업이라 큐로 미루면 안 된다. Action 훅의 기본 등록은
// 큐 디스패치(HookListenerRegistrar::applySubscribedHooks) 이므로, sync 플래그가
// 없으면 워커 미가동 환경(대부분의 소규모 사이트)에서 config:cache 가 영영 재생성되지
// 않는다. 게다가 CLI 커맨드(plugin:deactivate 등)는 실행 후 프로세스가 종료되어 큐에
// 쌓인 작업을 처리할 주체가 없다. 모든 구독 훅은 sync=true 여야 한다.
$hooks = ExtensionConfigCacheListener::getSubscribedHooks();
foreach ($hooks as $hookName => $config) {
$this->assertArrayHasKey('sync', $config, "{$hookName} 은 sync 플래그가 있어야 합니다 (config 캐시 재생성은 동기 실행 필수).");
$this->assertTrue($config['sync'], "{$hookName} 은 sync=true 여야 합니다 — 큐로 미루면 워커 미가동 시 config 캐시가 재생성되지 않습니다.");
}
}
}