삭제된 채팅 채널을 같은 이름으로 다시 생성해도 (여전히) 실패합니다

Attempt to recreate deleted chat channel with same name fails 토론을 이어서 말씀드립니다:

해당 버그는 링크된 스레드에서 보고되었지만, 제 환경에서는 여전히 지속되고 있습니다. 저는 최신 버전이며, 어제 git pull과 launcher 재빌드를 수행했습니다.

이전에 사용했던 채팅 채널 이름으로 새 채팅 채널을 지정하려고 하면 JS 콘솔에서 500 오류가 발생합니다.

Discourse 오류 로그에서는 다음과 같은 내용이 표시됩니다.

Failed to handle exception in exception app middleware : ActiveRecord::RecordNotUnique : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_chat_channels_on_slug"
DETAIL:  Key (slug)=(sec-fhir) already exists.

Rails 콘솔에서는 삭제된 ChatChannel이 사라진 것을 확인할 수 있지만, 삭제된 slug가 어딘가의 인덱스나 기타 DB 종속성에 남아있어 삭제되지 않은 것으로 의심됩니다.

이 우회 방법은 저에게는 작동하지 않습니다. "foo2"를 "foo"로 이름 변경을 시도하면 slug의 고유성 제약 조건 위반으로 인해 동일한 500 오류가 발생합니다.

삭제된 ChatChannel의 (인덱싱된) slug를 안전하게 삭제하는 방법을 확신하지 못하지만, 직접 시도해 볼 의향이 있습니다.


관련될 수 있는 내용: 이 문제도 slug에 영향을 미치지만, 동일한 문제는 아닌 것으로 보입니다: Attempt to recreate deleted chat channel with same name fails

2개의 좋아요

방금 아래 내용을 테스트해 보았는데 문제가 없었습니다:

  1. 이름이 "whiskers"이고 슬러그가 "whiskers"인 채널 생성
  2. 채널 삭제
  3. 이름이 "whiskers"이고 슬러그가 "whiskers"인 채널 생성

이렇게 하면 정상적으로 작동했습니다.

채널이 삭제될 때(2단계), 슬러그는 자동으로 고유한 값으로 변경됩니다. 하지만 해당 변경 사항이 도입되기 전에 채널을 삭제하셨다면, 기존 슬러그가 여전히 남아 있을 수 있습니다.

Rails 콘솔을 통해 삭제된 채널의 슬러그를 수동으로 업데이트할 수 있을 것 같습니다. 다만 정확한 명령어가 무엇인지는 확실하지 않습니다. 주변에 물어보겠습니다.

또한 채널 슬러그는 이제 채널 이름과 독립적으로 편집할 수 있으므로, 임시 해결책으로 오늘 원하는 이름의 채널을 생성하고 충돌하지 않는 다른 슬러그를 선택하는 방법도 있습니다.

2개의 좋아요

정말 예상치 못한 일이네요.

채널은 삭제하지 않고 소프트 삭제만 합니다. 따라서 deleted_at 컬럼이 채워진 상태로 여전히 남아 있어야 합니다.

콘솔에서 이 명령어를 실행하면 결과가 없나요?

ChatChannel.find_by(slug: "sec-fhir")
[1] pry(main)> ChatChannel.find_by(slug: "sec-fhir")
=> nil

저의 인스턴스에서도 이 테스트가 정상적으로 작동하는 것을 확인했습니다. 제 인스턴스는 최신 상태로 업데이트되어 있습니다.

문제는 데이터베이스 어딘가에 삭제되었어야 하지만 삭제되지 않고 남아 있는 슬러그가 있는 것 같습니다. 아마도 지금은 수정된 이전 버전에 버그가 있었을 수 있습니다. 이 인스턴스에서 채팅 기능이 활성화된 지 17일밖에 되지 않았으므로, 버그가 있었다면 그 기간 동안 발생했을 것입니다.

1개의 좋아요

어떤 방식으로 재현을 시도해도 재현이 되지 않습니다. DB 백업을 수행한 후, rails 콘솔에서 다음을 시도해 볼 수 있습니다. 좀 놀라운 일이긴 하지만요.

[1] pry(main)> DB.exec("DROP INDEX IF EXISTS index_chat_channels_on_slug;")
[2] pry(main)> DB.exec("CREATE UNIQUE INDEX index_chat_channels_on_slug ON chat_channels(slug);")

확인해 보니 이는 의도된 동작입니다. find_by를 사용하더라도 deleted_at 값이 있는 기록은 제외되기 때문입니다:

ChatChannel.find_by(slug: "sec-fhir")
  ChatChannel Load (0.4ms)  SELECT "chat_channels".* FROM "chat_channels" WHERE "chat_channels"."deleted_at" IS NULL AND "chat_channels"."slug" = 'sec-fhir' LIMIT 1
=> nil

대신 다음처럼 해야 합니다 (with_deleted 추가):

ChatChannel.with_deleted.find_by(slug: "sec-fhir")
  ChatChannel Load (0.3ms)  SELECT "chat_channels".* FROM "chat_channels" WHERE "chat_channels"."slug" = 'sec-fhir' LIMIT 1
