관리자 기능

안녕하세요, 관리자 화면에 접속을 시도하면 빈 화면만 표시됩니다. 관리자인데도 업데이트를 할 수 없습니다.
어떻게 해야 하나요?
도와주셔서 감사합니다.
Muriel

안전 모드를 시도해 볼 수 있습니다. 또한 명령줄을 통해 업그레이드를 수행하는 것도 좋은 방법입니다.

업데이트: 2컨테이너 구성으로 올바른 bootstrap, destroy, start를 수행한 후 보고된 버전 번호가 업데이트되었고 Admin UI가 다시 렌더링됩니다.

나머지 게시글 내용은 기록을 위해 그대로 유지합니다.


비슷한 문제를 겪고 있을 수 있습니다. Admin 인터페이스는 로드되지만 상단 탭만 표시되고 메인 콘텐츠 섹션은 비어 있습니다:

브라우저 콘솔 로그

브라우저 콘솔 로그를 검토해 보니 다음과 같은 오류를 확인했습니다:

[Error] Error: VM BUG: Target must be set before attempting to jump
vendor.xxxxx-xxxx.js
Unhandled Promise Rejection: Error: Could not find module `discourse/lib/decorators` imported from `discourse/plugins/docker_manager/discourse/routes/update`
에러 스택
[Error] Error: VM BUG: Target must be set before attempting to jump
	b (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:131956)
	evaluate (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:69428)
	_execute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111383)
	execute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111253)
	rerender (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:115153)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252217)
	tx (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:105883)
	_renderRoots (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252117)
	_renderRootsTransaction (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252504)
	_revalidate (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252982)
	invoke (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:153517)
	flush (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:152599)
	flush (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:154477)
	_end (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:159527)
	end (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:156653)
	_runExpiredTimers (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:160801)
[Error] Unhandled Promise Rejection: Error: Could not find module `discourse/lib/decorators` imported from `discourse/plugins/docker_manager/discourse/routes/update`
	(anonymous function) (vendor.6f1929e16c84d825f1e134b0a5a6bf6d-ed21b08557694a2386531fb8b5bd479da7fe4ec9cffd9278c49f382c5e7bc3a4.js:1:1310)
	h (vendor.6f1929e16c84d825f1e134b0a5a6bf6d-ed21b08557694a2386531fb8b5bd479da7fe4ec9cffd9278c49f382c5e7bc3a4.js:1:1311)
	(anonymous function) (vendor.6f1929e16c84d825f1e134b0a5a6bf6d-ed21b08557694a2386531fb8b5bd479da7fe4ec9cffd9278c49f382c5e7bc3a4.js:1:3065)
	h (vendor.6f1929e16c84d825f1e134b0a5a6bf6d-ed21b08557694a2386531fb8b5bd479da7fe4ec9cffd9278c49f382c5e7bc3a4.js:1:1375)
	requireModule (vendor.6f1929e16c84d825f1e134b0a5a6bf6d-ed21b08557694a2386531fb8b5bd479da7fe4ec9cffd9278c49f382c5e7bc3a4.js:1:599)
	_extractDefaultExport (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:105:269780)
	resolveOther (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:105:266326)
	resolve (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:105:266888)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:262092)
	resolve (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:262185)
	resolve (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:262275)
	c (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:260192)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:258815)
	getRoute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:56849)
	fetchRoute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:267571)
	_getQPMeta (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:63399)
	_hydrateUnsuppliedQueryParams (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:64113)
	_prepareQueryParams (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:63271)
	normalizeQueryParams (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:38898)
	_generateURL (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:111:38990)
	eA (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:202925)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:49065)
	X (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:140358)
	T (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:49044)
	eM (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:80191)
	flush (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:79868)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:70930)
	evaluate (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:65312)
	evaluateSyscall (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111047)
	evaluateInner (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:110609)
	evaluateOuter (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:110528)
	next (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:121496)
	_execute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:121359)
	handleException (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:112232)
	handleException (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:114799)
	throw (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111583)
	evaluate (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:68993)
	_execute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111383)
	execute (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:111253)
	rerender (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:115153)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252217)
	tx (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:105883)
	_renderRoots (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252117)
	_renderRootsTransaction (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252504)
	_revalidate (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:252982)
	invoke (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:153517)
	flush (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:152599)
	flush (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:154477)
	_end (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:159527)
	(anonymous function) (chunk.6994431508d4f7ecb4c3.d41d8cd9.js:119:155980)

업그레이드 과정 (2컨테이너)

처음에는 Discourse Admin UI에서 업그레이드를 완료하려는 시도에 따라 문제가 발생하기 시작했으며, Docker Manager를 먼저 업데이트해야 한다는 메시지가 표시되었습니다.

