Risen.JS

Risen.JS

  • Docs
  • Tutorial
  • API
  • Help

›API Reference

Introduction

  • Quickstart
  • Overview
  • Philosophy
  • Security
  • Terminology

Tutorial

  • Setting Up
  • Initialise Project
  • Prime Service
  • Render Service
  • Configure Framework
  • See Results

API Reference

  • Constructor
  • Instance
  • Services
  • Global Methods
  • Data Structure
  • Codes

Constructor

The Risen class

 new Risen(options);

The options arguments represent all the settings that are passed to the constructor Risen. This is used to create and return an instance of Risen.JS which you can then use to build your framework.

Returns: RisenInstance

constructor

Parameters

options

default
{
  address: "localhost:8080",
  mode: "server",
  http: false,
  databaseNames: ["_defaultTable"],
  verbose: true,
  maxBuffer: 50, // in megabytes
  logPath: void 0,
  restartTimeout: 50,
  connectionTimeout: 1000,
  msConnectionTimeout: 10000,
  msConnectionRetryLimit: 1000,
  address: "localhost:8080",
  portRangeStart: 1024,
  portRangeFinish: 65535,
  coreOperations: {},
  runOnStart: []
}
description
  • address [string|number] - This is the address of the service core where it will listen for new connections. We recommend always including a host otherwise if you specify just a port the service core will bind to 0.0.0.0.
  • mode [string] - This tells which mode the particular Risen.JS instance will operate under. "server" will have the instance run like a server. "client" mode will not start the Risen.JS instance. Both modes give you access to Global Methods.
  • http [bool] - Please see HTTP Configuration section.
    databaseNames [array] - The number of databases you want in the Risen.JS instance. Once declared you can use the method defined in this section to create/modify/delete data. Please see the storage section for more details.
  • verbose [bool] - Whether to print more verbose logs of what the instance is doing. Note this does not affect what the client will see for security reasons.
  • maxBuffer [number] - This option specifies the largest number of bytes allowed on stdout or stderr combined. If this value is exceeded, then the service instance is restarted.
  • logPath [string] - If you want to log to a file what you would see in the console. If you want more information set { verbose: true }.
  • restartTimeout [number] - How long to wait before restarting a service instance (in ms).
  • connectionTimeout [number] - How long to wait while attempting to acquire a connection to the service core before trying again (in ms).
  • msConnectionTimeout [number] - How the service core should wait while it attempting to connect to a service instance before timing out and returning an error to the source.
  • msConnectionRetryLimit [number] - How many times the service core should try to acquire a connection to a service instance if the connection is rejected before returning an error to the source.
  • address [number|string] - The main address where the service core listens to new connections.
  • portRangeStart [number] - What port the service core should begin while trying to find a free port for a service instance.
  • portRangeFinish [number] - What port the service core should end its search if it cannot find a free port. At this point, the service core will throw an error.
  • coreOperations [object] - This follows the same structure as defining operations for services. You can add new functions here which will be available for any instance (including the service core) to use. Please see the Service Core Operations section for the default core operations.
  • runOnStart [array] - What core operations you want to be executed on start-up to perform a function of your choice. This would be for example where you would put any polling if you were so inclined.
  • onConRequest [function] - A function that is executed when a connection is received by the service core.
  • onConClose [function] - A function that is executed when a connection is closed by the service core.

To bind below ports 1024 you need to have privileged access.

mode

server

To start the Risen.JS as a server you do:

{
  mode: "server",
  ...
}

client

You can use the constructor above to also create a client version of Risen.JS.

This means if you have Risen.JS running elsewhere you can initialize a separate class in client mode and as long as the address on both instances is the same you can send requests to it.

So assuming you have a Risen.JS application running elsewhere on the address localhost:8081 you can:

const risenClient = new Risen({
  address: "localhost:8081",
  mode: "client",
  verbose: false
})

risenClient.request(
  {
    body: null,
    destination: "exampleService",
    functionName: "echoData"
  },
  (data) => {
    // You would get your data here
    console.log(data);
  }
)

Please go to the Global Methods section to see what other methods will be available to you.

coreOperations

Please see the Service Core Operations section for more details on the default service core operations. This object takes the same form as a service definition. It's a collection of functions within an object.

