Renaming column and table in database migrations with Elixir and PostgreSQL
by Patryk Bąk

To guarantee zero downtime deployment, while deploying a new version of our application on more than one node, we can use rolling updates. What if this new version has a migration which renames either column or table? Will rolling updates protect our application against downtime?

Let's assume that we have a users table. As the name is not clear, we have decided to rename it to participants, as we keep there records of people who signed up for a triathlon race.

defmodule Migrations.RenameUsersTableName do
    use Ecto.Migration

    rename table(:users), to: table(:participants)
end

defmodule Participants do
    use Ecto.Schema

    schema "participants" do
        ...
    end
end

Not only did we write a migration which renames table, but also changed both the module and schema name.

Now, let's deploy this new code for both instances of our application using rolling update.

It means that its version will be updated incrementally. The first instance will be terminated and replaced with the new version of the application. Afterwards, if the first instance starts up properly, then the second instance will be terminated and also replaced with the new one.

As you can see, there is a moment, before the second instance is replaced with the new one, when we have two versions of the application.

Both of them can be used by users. The first new instance ran the migration which renamed a table from users to participants and started using a new schema name - participant. Both instances of the application use the same database. Due to that, until the second instance is replaced, every request handled by it will return error as this instance uses the old schema name - users. The one which does not exist anymore in our database structure.

How can we solve that?

One way to solve the above-mentioned problem is to use PostgreSQL views. In simple terms, a PostgreSQL view gives us a possibility to create a query and assign it a name. To make it clearer, I'll give an example in a moment.

Previously, while deploying the new version of our application, the change contained the migration which renames the table from users to participants. In this migration we can also create the following PostgreSQL view:

defmodule Migrations.RenameUsersTableName do
    use Ecto.Migration

    rename table(:users), to: table(:participants)

    execute("
        CREATE VIEW users AS SELECT * FROM participants;
    ")
end

The query which fetches all records from table participants, which we've just renamed, has been assigned users name - the old table name. It means that from now both instances of the application can fetch everything from this table using both users and participants name, so the new table name and the old one.

If our application starts up properly and all the instances will be replaced with the new one, we can create another migration which drops this PostgreSQL view, as it won't be required anymore.

defmodule Migrations.DropViewOnUsersTable do
    use Ecto.Migration

    execute("
        DROP VIEW users;
    ")
end

What about changing the column name?

Assuming that we deploy the application on two instances, we will face the same problem once we run a migration which renames the column on the first instance. The same problem as the one with changing a table name. The second instance, which hasn't been replaced yet with the new one containing new code, will use the old column name - the one which doesn't exist anymore in the database.

What can we do about it?

Do not rename the column - write a migration which creates a new one. Do all the steps which I described in my previous article entitled "How to migrate live production data" in order to implement these changes without any downtime.

This website stores cookies on your computer. The data is used to collect information about how you interact with our website and allow us to remember you. We use this information to improve and customize your browsing experience and for analytics and metrics about our visitors both on this website and other media. Cookie Policy Privacy Notice
Work together

Let’s Work Together!

Make the first step for a great partnership! Share your idea with us and check what we can do for you and your company.
AppUnite Sp. z o.o.
VAT ID: PL 7831689686
Droga Dębińska 3A/3
61-555 Poznań, Poland
+48 532 568 641
office@appunite.com
Clutch Top Developers 2020Clutch Top B2B Companies 2019Financial Times ranking of 1000 fastest-growing companies in EuropeDiament Miesięcznika Forbes