Andriy Drozdyuk
Andriy Drozdyuk

Reputation: 61121

How do you initialize mnesia on production?

I'm using rebar3 to produce a release, but how do I initialize mnesia on production?

If I write an "install" escript that does the mnesia:create_schema([node()]) - it will use a completely different node name from the one that release uses.

So I end up creating a schema for "nonode@nonode" while production mnesia when I start my app with my-app-1.0.0 start tries to access "myapp@localhost" node.

Also, it is kind of a chicken-and-egg problem:

  1. I can't start up my app without mnesia tables
  2. I can't install my mnesia tables without my app running (as the same node() name as the app will use).

Just wandering if there is a good way to handle this?

Here is my install escript that I run independently:

#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp enable ls-mnesia debug verbose
-include("../include/rr.hrl").

main(_) ->
    application:set_env(mnesia, dir, "/usr/local/src/db/mnesia"),
    application:stop(mnesia),
    install([node()|nodes()]).

install(Nodes) ->
    case mnesia:create_schema(Nodes) of
        ok -> 
            rpc:multicall(Nodes, application, start, [mnesia]),
            read_store_create_tables(Nodes),
            event_store_create_tables(Nodes),
            rpc:multicall(Nodes, application, stop, [mnesia]);
        Err -> 
            error_logger:warning_msg("Could not create schema: ~p~n", [Err]),
            Err
    end.    

event_store_create_tables(Nodes) ->
    {_, ok} = mnesia:create_table(rr_events,
            [{attributes, record_info(fields, rr_events)},
             {disc_copies, Nodes},
             {type, bag}]).

read_store_create_tables(Nodes) ->
    % Initialize the actual data-tables for the projections
    {_, ok} = mnesia:create_table(rr_competencies,
            [{attributes, record_info(fields, rr_competencies)},
             {disc_copies, Nodes}]).

P.S.: I am using rebar3 which uses relx to build releases.

Upvotes: 3

Views: 1230

Answers (1)

Greg
Greg

Reputation: 8340

I am using my own build system which was written mainly because of that exact requirement - ability to install and initialize a node before starting it. The idea is quite simple: there are two releases, in this particular example called cmd and humbundee. The cmd release doesn't start the main applications, only loads them. Then a special function is executed to initialize the node. The function is configured in the reltool.config file. In this case it's hbd_setup from the deploy application. That function reads the configuration file and either creates and initializes the mnesia database from a backup or creates a new database if the backup doesn't exist. Once the node is installed it's started using the proper release. The same steps are executed in development (directly from the source code) and in production (from an OTP release).

With that setup the problem you described doesn't exist because both releases are started from the same location, using almost the same command and configuration files (builderl generates them from the configuration in reltool.config).


You could employ the same idea with any build tool, including rebar3 and relx, by executing these steps manually or with some sort of a script.

What builderl does is that it executes these steps automatically and provides an environment to execute them in the same way in development and production, e.g. see the bottom of the humbundee project's README file:

Install the node. This will start the cmd release and execute the hbd_setup:install/2 function to initialize the node:

./bin/init.esh

Start the node. This will start the humbundee release, which starts all applications with their corresponding supervisor trees:

./bin/start.esh

builderl actually uses rebar to pull and compile dependencies that depend on other projects, however it uses only OTP to create the release. It can also download dependencies itself using a project-wide dependency file, which are then compiled with make (compiling without the make is work in progress). I hope that helps.

Upvotes: 1

Related Questions