For example, if you define this in your initial configuration it will be bound to the service core the same way as the default service core operations:

function saveStartupTime({ request }) {
  return request({
    body: {
      method: "set",
      table: "_appStats",  // Ensure this table is defined when you initialise your Risen.JS instance
      args: [`lastStartupTime`, Date.now()]
    },
    destination: "serviceCore",
    functionName: "storage"
  });
}

function getServiceData({ sendSuccess }) {
  return sendSuccess({
    result: this.serviceData
  });
}

const coreOperations = {
  saveStartupTime,
  getServiceData
};

const risenInstance =  new Risen({
  coreOperations,
  databaseNames: ["_appStats"],
  mode: "server",
});

Custom functions must be defined with the function keyword not the named arrow function pattern if you want to access information on Risen.JS using the this keyword.

In this example if you want to communicate with the service core custom operation you've just defined called getServiceData you would do:

{
  destination: "serviceCore",
  functionName: "serviceCore",
  body: null
}

You would pass this command object as an argument to the methods described in the Global Methods section.

runOnStart

This is a useful feature if you want a service core operation to be executed when the Risen.JS instance is started. You may want to do this too, for example, begin polling a database or perform a single initialization function.

Looking at the above example there is a custom service core operation called saveStartupTime() which saves the time which the Risen.JS framework started up in persistent storage. To run this function on startup you would do:

const risenInstance =  new Risen({
  coreOperations,
  databaseNames: ["_appStats"],
  mode: "server",
  runOnStart: ["saveStartupTime"]
});

This would execute this function when the framework starts. The full parameters of this function are described in the Global Methods section.

HTTP Configuration

Risen.JS allows you to define multiple instances of express as well as exposing the express instance itself for deeper configuration. This must be an array of configuration containing HTTP options described below:

Below HTTP capabilities are disabled and you will need to start a separate Risen.JS instance in client mode & matching address to communicate with the framework:

{
  http: false
}

In this case, because we specified an HTTP server we can communicate to the Risen.JS application via this as well as directly with a Risen.JS instance in client mode:

{
  http: [
    {
      host: "localhost",
      port: 8888,
      ssl: false,
      harden: true,
      beforeStart: (express) => express,
      middlewares: [],
      static: [],
      routes: []
    }
  ]
}

The idea of having multiple Express servers running on different ports in one framework allows you to segregate access to Risen.JS framework as you see fit.

You may, for example, expose one Express server designed to communicate with an external environment while having another for strictly localhost use, having your route handlers setup appropriately.

The beforeStart and middlewares are very powerful as they allow you to have full control of the express object before it's used. beforeStart gives you the express instance where you can do what you want with it. The middlewares allow you to add middlewares to express.

ssl

The framework allows starting an Express server via HTTPS. The configuration would look like so in that case:

{
  http: [
    {
      host: "localhost",
      port: 8888,
      ssl: {
        key: "<YOUR_PATH>/server.key",
        cert: "<YOUR_PATH>/server.crt",
        ca: "<YOUR_PATH>/server.pem"
      },
      harden: true,
      beforeStart: (express) => express,
      middlewares: [],
      static: [],
      routes: []
    }
  ]
}

options.http

example
{
  host: "localhost",
  port: 8888,
  ssl: false,
  harden: true,
  beforeStart: (express) => express,
  middlewares: [],
  static: [],
  routes: []
}
description
  • host [string] - The express host to bind on.
  • port [number] - The express port to listen on.
  • host [string] - If you want to bind to a specific address. If omitted it will bind to 0.0.0.0 (all interfaces).
  • ssl [bool|object] - Whether HTTPS will be enabled. false will run the Express server in HTTP and supplying an object (e.g. { key: "", cert: "", ca: "" }) will switch to HTTPS. The ca property is optional.
  • harden [bool] - This hardening follows the guidance from this link.
  • beforeStart [function] - Allows you access to the express instance before initialization.
  • middlewares [array] - If you want to apply middleware to your express instance before initialization.
  • static [array] - Allows you to serve static content, relative to the folder where Risen.JS is executed.
  • routes [array] - Please see Route Alias Configuration on how you map incoming requests to services.

routes

