🪣

バージョニング有効な S3 バケットを空にする

2024/04/24に公開

バケット内のすべてのオブジェクトを復元不可能な状態で削除するので注意してください

Aws::S3::Client#list_object_versionsAws::S3::Client#delete_object を使ってオブジェクトバージョンと削除マーカーを削除する。

削除を待っていると遅いので、マルチスレッドで処理している。

require "aws-sdk-s3"
require "thread"

NUMBER_OF_WORKERS = 8
BUCKET = "バケット名"
TERMINATOR = Object.new

def build_client
  Aws::S3::Client.new(
    # profile 使っていない場合は https://rubydoc.info/gems/aws-sdk-s3/1.147.0/Aws/S3/Client#initialize-instance_method を参考に access_key_id, secret_access_key など指定
    profile: "プロファイル名",
    region: "ap-northeast-1", # リージョン名
  )
end

def build_worker(queue)
  Thread.new {
    s3 = build_client
    loop do
      v = queue.pop
      break if v == TERMINATOR

      key, version_id = v.fetch(:key), v.fetch(:version_id)
      puts "deleting... #{key} (#{version_id})"
      s3.delete_object(bucket: BUCKET, key: key, version_id: version_id)
    end
  }
end

s3 = build_client
queue = SizedQueue.new(NUMBER_OF_WORKERS * 2)
workers = NUMBER_OF_WORKERS.times.map { build_worker(queue) }

key_marker = nil
version_id_marker = nil

loop do
  result = s3.list_object_versions(bucket: BUCKET, key_marker:, version_id_marker:)
  key_marker = result.next_key_marker
  version_id_marker = result.next_version_id_marker

  result.versions.each do |v|
    queue.push({key: v.key, version_id: v.version_id})
  end

  result.delete_markers.each do |d|
    queue.push({key: d.key, version_id: d.version_id})
  end

  p [key_marker, version_id_marker]
  break unless key_marker || version_id_marker
end

NUMBER_OF_WORKERS.times { queue.push(TERMINATOR) }
workers.each(&:join)

Discussion