누락된 업로드를 데이터베이스에 다시 추가하기

오케이, Claude와 많은 칭찬으로 문제를 해결했습니다. 비슷한 또는 동일한 문제를 겪고 있는 다른 분들을 도우려고 제가 한 작업을 공유합니다.

이것이 가장 지능적이고 최적의 방법인지는 확실하지 않지만, 제게는 효과가 있었던 방법입니다.

전문가가 아니라 항상 배우고 있는 초보자이므로 주의하시고 이 점을 염두에 두시기 바랍니다.

문제 (S3 → 로컬 파일 시스템)

AWS S3에서 로컬 FS로 마이그레이션한 후, 많은 이미지들이 transparent.png로 표시되었습니다. 파일은 항상 디스크에 존재했지만 Discourse가 이를 해결하지 못했습니다.

근본 원인은 끊어진 체인이었습니다:

  1. upload:// 짧은 URL(base62 인코딩된 SHA1)을 가진 게시물.
  2. SHA1 → 로컬 파일 경로를 매핑하는 데이터베이스uploads.
  3. SHA1 해시로 이름이 지정된 파일을 저장하는 파일 시스템.

마이그레이션은 파일을 디스크에 올바르게 이동했지만, uploads DB 기록이 존재하지 않았습니다. 일치하는 기록이 없으면 Discourse는 transparent.png로 대체합니다.

해결책 (기록 생성 및 재베이크)

# 컨테이너 진입
./launcher enter app
rails c

고아 파일에서 누락된 업로드 기록 생성:

dir = Rails.root.join("public", "uploads", "default", "original")
created = 0

Dir.glob(dir.join("**", "*")).select { |f| File.file?(f) }.each do |path|
  sha = File.basename(path, File.extname(path))
  next if Upload.find_by(sha1: sha)

  ext = File.extname(path).delete(".")
  relative = path.sub("#{Rails.root}/public", "")

  u = Upload.new
  u.sha1 = sha
  u.url = relative
  u.original_filename = File.basename(path)
  u.filesize = File.size(path)
  u.extension = ext
  u.user_id = -1
  u.save!(validate: false)

  created += 1
  puts "Created upload #{u.id}: #{sha}"
end

puts "Total created: #{created}"

복원된 업로드를 참조하는 게시물 재베이크:

fixed_posts = 0

Upload.where(user_id: -1).find_each do |u|
  short = u.short_url
  next unless short

  Post.where("raw LIKE '%upload://%'").find_each do |p|
    urls = p.raw.scan(/upload:\/\/[^\s\]\)]+/)
    urls.each do |url|
      decoded = Upload.sha1_from_short_url(url)
      if decoded == u.sha1
        p.rebake!
        fixed_posts += 1
        puts "Rebaked post #{p.id}"
        break
      end
    end
  end
end

puts "Total rebaked: #{fixed_posts}"

누락된 최적화 파일 재생성:

원본 파일을 수정한 후, 최적화 파일(1X, 2X 등)을 채워 넣어야 합니다.

Rake는 discourse 컨테이너에서는 작동하지만 rails 콘솔에서는 작동하지 않습니다.

rake uploads:regenerate_missing_optimized

[선택 사항] 여전히 최적화 파일이 누락된 경우

rake uploads:regenerate_missing_optimized가 모든 파일 문제를 해결하지 못하고 여전히 파일이 누락된 경우:

# 컨테이너 진입
./launcher enter app
rails c
missing = 0
OptimizedImage.find_each do |oi|
  path = "#{Rails.root}/public#{oi.url}"
  unless File.exist?(path)
    missing += 1
    oi.delete
  end
end
puts "Deleted #{missing} broken optimized records"

그 후 rails를 종료하고 다시 실행합니다:

rake uploads:regenerate_missing_optimized

안전한 롤백 (만약을 대비하여)

생성된 모든 기록은 user_id: -1을 사용하며, delete_all은 콜백을 건너뛰므로 파일 시스템의 파일에는 영향을 미치지 않습니다. 되돌리려면:

Upload.where(user_id: -1).delete_all

실수로 destroy_all을 사용하여 파일이 톰스톤으로 이동하는 콜백이 트리거되었습니다.

테스트용으로 사용했던 개별 항목을 복구하고 제 접근 방식을 재구성했습니다.