diff --git a/lib/postal/message_db/provisioner.rb b/lib/postal/message_db/provisioner.rb index dca20547f..638723921 100644 --- a/lib/postal/message_db/provisioner.rb +++ b/lib/postal/message_db/provisioner.rb @@ -59,10 +59,12 @@ def create_table(table_name, options) end # - # Drop a table + # Drop a table. Uses IF EXISTS so that two workers running retention + # concurrently do not crash when the second one tries to drop a table + # the first has already removed. # def drop_table(table_name) - @database.query("DROP TABLE `#{@database.database_name}`.`#{table_name}`") + @database.query("DROP TABLE IF EXISTS `#{@database.database_name}`.`#{table_name}`") end # diff --git a/spec/lib/postal/message_db/database_spec.rb b/spec/lib/postal/message_db/database_spec.rb index dc9e96080..ec9613b04 100644 --- a/spec/lib/postal/message_db/database_spec.rb +++ b/spec/lib/postal/message_db/database_spec.rb @@ -73,5 +73,15 @@ end.to raise_error(Mysql2::Error) end end + + describe "#drop_table" do + # The retention task's lock can be stolen after a few minutes, so two + # workers may call drop_table for the same table. Dropping a table that + # has already been removed must not raise (regression for #3595). + it "does not raise when the table no longer exists" do + expect { database.provisioner.drop_table("raw-does-not-exist") } + .not_to raise_error + end + end end end