Routes are defined as a collection of objects within an array. Below are the options for each route. You will need to do this for each uri/method combination.

options.http.routes[...]

example

A typical route object may look like this:

{
  method: "get",
  uri: "/",
  preMiddleware: [],
  postMiddleware: [],
  handler: (req, res, next, { request }) =>
    request(
      {
        body: { query: "xyx" },
        destination: "dbService",
        functionName: "searchNames"
      },
      (data) => res.send(data);
    )
}

The handler (or HTTP route handler) property will receive the same parameters you would with a typical route in the Express server.

A fourth parameter is an object which contains methods described in the Global Methods section of this documentation.

If you are going to be, for example, sending an HTTP body with your request it's advised to add a middleware to the express configuration of the server to help with this such as body-parser. It will make dealing with this data easier at this stage.

description
  • method [string] - The method of the URI, case sensitive. Allowed values are "get"|"delete"|"post"|"patch"|"put"
  • URI [string] - The URI in which this route will be mapped.
  • preMiddleware [array] - Any middleware you want the request to pass through before running your HTTP route handler.
  • postMiddleware [array] - Any middleware you want the request to pass through after running your HTTP route handler.
  • handler [function] - This is where you link express with the framework. It’s here where you receive an HTTP request from a client, you then send a command to your chosen service, receive a response from the service, and send the data back to the client via res.send() o.e.

Service Core Operations

Service core operations work exactly as they do in the services themselves and receive the same parameters.

The only difference is they are executed in the service core process, so if you are not careful you could block your framework if you do something CPU intensive, stopping further communication.

You can call these methods from anywhere. Below is the command object you need to pass to one of the methods described in the Global Methods section:

To access these methods below your destination should always be set to serviceCore. This also applies to any service core custom operations you have defined as well when you initialized the Risen.JS instance.

end

This function shuts down the Risen.JS microservice framework. The service instances are shut down first and then the service core. The command object looks like this:

{
  destination: "serviceCore",
  functionName: "end",
  body: null // Nothing is required
}

storage

This is the operation that provides access to persistent storage for a running Risen.JS instance. All storage operations only happen on the service core ensuring synchronization.

The storage is powered by Quick-DB so please have a look at available methods to use. The command object looks like this:

{
  destination: "serviceCore",
  functionName: "storage",
  body: {
    method: "set" // See a full list by visiting the above link
    table: "_defaultTable", // Make sure you have defined the "table" in the when you initialised Risen.JS or you will get an error.
    args: ["randomNumber", 1024] // Arguments will change depending on the method, these will be spread across the Quick.DB method
  }
}

Because you can initialize multiple tables at start-up you can separate your data as you need. The data will be stored in a json.sqlite file in the __dirname folder.

changeInstances

This is one of the key core operations in Risen.JS because this service core operation allows you to increase and decrease the instance count of any services you have already defined during runtime.

This means it’s possible to have a service dedicated to monitoring load and increasing/decreasing the instance count of various services where necessary. How you implement this is up to you.

The command is very simple, define the name of the service you want to change the instance count, and define how many instances you want to add/remove.

Adding Instances

The command object for adding 3 instances to a service:

{
  destination: "serviceCore",
  functionName: "changeInstances",
  body: {
    name: "exampleService" // The name of the service
    instances: 3 // The number of instances you want to add
  }
}

Removing Instances

The command object for removing 3 instances to a service:

{
  destination: "serviceCore",
  functionName: "changeInstances",
  body: {
    name: "exampleService" // The name of the service
    instances: -3 // The number of instances you want to remove
  }
}

Note that if you only have 2 instances and request to remove 5 the service core will stop all remaining instances, effectively shutting down this service. You can always start them back up at any point during runtime.

← See ResultsInstance →
  • The Risen class
    • constructor
    • mode
    • coreOperations
    • runOnStart
  • HTTP Configuration
    • ssl
    • routes
  • Service Core Operations
    • end
    • storage
    • changeInstances
Topics
QuickstartOverviewPhilosophySecurityTerminology
Community
Code RepositoryIssuesPull RequestsStack Overflow
Links
NPMBuild StatusLicence StatusDependenciesGitHub Repo stars
Facebook Open Source
Copyright © 2018 - 2021 David Makuni