Performing Migrations Using Boot Scripts in Elixir 1.9

I am using Elixir 1.9 and it’s release structure to deploy a Phoenix application, and I’m having some trouble getting migrations to trigger on start of the application. So far, I’ve been manually running a migration task within a module before running start, but I’m hoping for a more modular solution.

I noticed that that MixRelease struct has a :boot_scripts field. However, I can’t find any examples on exactly how it should be used. I was wondering if it would help me bundle any pre-launch tasks though within my application cleanly, and how exactly I could do that. Could anyone advise me?

Thank you.

If you are looking for a good example of performing DB migrations, you can leverage the work done in hex.pm as a reference: https://github.com/hexpm/hexpm/blob/master/lib/hexpm/release_tasks.ex#L36

And then run the release task defined function via eval as seen in this section of the docs: https://hexdocs.pm/mix/Mix.Tasks.Release.html#module-one-off-commands-eval-and-rpc

3 Likes

I currently have this, which I believe is similar.

 def migrate do
    start_services()

    path = Application.app_dir(:my_app, "priv/repo/migrations")

    IO.puts "Running migrations: #{path}"
    Migrator.run(Repo, path, :up, all: true)

    IO.puts "Ran migrations successfully."

    stop_services()
  end

  defp start_services do
    Application.load(:my_app)

    IO.puts("Starting dependencies..")
    # Start apps necessary for executing migrations
    Enum.each(@start_apps, &Application.ensure_all_started/1)

    # Start the Repo(s) for app
    IO.puts("Starting repos..")
    Enum.each(@repos, & &1.start_link(pool_size: 1))
  end

Is there any way to ensure this is always invoked though at boot time? I was under the impression it’s possible to tie this together with /bin/my_app start so that I don’t have to call separate commands.

I might just be mistaken on the best practice as far as this goes, however.

If you want to ‘always’ call it on boot, then just put it in a gen_server that is launched after the DB loads in the dependency tree, and then return from the start when the migration is complete, then you can just shut the gen_server down (transient or temporary or so).

1 Like

This sounds like a really good solution, thank you!

1 Like