Docker Manager를 업데이트한 후 해당 문제가 발생하기 시작하여, 서버에 SSH로 접속하여 web_only에 대한 수동(2컨테이너) 업데이트를 수행했습니다:

cd /var/discourse
git pull
./launcher bootstrap web_only
./launcher stop web_only && ./launcher start web_only
           ^^^^
    ⚠️ 이것은 잘못되었습니다! 아래에서 설명하는 destroy를 사용하세요. ⚠️

흥미롭게도, /about.json 경로에서는 여전히 3.4.0.beta4-dev를 실행 중임을 표시하고 있습니다. 이는 원래 이메일이 3.4.0.beta4-dev에서 3.5.0.beta1로 업그레이드하는 것이었기 때문에 시작점으로 생각했던 버전입니다.

git 로그를 다시 확인해 보니, 작성 시점 기준으로 discourse_docker는 최신 커밋 3715498fc188d60c0b579443383c4e973cf26f59에 있는 것 같습니다.

안전 모드(Safe-Mode)는 작동합니다

안전 모드에 대해 알지 못했지만,Apparently 모든 클라이언트 측 플러그인을 비활성화하면 문제가 발생하지 않는 것 같습니다.

비공식 클라이언트 측 플러그인 커스터마이제이션만 비활성화해서는 문제를 해결할 수 없었으며, 문제를 좁히기 위해 각 조합을 시도해 보았습니다.

옵션 결과
no_unofficial_plugins :cross_mark:
no_plugins :white_check_mark:
no_themes :cross_mark:

docker_manager 비활성화는 도움이 되지 않습니다

hooks/after_code 아래에서 docker_manager 플러그인을 주석 처리하고, web_only 컨테이너를 다시 빌드한 후 stop && start를 수행해 보았지만, 위에서 언급한 클라이언트 측 오류 메시지는 여전히 남아 있습니다.

this.class.create is not a function라는 또 다른 오류 메시지를 도입합니다. 이는 테스트를 위해 기본 docker_manager 플러그인이 비활성화된 상태이기 때문에 예상되는 결과일 수 있습니다:

loader.js:247 Uncaught (in promise) Error: Could not find module `discourse/lib/decorators` imported from `discourse/plugins/docker_manager/discourse/routes/update`
    at loader.js:247:1
    at h (loader.js:258:1)
    at u.findDeps (loader.js:168:1)
    at h (loader.js:262:1)
    at requireModule (loader.js:24:1)
    at f.get (composer.js:874:1)
    at push.98673._extractDefaultExport (composer.js:874:1)
    at push.98673.resolveOther (composer.js:874:1)
    at push.98673.resolve (composer.js:874:1)
    at n.i [as getRoute] (upload-debugging.js:25:1)
    at p._getQPMeta (upload-debugging.js:25:1)

index.js:78 Uncaught TypeError: this.class.create is not a function
    at n.i [as getRoute] (upload-debugging.js:25:1)
    at p._getQPMeta (upload-debugging.js:25:1)

다시 한번, no_plugins를 사용하는 안전 모드는 문제를 일시적으로 우회하는 방법입니다.

컨테이너 2개 최소 다운타임 업데이트 명령어는 기억에 의존해서 작성했는데, 분명히 제 기억을 신뢰할 수 없었네요! :flushed_face:

bootstrap 후 새 컨테이너를 시작하기 전에 destroy하는 올바른 명령어를 사용한 후, 버전이 업데이트되었음을 확인했고 관리자 인터페이스가 예상대로 작동하고 있습니다.

데이터 컨테이너를 업그레이드하셨나요? 업그레이드하셔야 합니다. 하지만 먼저 PostgreSQL 15 업데이트를 확인해 보세요. 또는, 읽는 것을 정말 싫어하신다면 ./laumcher rebuild data두 번 실행하시면 됩니다. 그러면 문제가 해결될 것입니다. 그 다음에는 웹 컨테이너를 destroy하고 start해야 합니다(그렇지 않으면 이미 파괴할 구 데이터 컨테이너를 찾게 됩니다).

아직은 아니지만 신경 써줘서 고마워!

더 강력한 스펙의 새 서버를 세팅하는 것을 이미 고려 중이었어. 그래서 Discourse 3.5 + PG13에서 백업한 뒤 다른 호스트의 Discourse 3.5 + PG15로 복원할 수 있는지 조사하고 있었어.

