feat(seo): 사이트맵 안전 서빙·잡 견고화·분할 설정 + 캐시 설정 정합
봇 요청 스레드의 동기 생성을 제거하고 디스크 스트리밍 서빙으로 전환했다. 신선도가 만료되면 생성 잡만 예약하고 기존 세트(stale) 또는 503+Retry-After 로 응답해, 대용량에서 봇 요청이 OOM/타임아웃을 유발하던 경로를 끊었다. - 잡: ShouldBeUnique(고정 uniqueId)+uniqueFor+retryUntil, timeout 300→1800, backoff - 컨트롤러: 인덱스 stale/503 분기 + 자식 라우트(.xml/.xml.gz 동일 액션) - 스케줄 withoutOverlapping, 관리자 재생성 큐 이관 - 설정 4키(분할 기준·압축·stale 서빙·수집기 상한) + 고급탭 Sitemap 캐시 짝 - SitemapManager 응답 메시지 다국어화 설정 저장 테스트가 실제 설정 파일(사이트명/언어 포함)을 덮어쓰던 사전결함을 TestCase 전역 격리로 차단하고, 두 탭이 같은 다국어 키를 공유해 한쪽에 틀린 한도를 안내하던 사전결함을 키 분리로 해소했다.
This commit is contained in:
1 parent
21f666e4b5
commit
1c99547bc1
71 files changed
+3767
-2472
No files matched your search
@@ -220,6 +220,11 @@ class SaveSettingsRequest extends FormRequest
|
||||
'seo.cache_ttl' => ['nullable', 'integer', 'min:60', 'max:86400'],
|
||||
'seo.sitemap_enabled' => ['nullable', 'boolean'],
|
||||
'seo.sitemap_cache_ttl' => ['nullable', 'integer', 'min:3600', 'max:604800'],
|
||||
// 분할 기준. 상한 50000 은 sitemaps.org 프로토콜 제한이며 SitemapWriter 가 동일 값으로 클램프합니다.
|
||||
'seo.sitemap_urls_per_file' => ['nullable', 'integer', 'min:1000', 'max:50000'],
|
||||
'seo.sitemap_gzip' => ['nullable', 'boolean'],
|
||||
'seo.sitemap_serve_stale_on_miss' => ['nullable', 'boolean'],
|
||||
'seo.sitemap_max_urls_per_contributor' => ['nullable', 'integer', 'min:0'],
|
||||
'seo.sitemap_schedule' => ['nullable', 'string', Rule::in(['hourly', 'daily', 'weekly'])],
|
||||
'seo.sitemap_schedule_time' => ['nullable', 'string', 'regex:/^\d{2}:\d{2}$/'],
|
||||
'seo.generator_enabled' => ['nullable', 'boolean'],
|
||||
@@ -242,6 +247,9 @@ class SaveSettingsRequest extends FormRequest
|
||||
'advanced.stats_cache_ttl' => $this->getAdvancedTabCacheTtlRules($tab),
|
||||
'advanced.seo_cache_enabled' => $this->getTabRules($tab, 'advanced', 'boolean'),
|
||||
'advanced.seo_cache_ttl' => $this->getAdvancedTabCacheTtlRules($tab),
|
||||
// 신규 설정이므로 미전송(기존 클라이언트)을 허용한다 — 미전송/미지정 시 코드 기본값 유지.
|
||||
// 범위는 SEO 탭의 오버라이드 칸(seo.sitemap_cache_ttl)과 동일하게 맞춘다.
|
||||
'advanced.seo_sitemap_cache_ttl' => ['nullable', 'integer', 'min:3600', 'max:604800'],
|
||||
|
||||
// 디버그 설정 (advanced 탭)
|
||||
'advanced.debug_mode' => $this->getTabRules($tab, 'advanced', 'boolean'),
|
||||
@@ -605,6 +613,13 @@ class SaveSettingsRequest extends FormRequest
|
||||
'seo.sitemap_cache_ttl.integer' => __('validation.settings.sitemap_cache_ttl_integer'),
|
||||
'seo.sitemap_cache_ttl.min' => __('validation.settings.sitemap_cache_ttl_min'),
|
||||
'seo.sitemap_cache_ttl.max' => __('validation.settings.sitemap_cache_ttl_max'),
|
||||
'seo.sitemap_urls_per_file.integer' => __('validation.settings.sitemap_urls_per_file_integer'),
|
||||
'seo.sitemap_urls_per_file.min' => __('validation.settings.sitemap_urls_per_file_min'),
|
||||
'seo.sitemap_urls_per_file.max' => __('validation.settings.sitemap_urls_per_file_max'),
|
||||
'seo.sitemap_gzip.boolean' => __('validation.settings.sitemap_gzip_boolean'),
|
||||
'seo.sitemap_serve_stale_on_miss.boolean' => __('validation.settings.sitemap_serve_stale_on_miss_boolean'),
|
||||
'seo.sitemap_max_urls_per_contributor.integer' => __('validation.settings.sitemap_max_urls_per_contributor_integer'),
|
||||
'seo.sitemap_max_urls_per_contributor.min' => __('validation.settings.sitemap_max_urls_per_contributor_min'),
|
||||
'seo.sitemap_schedule.in' => __('validation.settings.sitemap_schedule_invalid'),
|
||||
'seo.sitemap_schedule_time.regex' => __('validation.settings.sitemap_schedule_time_invalid'),
|
||||
|
||||
@@ -639,12 +654,15 @@ class SaveSettingsRequest extends FormRequest
|
||||
'advanced.stats_cache_ttl.integer' => __('validation.settings.stats_cache_ttl_integer'),
|
||||
'advanced.stats_cache_ttl.min' => __('validation.settings.stats_cache_ttl_min'),
|
||||
'advanced.stats_cache_ttl.max' => __('validation.settings.stats_cache_ttl_max'),
|
||||
'advanced.seo_cache_enabled.required' => __('validation.settings.seo_cache_enabled_required'),
|
||||
'advanced.seo_cache_enabled.boolean' => __('validation.settings.seo_cache_enabled_boolean'),
|
||||
'advanced.seo_cache_ttl.required' => __('validation.settings.seo_cache_ttl_required'),
|
||||
'advanced.seo_cache_ttl.integer' => __('validation.settings.seo_cache_ttl_integer'),
|
||||
'advanced.seo_cache_ttl.min' => __('validation.settings.seo_cache_ttl_min'),
|
||||
'advanced.seo_cache_ttl.max' => __('validation.settings.seo_cache_ttl_max'),
|
||||
'advanced.seo_cache_enabled.required' => __('validation.settings.advanced_seo_cache_enabled_required'),
|
||||
'advanced.seo_cache_enabled.boolean' => __('validation.settings.advanced_seo_cache_enabled_boolean'),
|
||||
'advanced.seo_cache_ttl.required' => __('validation.settings.advanced_seo_cache_ttl_required'),
|
||||
'advanced.seo_cache_ttl.integer' => __('validation.settings.advanced_seo_cache_ttl_integer'),
|
||||
'advanced.seo_cache_ttl.min' => __('validation.settings.advanced_seo_cache_ttl_min'),
|
||||
'advanced.seo_cache_ttl.max' => __('validation.settings.advanced_seo_cache_ttl_max'),
|
||||
'advanced.seo_sitemap_cache_ttl.integer' => __('validation.settings.seo_sitemap_cache_ttl_integer'),
|
||||
'advanced.seo_sitemap_cache_ttl.min' => __('validation.settings.seo_sitemap_cache_ttl_min'),
|
||||
'advanced.seo_sitemap_cache_ttl.max' => __('validation.settings.seo_sitemap_cache_ttl_max'),
|
||||
|
||||
// 디버그 설정
|
||||
'advanced.debug_mode.required' => __('validation.settings.debug_mode_required'),
|
||||
|
||||
Reference in new issue
Block a user