allow additional columns to be ignored through Consul
refs AE-124 When running pre-deploy migrations that add a new column, if an application server loads the schema on a shard where the migration has already run, and tries to run queries on a shard where the migration has not already run, it can lead to errors. Fix this by allowing ignored_columns to append to its value dynamically through Consul. Change-Id: I3b13e0fd2ac066e1439d3d314d71f2ebd8938e0c Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/310561 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jacob Burroughs <jburroughs@instructure.com> QA-Review: Aaron Ogata <aogata@instructure.com> Product-Review: Aaron Ogata <aogata@instructure.com>
This commit is contained in:
parent
fe4f7009d4
commit
0aca0be810
|
@ -2219,3 +2219,13 @@ if Rails.version >= "6.1"
|
|||
# rubocop:enable Lint/RescueException
|
||||
# rubocop:enable Naming/RescuedExceptionsVariableName
|
||||
end
|
||||
|
||||
module AdditionalIgnoredColumns
|
||||
def ignored_columns
|
||||
return super unless superclass <= ActiveRecord::Base && !abstract_class?
|
||||
|
||||
columns_to_ignore = DynamicSettings.find("activerecord/ignored_columns", tree: :store)[table_name]&.split(",") || []
|
||||
super + columns_to_ignore
|
||||
end
|
||||
end
|
||||
ActiveRecord::Base.singleton_class.include(AdditionalIgnoredColumns)
|
||||
|
|
|
@ -11,3 +11,35 @@ end
|
|||
MultiCache.delete("schema_cache")
|
||||
end
|
||||
end
|
||||
|
||||
namespace :db do
|
||||
desc "Clear columns to be ignored for each model"
|
||||
task :clear_ignored_columns, [:table_name] => :environment do |_t, args|
|
||||
Diplomat::Kv.delete(
|
||||
"store/canvas/#{DynamicSettings.environment}/activerecord/ignored_columns/#{args[:table_name]}"
|
||||
)
|
||||
|
||||
MultiCache.delete("schema_cache")
|
||||
end
|
||||
|
||||
desc "Get columns to be ignored for each model"
|
||||
task :get_ignored_columns, [:table_name] => :environment do |_t, args|
|
||||
ignored_columns = Diplomat::Kv.get(
|
||||
"store/canvas/#{DynamicSettings.environment}/activerecord/ignored_columns/#{args[:table_name]}"
|
||||
)
|
||||
|
||||
puts "Ignored Columns: #{ignored_columns}"
|
||||
rescue Diplomat::KeyNotFound
|
||||
puts "Ignored Columns: -"
|
||||
end
|
||||
|
||||
desc "Set columns to be ignored for each model"
|
||||
task :set_ignored_columns, [:table_name, :columns] => :environment do |_t, args|
|
||||
Diplomat::Kv.put(
|
||||
"store/canvas/#{DynamicSettings.environment}/activerecord/ignored_columns/#{args[:table_name]}",
|
||||
args[:columns]
|
||||
)
|
||||
|
||||
MultiCache.delete("schema_cache")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -338,6 +338,31 @@ module ActiveRecord
|
|||
.to eq [user]
|
||||
end
|
||||
end
|
||||
|
||||
describe ".ignored_columns" do
|
||||
it "ignores additional columns specified in Consul" do
|
||||
# If this test is the first one to run that requires User - preload User so that the correct
|
||||
# accessors (getters / setters) already exist since the "ensure" block won't create them. In
|
||||
# a real situation, we would first perform a rolling restart after having unset this key and
|
||||
# finished pre-deploy migrations everywhere.
|
||||
User.create!(name: "user u1")
|
||||
|
||||
allow(DynamicSettings).to receive(:find).with(any_args).and_call_original
|
||||
allow(DynamicSettings).to receive(:find).with("activerecord/ignored_columns", tree: :store).and_return(
|
||||
{
|
||||
"users" => "name"
|
||||
}
|
||||
)
|
||||
|
||||
User.reset_column_information
|
||||
expect { User.create!(name: "user u2") }.to raise_exception(ActiveModel::UnknownAttributeError)
|
||||
ensure
|
||||
allow(DynamicSettings).to receive(:find).with("activerecord/ignored_columns", tree: :store).and_call_original
|
||||
|
||||
User.reset_column_information
|
||||
User.create!(name: "user u2")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".asset_string" do
|
||||
|
|
Loading…
Reference in New Issue