긴 시간의 다운타임을 좋아하지 않아. 지난번에는 커뮤니티를 임시로 읽기 전용으로 설정하고 서버 인스턴스 간 백업/복원을 진행했는데, (물론 읽기 전용 기간을 제외하면) 사실상 다운타임이 없었어… 그래서 PG 버전 간에도 작동하는지 조사/테스트해 보기로 했어.

그렇지 않으면 PG15 업그레이드를 먼저 하고 서버 마이그레이션을 진행하는 수밖에 없겠어. :slight_smile:

작동합니다. 어차피 OS를 업그레이드할 때가 된 것 같습니다. 새 서버를 설정하고 백업을 복원하세요.

저도 정확히 같은 문제를 겪고 있습니다. 도움을 주셔서 감사합니다. 제 웹마스터 벤자민이 이 내용을 확인해 보겠습니다.
뮈리엘

저한테는 이런 일이 생겼습니다. 새 서버를 띄우고 백업에서 복원하는 것이 유일한 해결책이었어요.
그는 핵심을 찌릅니다. 디버깅에 시간을 낭비하지 마세요. 이 조언 덕분에 금방 해결할 수 있습니다.

결국 백업과 복원을 수행했고, 예상대로 잘 작동했습니다.


혹시 다른 사람이 유사한 문제에 직면할 경우를 대비해 참고용으로 공유합니다…

처음에 약간의 문제가 있었습니다. 복원 프로세스가 내부적으로 uploads:migrate_to_s3를 호출하는데, 여기서 멈추는 현상이 발생했기 때문입니다.

2025-02-26 00:24:16] Migrating the database...
[2025-02-26 00:24:24] 
[2025-02-26 00:24:24] Reconnecting to the database...
[2025-02-26 00:24:24] Reloading site settings...
[2025-02-26 00:24:24] Disabling outgoing emails for non-staff users...
[2025-02-26 00:24:24] Disabling readonly mode...
[2025-02-26 00:24:24] Clearing category cache...
[2025-02-26 00:24:24] Reloading translations...
[2025-02-26 00:24:24] Remapping uploads...
[2025-02-26 00:24:24] Restoring uploads, this may take a while...
[2025-02-26 00:25:09] EXCEPTION: 12 of 12208 uploads are not migrated to S3. S3 migration failed for db 'default'.
[2025-02-26 00:25:09] /var/www/discourse/lib/file_store/to_s3_migration.rb:132:in `raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:73:in `migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:383:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:59:in `migrate'
/var/www/discourse/lib/file_store/s3_store.rb:354:in `copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:69:in `restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:49:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:167:in `restore_uploads'
/var/www/discourse/lib/backup_restore/restorer.rb:71:in `run'
/var/www/discourse/script/spawn_backup_restore.rb:20:in `restore'
/var/www/discourse/script/spawn_backup_restore.rb:33:in `block in <main>'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `<main>'
[2025-02-26 00:25:09] Trying to rollback...
[2025-02-26 00:25:09] Rolling back...
[2025-02-26 00:25:10] Cleaning stuff up...

결국 데이터 컨테이너에서 몇 가지 SQL 쿼리를 실행하여 무슨 일이 일어나고 있는지 파악해 보았습니다.

./launcher enter data
sudo -u postgres psql discourse
SELECT url FROM uploads WHERE url NOT LIKE '%s3%';

이 쿼리는 Discourse의 표준 내장 항목 몇 가지를 반환했을 뿐이므로, 반대로 이렇게 시도해 보았습니다:

SELECT url from uploads where url LIKE '%s3%' limit 10;

그 결과 다음과 같은 형식의 많은 매칭 항목이 반환되었습니다:

  • //{my-bucket-name}.s3.dualstack.us-east-2.amazonaws.com/original/2X/5/{image-id}.jpeg

그런 다음 해당 s3.dualstack 호스트와 일치하지 않는 모든 항목을 가져오는 쿼리를 실행해 보았는데, 이전 복원 로그 실패에서 실패한 수와 일치하는 12개의 구식 엔트리가 약간 다른 형식으로 사용되고 있음을 발견했습니다.

  • //{my-bucket-name}.s3-us-east-2.amazonaws.com/{file-path}.jpeg

실제 버킷에서 해당 파일의 존재 여부를 확인했을 때 파일이 존재하지 않았으므로, 다음과 같은 쿼리를 실행하여 삭제했습니다:

DELETE FROM uploads where url LIKE '%{my-bucket-name}.s3-us-east-2.amazonaws.com%';

이후 백업과 복원이 예상대로 정상적으로 작동했습니다!

P.S. 백업을 복원한 후 이메일을 다시 활성화하는 것을 잊지 마세요!

/admin/site_settings/category/all_results?filter=disable_email