다음으로 다뤄야 할 두 가지가 있습니다. 첫째, limit은 유용하지만 검색 공간에 대한 제한일 뿐입니다. 다음으로, 수정할 게시글의 최대 수를 지정할 수 있도록 하고 싶습니다. 따라서 쿼리의 limit과 함께 수정할 게시글의 최대 수도 추가해야 합니다.
또한, max를 지정할 때 디버깅 목적으로 처리되는 대상이 무엇인지 자세히 출력하는 것이 합리적입니다. 따라서 max가 nil이 아닐 때 출력을 자세히(verbose) 표시하고 싶습니다. 이는 이 작업의 주요 사용 사례가 프로세스를 계속 진행하기 전에 검증하는 것이기 때문에, 사람들이 이를 통해 프로세스를 검증할 수 있게 해줍니다.
구체적인 max를 첫 번째 인수로, 선택적인 limit을 두 번째 인수로 사용하기로 했습니다. 실제로 max가 가장 중요한 사항이기 때문입니다. limit은 “단 하나의 ping만” 처리하는 비용을 줄이기 위한 것입니다.
둘째는 비업로드: 업로드입니다. 약 1년 반 전, Google+에서 Discourse로의 마이그레이션을 작성하는 방법을 알아내려 고군분투하던 중 가입한 Discourse 사이트에 비디오를 업로드해 보았는데, 작성된 내용이 https://#{SiteSettings.absolute_base_url}/original/3X/b/a/ba9e06ebc2f4397f26793bb5cd4e169308dd371d.mp4인 것을 보았습니다.
오늘날 비디오를 업로드하면 대신 와 같은 형식이 생성됩니다.
적어도 제 최근 테스트에서는 migrate_from_s3가 이러한 URL을 완전히 망가뜨려 URL조차 되지 않게 만들었습니다. 따라서 이는 반드시 수정해야 합니다. 그런 다음, 이 작업이 실제로는 에 부딪힐 가능성이 낮다고 생각합니다. 따라서 첫 번째 단계에서는 정규 표현식이 두 가지 경우를 모두 처리하도록 하여 가독성이 더 떨어지지 않도록, 마법 같은 upload 프로토콜 주위에 링크 마크다운을 추가하는 것만 하려고 합니다. 하지만 제 생각을 바꿀 수도 있습니다.
video 또는 audio 태그가 정규 표현식 매치를 통해 자바스크립트로 추가되는 것 같습니다. 따라서 이를 올바르게 식별하기 위해 app/assets/javascripts/discourse/app/lib/uploads.js의 정규 표현식을 작업으로 복사해 와야 합니다. 다음에 이를 찾는 사람이 어디서 업데이트해야 하는지 알 수 있도록 정규 표현식의 출처를 포함할 것입니다. ![]()
…
오늘 밤, 이 작업을 위해 시간을 내어 초안 PR을 진행 중입니다. 아직 _완성_되지 않았으며, 버그가 남아 있음을 알고 있습니다. 현재 시점에서 upload: 유사 프로토콜 URL(이미지의 경우 일반적)에 대한 동작을 변경하지 않았다고 생각합니다. 다만 무결성 검사(sanity check)를 추가했습니다.
이 PR의 변경 사항으로, 현재 S3(제 경우 DigitalOcean Spaces)에 명시적으로 참조되어 있는 일반 upload: 유사 프로토콜 업로드와 비디오를 모두 성공적으로 마이그레이션했습니다. 다음 명령을 사용하여 한 번에 하나의 게시글만 수정하고 있습니다:
bin/rake uploads:batch_migrate_from_s3[1,1000]
데이터베이스 쿼리에서 무작위로 반환된 첫 번째 1000개 게시글을 넘지 않는다는 점에 유의하세요. 낮은 limit은 한 번에 하나의 게시글만 마이그레이션하면서 쿼리 속도를 높이기 위한 것이며, 해당 게시글의 올바른 동작을 검토한 후 처음부터 다시 시작하여 다른 게시글을 찾는 과정입니다. 이 명령은 현재 작업 중인 PR에서만 이 방식으로 작동합니다!
…
작업을 진행하면서 진단 출력을 계속 추가하고 있으며, 개발을 넘어 중요한 사항이라고 생각하기 시작했습니다. DigitalOcean Spaces에서 일시적인 다운로드 실패가 많이 발생하고 있으며, 게시글의 일부 다운로드만 마이그레이션되는 경우가 있습니다. 원래 코드에서는 단순히 .을 출력하고 계속 진행한 후 Done이라고 표시하지만, 실제로는 작업이 완료되지 않습니다. 모든 파일이 마이그레이션되도록 한 게시글에 대해 5~6번 정도 반복해야 했습니다. (처음에는 로컬 버그를 디버깅하는 것이라고 생각했기 때문에 개수를 세지 않았습니다.) 진단 결과가 깨끗해질 때까지 동일한 limit으로 이 마이그레이션을 반복적으로 실행해야 할 것으로 예상됩니다. 따라서 max가 설정된 경우에만 자세한 진행 상황을 출력하지만, 유용한 경고 메시지는 항상 출력하도록 하고 있습니다.
현재, 간헐적으로 다운로드가 실패하는 discourse spaces에 대해 다음과 같은 해킹 방식을 사용하고 있으며, 실제로 성공률을 크게 향상시켰습니다(수백 개의 마이그레이션된 게시글에 걸쳐 3회 재시도가 완전히 충분했습니다).
https://github.com/johnsonm/discourse/commit/7dfac12a2ea6ec04ba4e0616b4e0dbd1d806cff7
또한, Google+에서 가져왔을 때 제가 설정한 제한보다 큰 비디오가 어떻게 사이트에 들어오게 되었는지 모르겠지만, 몇 개의 과도하게 큰 비디오를 원샷 마이그레이션하는 동안 SiteSettings.max_image_size_kb와 SiteSettings.max_attachment_size_kb를 일시적으로 증가시켜야 했습니다. 이제 이를 깨뜨리고 싶지 않습니다… 과도한 업로드를 허용한 버그가 제 가져오기 스크립트, discourse, 또는 시간이 지남에 따라 설정에 적용한 변경 사항에 대한 제 기억 중 어디에 있는지 알 수 없습니다. ![]()
마이그레이션하는 것의 상당 부분이 G+에서 가져온 것이기 때문에, 일부 게시글이 현재 유효성 검사를 통과하지 못했습니다. Unhandled failure: Validation failed: Sorry, new users can only put one image in a post 오류를 몇 번 받았고, 처음에는 왜 다시 발생하지 않는지 이해하지 못했습니다. 나중에 알고 보니 업로드가 로컬로 성공적으로 이동되었고, 모두 upload: 유사 프로토콜을 사용했기 때문에 raw 데이터가 변경되지 않았습니다. 그러나 post.save!는 여전히 유효성 검사에서 해당 오류로 실패하여 post.rebake!가 실행되지 않았습니다. 따라서 3만 개 중 몇 개의 게시글에 이미지가 있어 rebake가 필요한 상태입니다. 불행히도 어떤 게시글인지 기록이 없습니다. 이제 post.save!(validate: false)로 전환하여 또 다른 수정을 가했기 때문에, 이 특정 문제는 다시 발생하지 않아야 합니다. 마이그레이션이 처리되지 않은 오류에서 중단되도록 한 것에 대해 매우 다행스럽게 생각합니다. 그렇지 않았다면 몇 개의 게시글보다 훨씬 더 큰 피해를 입혔을 수도 있었을 테니까요.
…
마이그레이션을 실행하는 동안 알림 전달을 포함하여 사이트가 사용 가능하게 유지하기 위해 sidekiq 큐를 스팸하지 않으려 합니다. 네이밍은 캐시 무효화와 오프바이원 오류와 함께 컴퓨터 과학에서 가장 어려운 두 문제 중 하나라는 것을 알고 있지만, 마이그레이션 중 rebake 후 다른 항목을 마이그레이션할 때 큐 슬롯(작업 슬롯이 아님)이 채워질 수 있는 총 허용 수를 지정하기 위해 DISCOURSE_MIGRATION_MAX_ENQUEUED 환경 변수를 제안합니다. 이를 통해 큐를 스팸하지 않고 사이트가 계속 기능하도록 합니다. lib/tasks/uploads.rake의 게시글별 rebake에 대해 이를 추가하는 패치를 가지고 있으며, 기본값은 0입니다. 저는 프로덕션 마이그레이션에서 이를 사용하고 있습니다.