최신 Discourse 업그레이드 오류 -- 해결됨

Discourse 설치에서 3.5.0.beta3-dev로 업그레이드를 시도하는 중 오류가 발생했습니다:

Discourse가 시작되지 않습니다. 어떤 제안이라도 큰 도움이 될 것입니다.

Status: Image is up to date for discourse/base:2.0.20250226-0128

...

I, [2025-04-18T15:16:34.677745 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'LOAD_PLUGINS=0 bundle exec rake plugin:pull_compatible_all'
I, [2025-04-18T15:16:40.775977 #1]  INFO -- : discourse-bbcode-color is already at latest compatible version
discourse-cakeday is already at latest compatible version
discourse-chat-integration is already at latest compatible version
discourse-data-explorer is already at latest compatible version
discourse-math is already at latest compatible version
discourse-oauth2-basic is already at latest compatible version
discourse-rss-polling is already at latest compatible version
discourse-solved is already at latest compatible version
discourse-whos-online is already at latest compatible version
discourse-yearly-review is already at latest compatible version
docker_manager is already at latest compatible version

오류:

I, [2025-04-18T15:16:50.782650 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate'
2025-04-18 15:16:59.705 UTC [911] discourse@discourse ERROR:  null value in column "answer_post_id" of relation "discourse_solved_solved_topics" violates not-null constraint
2025-04-18 15:16:59.705 UTC [911] discourse@discourse DETAIL:  Failing row contains (768, 16673, null, -1, null, 2021-05-10 18:32:53.008822, 2021-05-10 18:32:53.008822).
2025-04-18 15:16:59.705 UTC [911] discourse@discourse STATEMENT:  INSERT INTO discourse_solved_solved_topics (
          topic_id,
          answer_post_id,
          topic_timer_id,
          accepter_user_id,
          created_at,
          updated_at
        )
        SELECT
          tc.topic_id,
          tc.answer_post_id,
          tc.topic_timer_id,
          tc.accepter_user_id,
          tc.created_at,
          tc.updated_at
        FROM (
          SELECT
            tc.topic_id,
            CAST(tc.value AS INTEGER) AS answer_post_id,
            CAST(tc2.value AS INTEGER) AS topic_timer_id,
            COALESCE(ua.acting_user_id, -1) AS accepter_user_id,
            tc.created_at,
            tc.updated_at,
            ROW_NUMBER() OVER (PARTITION BY tc.topic_id ORDER BY tc.created_at ASC) AS rn_topic,
            ROW_NUMBER() OVER (PARTITION BY CAST(tc.value AS INTEGER) ORDER BY tc.created_at ASC) AS rn_answer
          FROM topic_custom_fields tc
          LEFT JOIN topic_custom_fields tc2 ON tc2.topic_id = tc.topic_id AND tc2.name = 'solved_auto_close_topic_timer_id'
          LEFT JOIN user_actions ua ON ua.target_topic_id = tc.topic_id AND ua.action_type = 15
          WHERE tc.name = 'accepted_answer_post_id'
            AND tc.id > 0
            AND tc.id <= 0 + 10000
        ) tc
        WHERE tc.rn_topic = 1 AND tc.rn_answer = 1
        ON CONFLICT DO NOTHING

rake aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)

방금 discourse-doctor를 실행했는데 동일한 오류로 실패합니다.

추가적인 세부 정보; 실패한 행:

DETAIL:  Failing row contains (1152, 16673, null, -1, null, 2021-05-10 18:32:53.008822, 2021-05-10 18:32:53.008822)

컨테이너를 실행하지 않고도 데이터베이스에 접근할 수 있다면 그 행을 삭제할 수 있을 텐데…

수정되었습니다.

DB를 정리하는 데 시간이 좀 걸렸습니다. postgres 도커 이미지를 사용해 데이터베이스를 마운트했습니다:

docker run --name postgres_container_2 -e POSTGRES_PASSWORD=mysecretpassword -d -p 5432:5432 -v /var/discourse/shared/standalone/postgres_data:/var/lib/postgresql/data postgres:15

그런 다음 문제의 테이블 행을 찾았습니다:

SELECT
          tc.topic_id,
          tc.answer_post_id,
          tc.topic_timer_id,
          tc.accepter_user_id,
          tc.created_at,
          tc.updated_at
        FROM (
          SELECT
            tc.topic_id,
            CAST(tc.value AS INTEGER) AS answer_post_id,
            CAST(tc2.value AS INTEGER) AS topic_timer_id,
            COALESCE(ua.acting_user_id, -1) AS accepter_user_id,
            tc.created_at,
            tc.updated_at,
            ROW_NUMBER() OVER (PARTITION BY tc.topic_id ORDER BY tc.created_at ASC) AS rn_topic,
            ROW_NUMBER() OVER (PARTITION BY CAST(tc.value AS INTEGER) ORDER BY tc.created_at ASC) AS rn_answer
          FROM topic_custom_fields tc
          LEFT JOIN topic_custom_fields tc2 ON tc2.topic_id = tc.topic_id AND tc2.name = 'solved_auto_close_topic_timer_id'
          LEFT JOIN user_actions ua ON ua.target_topic_id = tc.topic_id AND ua.action_type = 15
          WHERE tc.name = 'accepted_answer_post_id'
            AND tc.id > 0
            AND tc.id <= 0 + 10000
            AND tc.value IS NULL
        ) tc

이 쿼리가 오류에 해당하는 행만 선택하도록 확인한 후, SELECT를 DELETE로 변경하고, ./launcher rebuild app을 실행했습니다.

이미지 빌드를 기다리는 시간이 꽤 오래 걸렸지만, 이제 커뮤니티는 안정적이고 사이트도 재구축되었습니다. 보안 수정 사항도 포함되었습니다.

위에서 언급한 행이 왜 비효율적인 상태가 되었는지는 정확히 알 수 없지만, 해당 행이 삭제된 후에는 모든 것이 정상으로 돌아왔습니다.

Discourse가 실행되지 않을 때 데이터베이스에 액세스하는 위험한 지침

책임 소재를 명확히 하고 사용하시기 바랍니다.