=> #<CategoryChannel:0x00007fc9bfb4abf0
 id: 124,
 chatable_id: 19,
 deleted_at: Wed, 15 Feb 2023 01:19:20.982181000 UTC +00:00,
 deleted_by_id: nil,
 featured_in_category_id: nil,
 delete_after_seconds: nil,
 chatable_type: "Category",
 created_at: Fri, 13 Jan 2023 01:46:43.730329000 UTC +00:00,
 updated_at: Wed, 15 Feb 2023 01:19:56.427647000 UTC +00:00,
 name: "test channel",
 description: "",
 status: "archived",
 user_count: 1,
 last_message_sent_at: Fri, 13 Jan 2023 01:46:51.130903000 UTC +00:00,
 auto_join_users: false,
 user_count_stale: false,
 slug: "sec-fhir",
 type: "CategoryChannel",
 allow_channel_wide_mentions: true,
 messages_count: 0,
 threading_enabled: false>

따라서 오래된 삭제된 채널의 슬러그를 정리하려면 다음과 같이 처리해야 합니다:

channel = ChatChannel.with_deleted.find_by(slug: "sec-fhir")
channel.update!(slug: "#{channel.deleted_at.strftime("%Y%m%d-%H%M")}-#{channel.slug}-deleted")

@mcwumbly 와 @j.jaffeux 님, 이를 수정하기 위해 마이그레이션이 필요할까요?

2개의 좋아요

아 네, 맞아요. 이 경우 with_deleted를 빼먹었네요 :+1:

지금은 그냥 이 답변을 그대로 두는 걸 제안합니다. 수정 전에 삭제된 후 같은 이름으로 다시 생성하려는 경우는 드물어야 하니까요.

4개의 좋아요

위 내용 감사합니다. with_deleted에 대해서는 몰랐지만, 덕분에 삭제된 인스턴스를 확인하고 스니펫에 따라 슬러그를 변경할 수 있었습니다.

이 문제가 수정되었음을 확인했습니다. @j.jaffeux의 의견에 동의하며, 이 문제가 많은 사용자에게 영향을 미칠 가능성은 낮으므로, Rails 콘솔로 해결하는 방법이 이 스레드에 남아 있는 것만으로도 충분하다고 생각합니다.

3개의 좋아요

좋아요, 마커스 님에게 해결되었다니 다행입니다. 이제 이 주제를 닫겠습니다.

2개의 좋아요

새 채널(이름 “general”, 슬러그도 동일)을 생성하려고 하면 로그에 다음 오류가 표시됩니다(프론트엔드에서는 아무 반응이 없습니다).

“닫힘(Closed)” 상태의 채널은 표시되지 않습니다.

과거에 general 채널이 있었을 수 있고, 아마 삭제했을 것입니다(기본 채널인가요?)

다른 랜덤 슬러그로 재현할 수 없습니다(생성 > 삭제 > 생성이 정상적으로 작동합니다).

Failed to handle exception in exception app middleware : ActiveRecord::RecordNotUnique : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_chat_channels_on_slug"
DETAIL:  Key (slug)=(general) already exists.

보고서들을 한데 모으기 위해 게시글을 여기로 옮겼습니다. :+1:

위에서 언급한 우회 방법이 당신에게도 적용될 수 있을까요?

OP의 우회책은, 아니, 작동하지 않았습니다.

이것도 제 환경에서는 작동하지 않는 것 같습니다.

[1] pry(main)> ChatChannel.find_by(slug: "general")
NameError: uninitialized constant ChatChannel
from (pry):1:in `__pry__'

OP의 문제에 대한 우회 방법은 이 게시물에 있습니다:

2개의 좋아요

저는 이 방법들을 시도해 보았고, 제가 공유한 코드 블록도 바로 그 내용과 관련이 있습니다.

저는 rails에서 이 명령어들을 실행하는 데 실패했습니다.

아마 제가 무언가를 잘못하고 있는 것일까요?

수정: 명확히 하기 위해, 제안된 우회 방법은 채널을 찾을 때 동일한 오류를 반환합니다.

[7] pry(main)> ChatChannel.with_deleted.find_by(slug: "general")
NameError: uninitialized constant ChatChannel
from (pry):7:in `__pry__'
2개의 좋아요

좋아요, 문제를 해결했습니다 (적어도 그렇게 생각합니다).

저는 이 모든 것을 파악하는 데 꽤 고생했기 때문에 전체 단계를 공유하겠습니다.

cd /var/discourse && ./launcher enter app
rails c
DB.exec("UPDATE chat_channels SET slug = 'new' WHERE slug = 'old';")

따라서 Rails 콘솔에서는 다음과 같이 표시됩니다:

[1] pry(main)> DB.exec("UPDATE chat_channels SET slug = 'new' WHERE slug = 'old';")
=> 1
[2] pry(main)> exit
root@discourse-app:~# exit
logout
➜  discourse git:(main) ✗ 

이제 원하는 슬러그로 새 채널을 만들 수 있습니다.

이것이 (또는) 올바른 방법인가요?

2개의 좋아요

위에서 실패한 우회 방법은 몇 주 전에 도입한 네임스페이스링 때문입니다. 이제 ChatChannel은 Chat::Channel입니다.

1개의 좋아요

이런 걸 기대하고 있었지만 찾지 못했어요. 제 DB 변경 사항도 좋은 우회책이 될까요? 지금까지는 문제가 없었어요.

2개의 좋아요