db: fix ActiveStorage migration to Rails 6.1

1. Executing an `update_all` on a lot of records is slow. Instead we
backfill the column in batches (without locking the table).

2. We can't mark the colum as not-null, because already running
instances still using the old code will not use the service_name
column yet.

  A later migration will backfill the remaining data and make the column
non-null.
This commit is contained in:
Pierre de La Morinerie 2021-03-25 16:46:18 +00:00
parent 703f13c34d
commit a08c18eb81
2 changed files with 18 additions and 7 deletions

View file

@ -1,16 +1,27 @@
# This migration comes from active_storage (originally 20190112182829)
class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
unless column_exists?(:active_storage_blobs, :service_name)
add_column :active_storage_blobs, :service_name, :string
end
if (configured_service = ActiveStorage::Blob.service.name)
# rubocop:disable DS/Unscoped
ActiveStorage::Blob.unscoped.update_all(service_name: configured_service)
# rubocop:enable DS/Unscoped
# rubocop:disable DS/Unscoped
blobs_without_service_name = ActiveStorage::Blob.unscoped.where(service_name: nil)
# rubocop:enable DS/Unscoped
if (configured_service = ActiveStorage::Blob.service.name && blobs_without_service_name.count > 0)
# Backfill the existing blobs with the service.
# NB: during a continuous deployments, some blobs may still be created
# with an empty service_name. A later migration will fix those later.
say_with_time('backfill ActiveStorage::Blob.service.name. This could take a while…') do
blobs_without_service_name.in_batches do |relation|
relation.update_all service_name: configured_service
sleep(0.01) # throttle
end
end
change_column :active_storage_blobs, :service_name, :string, null: false
end
end

View file

@ -44,7 +44,7 @@ ActiveRecord::Schema.define(version: 2021_03_18_090001) do
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.string "service_name", null: false
t.string "service_name"
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end