Component lifecycle and prioritization

When working with a Thorin component or accessing another part of the application from within a component, it is important that you now how the core module will load them up.

Booting up

The Thorin core module acts as a global singleton (placed under global.thorin for convenience). Therefore, whenever you launch your thorin app using node app.js --env=development, and require('thorin'), it will perform the following steps

  • Gather information about the environment, such as the application's root path, extract information from package.json, parse the running environment mode, parse any command-line arguments and give your application a name.
  • Bootstrap the thorin singleton instance, loading up all core sanitizers, interfaces, validate the .gitignore to include the .thorin persist file, load up all core utilities and functionality
  • From the moment you require('thorin'), until the moment you call thorin.run(), it will register all the components that you add via addTransport, addStore, addPlugin, addLibrary, addSanitizer or addErrorParser
  • The moment you call thorin.run(), it will start running all registered components and start the application (see below).
Component lifecycle

Once you've called thorin.run(), the initialization process begins and the following steps will be taken

  • Load up the application's configuration data, from the registered sources, then merge them together into a single config object
  • Creates all the registered components by following the priority list below.
    • Create all registered sanitizers
    • Create all registered stores
    • Create all registered libraries
    • Create all registered transports
    • Create all registered plugins
  • For every component loaded, verify if it exports a init() function. If so, call it. This is the moment where you can access the state of other components, by listening to their init or run event. Note that this is a synchronous call.
  • Load and require any application action, middleware or file that was added via thorin.loadPath()
  • If our application is run with the --setup flag, check if we have to setup all components, or just specific ones. Depending on the case, verify if the selected components have a setup() function exported and call it. As this is an asynchronous call, we will pass a callback function to setup() and each component should call it once it's done setting up, with the standard callback(error, null). Note that this is a asynchronous call.
  • For every component loaded, verify if it exports a run() function. If so, call it and pass it a callback as callback(error, null). This is the time where components should initialize any kind of external connection, perform binding or do any kind of file altering, since the call is done asynchronously.
  • If at least one component encountered any kind of error in the lifecycle, stop the booting and call thorin.run's callback with the encountered error. Otherwise, the application should be up and running in a stable state.
Thorin core events

During the startup period of a Thorin app, on every step of the way and for each component, thorin will emit a specific event. You can tap into these events by calling thorin.on({eventName}, {componentName} callback). The following events are triggered:

  • init - triggered right after calling the init() function of a given component.
  • setup - triggered right after a component has finished setting up, as a result of the setup() call.
  • run - triggered right after a component has finished its running process, as a result of the run() call.

The above core events are available only in the boot period of a thorin app, and are triggered exactly once for each component. A short example can be seen below.

'use strict'
const thorin = require('thorin');
// Add the SQL store and the HTTP transport
thorin
   .addStore(require('thorin-store-sql'))
   .addTransport(require('thorin-transport-http'));

// Capture the init event for our SQL store.
thorin.on(thorin.EVENT.INIT, 'store.sql', (storeObj) => {
   log.info(`SQL store initialized but not yet connected to store`);
});

// Capture the run event for our HTTP transport
thorin.on(thorin.EVENT.RUN, 'transport.http', (transportObj) => {
   log.info(`HTTP web server is binded and accepting connections`);
});
// Capture the moment when thorin finished calling the init() function of ALL our registered components.
thorin.on(thorin.EVENT.INIT, () => {
   log.info(`All components successfully initialized`);
});

thorin.run();
Do you have a question or is something missing?

You can always create a new issue on GitHub or contact one of the core founders by chat.