Giter Site home page Giter Site logo

sailor-nodejs's Introduction

elasticio-sailor-nodejs Build Status Dependency Status

The official elastic.io library for bootstrapping and executing for Node.js connectors.

NPM

elasticio-sailor-nodejs is a required dependency for all components build for elastic.io platform in Node.js. Add the dependency in the package.json file in the following way:

    "dependencies": {
        "q": "^1.4.1",
        "elasticio-sailor-nodejs": "^2.2.1",
        "elasticio-node": "^0.0.8"
    }

Building components in Node.js

If you plan to build a component for elastic.io platform in Node.js then you can visit our dedicated documentation page which describes how to build a component in node.js.

Before you start

Before you can deploy any code into our system you must be a registered elastic.io platform user. Please see our home page at http://www.elastic.io to learn how.

Any attempt to deploy a code into our platform without a registration would fail.

After the registration and opening of the account you must upload your SSH Key into our platform.

If you fail to upload you SSH Key you will get permission denied error during the deployment.

Getting Started

After registration and uploading of your SSH Key you can proceed to deploy it into our system. At this stage we suggest you to:

  • Create a team to work on your new component. This is not required but will be automatically created using random naming by our system so we suggest you name your team accordingly.
  • Create a repository inside the team to deploy your new component code.

Examples of Node.js components

Here is a list of components build on Node.js:

Sailor logging

Sailor uses bunyan logging framework.

Supported log levels are:

  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • TRACE

Default log level is INFO. You can change default log level with environment variable LOG_LEVEL.

Sailor logger adds the following extra context to log messages:

  • ELASTICIO_API_USERNAME
  • ELASTICIO_COMP_ID
  • ELASTICIO_COMP_NAME
  • ELASTICIO_CONTAINER_ID
  • ELASTICIO_CONTRACT_ID
  • ELASTICIO_EXEC_ID
  • ELASTICIO_EXEC_TYPE
  • ELASTICIO_EXECUTION_RESULT_ID
  • ELASTICIO_FLOW_ID
  • ELASTICIO_FLOW_VERSION
  • ELASTICIO_FUNCTION
  • ELASTICIO_STEP_ID
  • ELASTICIO_TASK_USER_EMAIL
  • ELASTICIO_TENANT_ID
  • ELASTICIO_USER_ID
  • ELASTICIO_WORKSPACE_ID

Component logging

Sailor exposes logger object for use in a component. Component logger inherits log level from sailor's logger and adds the following extra context to log messages:

  • messageId (unique ID of the next RabbitMQ message)
  • parentMessageId (unique ID of previous RabbitMQ message)
  • threadId (unique ID of execution thread)

Component logger usage example:

this.logger.fatal('message');
this.logger.error('message');
this.logger.warn('message');
this.logger.info('message');
this.logger.debug('message');
this.logger.trace('message');

Flow control

When working in the multi-tenant integration environment it's important to obey the API and consumption limits imposed by the platform. This is not only a condition for you integrations to run on the platform (and not begin suspended), but also a good integration practice to sustainably and efficiently use resources.

Imagine a system where one party (published) publishes to the queue and one or more consumers consume from the queue. If publishers are writing to the queue faster than consumers read data from the queue, queue will earlier or later be overfilled. Once one queue of your integration flow will grow to a particular limit, the complete integration flow will be suspended and author will be informed about it. Flow control is a build-in mechanism in the SDK that will help you to prevent the overflow to happen.

There are two types of flow control:

  • Static flow control - the hard limit of the events (e.g. messages published to the queue) that can be generated by component. This limit is dictated by your pricing plan and will limit protect the platform from extensive load.
  • Dynamic flow control - the limit that is imposed based on the state of individual queue, more messages are in the queue, slower publisher could write to it.

Let's take a look at the simple example:

'use strict';

exports.process = process;

async function process(msg, cfg, snapshot) {
    for (let i = 0; i < 100000; i++) {
        this.logger.info('Sending message %s', i);
        await this.emit('data', {
            body: {
                counter: i,
                hi: 'there'
            }
        });
        this.logger.info('Message %s was sent', i);
    }
}

This simple component, once started on the platform will generate 100k messages. Without flow control this example will quickly bring the integration queue to the limits and integration flow will be suspended. With flow control the publishing rate of the messages will be slowed down so both publisher and consumers will operate in balance.

How to configure it

There is a set of environment variables that are responsible for the configuration of the static flow control (dynamic flow control is implemented in the message-oriented middleware of the platform hence can't be configured on the component level)

  • ELASTICIO_DATA_RATE_LIMIT - a number of maximum data messages per second that could be emitted by the component

  • ELASTICIO_SNAPSHOT_RATE_LIMIT - a number of maximum snapshot messages per second that could be emitted by the component

  • ELASTICIO_PROCESS_AMQP_DRAIN, (boolean) - true value means that 'emit' method in component would return promise which will resolve to true value when amqplib inner buffer would be empty. Preventing OutOfMemoryError on buffer overflow.

Sailor hooks

Init hook

/**
* cfg - This is the same config as the one passed to "processMessage" method of the trigger or action
*/
exports.init = function(cfg) {
    //do stuff
    return Promise.resolve();
}

Startup hook

/**
* cfg - This is the same config as the one passed to "processMessage" method of the trigger or action
*/
exports.startup = function(cfg) {
    //do stuff
    const data = {
        message: 'Hello from STARTUP_HOOK'
    };
    return Promise.resolve(data);
}
  • Only on the first trigger

  • Called without this

  • May return promise

  • May return value

  • May throw - not recommended

  • May return a promise that will fail

  • Startup logs can be found in the tab of the component on execution page

  • TBD - Separate them under different tab in UI

  • TBD - Where to see restart errors?overwritten

Startup state data - either return value or the result of the promise

  • OK
    • Results will be stored as the startup state, previous will be overwritten with warning
    • After that init hook will be run, etc
  • NOK
    • Sailor will exit the process
    • Platform will restart the component immediately
    • If init wont' happen it will be removed after 5 minutes (see restart policy)
    • In the next scheduling interval initialisation will repeat

Shutdown hook

/**
* cfg - This is the same config as the one passed to "processMessage" method of the trigger or action
* startData - result from the startup
*/
exports.shutdown = function(cfg, startData) {
    //corresponding to the startup example above, startData is { message: 'Hello from STARTUP_HOOK' }
    //do stuff
    return Promise.resolve();
}
  • Only on the first trigger
  • One stop is pressed
    • If task is running then containers are shutdown
    • If task is sleeping then do nothing
  • Start new trigger container
  • Trigger starts without this context - it's not possible to log errors or send new data
  • Should either return value (ignored) or promise (resolved).
  • Startup data is removed after shutdown hook
  • Call the shutdown hook, parameters that are passed is from the startup results or {} if nothing was returned
  • Errors are ignored
  • If shutdown hook won't complete within 60 seconds then container will be killed
  • As soon as user pressed stop, task is marked as inactive and 'webhooks gateway' will start responding with the error (Task either does not exist or is inactive) to possible data

TBD - log for shutdown hooks?

sailor-nodejs's People

Contributors

a3a3e1 avatar allirey avatar andkom avatar anton-kotenko avatar bolgovr avatar danylo-felekevchuk-elasticio avatar denyshld avatar ellenaua avatar ghaiklor avatar irisked avatar khanzadyan avatar legendmiha avatar nazar910 avatar paulannekov avatar pnedelko avatar sdwvit avatar shkarupanick avatar skarbovskiy avatar vitaliykovalchuk avatar yarikos avatar zubairov avatar zuker avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sailor-nodejs's Issues

Name of environment variables can not be changed for white-labeling purpose

Description: Name of environment variables can not be changed for white-labeling purpose, for example ELASTICIO_API_KEY can not be changed to RIVERSAND_API_KEY

AR: Name of environment variables can not be changed for white-labeling purpose.

ER: Name of environment variables can be changed for white-labeling purpose.

Sailor does not reliably publish large messages

Bug Report

Description

When multiple large messages (that are still less than 10 MB) are published, they do not reliably arrive.

Preconditions

Deploy a version of the code component with sailor version 2.6.0 (such as this commit).

Environment

  • Popeye
  • Great Moraq (development)
  • Essos (stage)
  • Westeros (production)

Steps to Reproduce

  1. Create a flow of the from Code component with sailor 2.6.0 -> Code component with sailor 2.6.0
  • For the first step use the code snippet
async function run(msg, cfg, snapshot) {
  const longString = (new Array(1024*1024*7)).join('a');
  for(let i = 0; i < 10; i++) {
      var data = messages.newMessageWithBody({
          i,
          data: longString
      });
      await emitter.emit('data', data);
      this.logger.info(`Published message ${i}`);
  }
}
  • For the second code component use the snippet
async function run(msg) {
  const body = { result : 'Hello world!' };
  // You can emit as many data messages as required
  await this.emit('data', { body });
}
  • Manually save {} as both samples.
  1. Publish and run the flow.

Actual Result

  • Only a single message is produced every execution (for each component).
  • Text similar to the following appear in the logs indicating an error
    Buffer full when publishing a message to exchange=59b11ca941e98200195eb6e3_org with routingKey=59b11ca941e98200195eb6e3.5e173bb8129b6e0013a680bc/ordinary.step_1.message

Expected Result

  • 10 Messages are produced for each component on every execution.
  • No log statements about Buffer full appear in the logs.

Make sure sensitive data is not logged in components

Example of what should be fixed:
https://github.com/elasticio/elasticio/blob/0a290c8636aed69904eae0987cdd278b9cd1f8e2/tools/sailor-performance-analyze/sailor-nodejs/lib/sailor.js#L72

data that is logged by sailor-nodejs in components:

Received step data: 
{
  "id": "step_1",
  "comp_id": "5f6b54b68636120011b43b9f",
  "function": "httpRequestTrigger",
  "config": {
    "secretId": "5f6c7d69276f4800116ededd",
    "reader": {
      "auth": {
        "basic": {
          "password": "",
          "username": ""
        }
      },
      "body": {
        "contentType": "multipart/form-data",
        "urlencoded": [],
        "formData": [],
        "raw": ""
      },
      "headers": [],
      "url": "\"https://via.placeholder.com/150\"",
      "method": "GET"
    }
  },
  "is_passthrough": true,
  "variables": {}
}

Replace Q with native Promise

The engine specified in the package.json is modern enough to not use the Q, which was required when there was no native Promise in JS.

  "engines": {
    "node": ">=10.15.0"
  },

Static flow control (sailor)

Currently when component code does:

this.emit('data', {});

Message is encoded, encrypted and sent to RabbitMQ channel here. Unfortunately there are following problems with this use:

  1. Result of the publish method is ignored (it returns true or false, in case of false we need to wait for drain event)

  2. In the situations when component call emit faster than underlying RabbitMQ layer could serialize and send data out of memory we are getting memory management problem (OOMs)

  3. We have no way to limit the publishing rate to the queue which is an essential feature for flow control and (possibly) QoS enforcement

We need to fix that as following:

  • Make sure emit (as well as all other methods of sailor API that may result in networking operations e.g. snapshot) return a promise

  • Make sure we have a static rate limits for following operations:

    • Emitting data, default value 200 messages per second

    • Emitting errors, default value 20 per second

    • Emitting snapshots, default value 20 per second

    • Make sure all limits above can be changed from default value with help of environment variables

    • Make sure documentation for sailor is updated with information about rate limits as well as with information (example) on how to use them (e.g. use the await for the promise after each operation)

Sailor enhancement: have this.emit() function be defined consistently for all methods called through Sailor

The function this.emit() is only properly defined and working as intended in the process function. Either this.emit() should be defined consistently across all the functions Sailor parses, or at the very least there should be clear documentation regarding where this.emit is defined and where it is not.

Discrepancies within this.emit

At the moment, only in process does this.emit() correctly return a Promise.

In verifyCredentials, getMetaModel, and any Select Views function, this.emit() is defined, but is not an async function and does not return a Promise.

In init(), startup(), and shutdown() methods, this.emit() is not defined at all.

Please refer to the image below for more details:

image

For this issue to be resolved:

  • define this.emit for all of the functions above and ensure that it returns a promise (first two columns)
  • provide documentation in the Sailor README or elsewhere regarding which functions currently support using this.emit

Update Sailor Dependencies

As stated in #94, lodash needs to be bumped to at least version 4.17.11 or later.

Recommended to run npm-check on Sailor and check packages that can be updated or removed as well.

Deprecation warnings when using sailor

I can see this during npm install:

npm WARN deprecated [email protected]: use uuid module instead
npm WARN deprecated [email protected]: use uuid module instead
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

Passthrough step loss

In a specific scenario, passthrough can lose one of the previous steps data.

STR:
Flow with two consequent steps with new sailor (components deployed on 30th of January) components and then Transformation step in any place in the flow after them. Such a scenario will cause that after the Transformation step passthrough will lose data from the first step of the new sailor steps pair.

The easiest way to reproduce is to build flow with the next configuration:

  • Webhook
  • NodeJS component
  • Transformation
  • Replay

And if you specify $ in the reply body, you will see that there is no step_1 in the passthrough left.
image
In response you will see:

{
	"1": 1,
	"elasticio": {
		"step_2": {
			"body": {
				"result": "Hello world!"
			}
		},
		"step_3": {
			"id": "87f54d4f-4154-4d89-9f77-fe73ff6f6345",
			"attachments": {},
			"body": {
				"1": 1
			},
			"headers": {},
			"metadata": {}
		}
	}
}

Sailor should auto-rebound when it encounters an HTTP timeout in a component's process function

Feature Request

Description

As part of https://github.com/elasticio/elasticio/issues/5012 we started re-using http connections so that HTTP timeouts were avoided as a result of there being insufficient outbound IP ports. However, it is still possible in the internet for a certain amount of HTTP timeouts to occur. In principle, this could be solved by adding retry/rebound logic to the component code, however, in practice, this can become quite difficult & tedious (especially if an underlying code library is used). Ideally, Sailor could simply catch thrown exceptions which are caused by HTTP timeouts and auto emit a rebound in those cases.

Definition of Done

Whenever a component's action or trigger's .process() function throws an exception where err.message.code === 'ETIMEDOUT', then sailor should handle that message as a rebound as opposed to an error.

Sailor should be more tolerant of invalid `LOG_LEVEL` values

Consider the following cases:

  • A user enters IFNO as the LOG_LEVEL env var for a component
  • A user enters INFO (with lead space) as the LOG_LEVEL env var for a component
  • A user enters INFO, DEBUG as the LOG_LEVEL env var for a component (doesn't logging understand heirarchy)

Results in the following exception being thrown on virtually any action involving the component:

throw new Error(format('unknown level name: "%s"', nameOrNum));
(no message)
at resolveLevel (/home/apprunner/node_modules/elasticio-sailor-nodejs/node_modules/bunyan/lib/bunyan.js:293:19)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
/home/apprunner/node_modules/elasticio-sailor-nodejs/node_modules/bunyan/lib/bunyan.js:293
at Logger.addStream (/home/apprunner/node_modules/elasticio-sailor-nodejs/node_modules/bunyan/lib/bunyan.js:570:19)
at new Logger (/home/apprunner/node_modules/elasticio-sailor-nodejs/node_modules/bunyan/lib/bunyan.js:490:18)
at Function.createLogger (/home/apprunner/node_modules/elasticio-sailor-nodejs/node_modules/bunyan/lib/bunyan.js:1618:12)
at Object.<anonymous> (/home/apprunner/node_modules/elasticio-sailor-nodejs/lib/logging.js:36:20)
at Module.require (internal/modules/cjs/loader.js:952:19)
^
Error: unknown level name: "IFNO"
at Module._compile (internal/modules/cjs/loader.js:1063:30)

Ideally sailor should be more resillient and log an error while falling back to the defaults so that things don't catastrophically break on minor configuration errors.

We have a number of security issues in salior

See the nsp report:

(+) 4 vulnerabilities found
 Name      Installed   Patched                        Path                                                                 More Info                              
 debug     2.1.3       >= 2.6.9 < 3.0.0 || >= 3.1.0   [email protected] > [email protected]                   https://nodesecurity.io/advisories/534 
 ms        0.7.0       >0.7.0                         [email protected] > [email protected] > [email protected]        https://nodesecurity.io/advisories/46  
 request   2.57.0      >=2.68.0                       [email protected] > [email protected]                https://nodesecurity.io/advisories/309 
 hawk      2.3.1       >=3.1.3 < 4.0.0 || >=4.1.1     [email protected] > [email protected] > [email protected]   https://nodesecurity.io/advisories/77  

Sailor does not work if ELASTICIO_API_URI conatins / at the end

In case when env variable ELASTICIO_API_URI contains "/" symbol at the end (http://192.168.39.1:9000/) sailor sends incorrect request to api and fails with error:

Error happened: Cannot GET //v1/tasks/5aaa9ef8de5ff030189776dd/steps/step_1

Error: Cannot GET //v1/tasks/5aaa9ef8de5ff030189776dd/steps/step_1

    at checkStatusCode (/app/node_modules/elasticio-rest-node/lib/resource.js:104:29)
    at /app/node_modules/q/q.js:1249:26
    at _fulfilled (/app/node_modules/q/q.js:854:54)
    at self.promiseDispatch.done (/app/node_modules/q/q.js:883:30)
    at Promise.promise.promiseDispatch (/app/node_modules/q/q.js:816:13)
    at /app/node_modules/q/q.js:570:49
    at runSingle (/app/node_modules/q/q.js:137:13)
    at flush (/app/node_modules/q/q.js:125:13)
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)
```
Seams that  sailor just concatenates prefix of api uri and path to endpoint. This produces url with doubled '/'. What todo: use path module for concatenations. 

Wrap component trigger results into JsonObject

Wrap all results that are non-JSONObject into {"result": <message>}.

Currently, we implement this in components, but it makes sense to implement it once in the sailor, as there are already at least 2 components that have they wrapped results into JSONObject in theirs code: restapi, salesforce (Magic updates).

This will keep stable runtime mapper processing of messages at the next steps.

Preserve flow execution after 20 minutes if it do any activity

There is an issue with a flow processing that stops accidentally after 20 minutes of execution.
Here is a line in the code that describes a constant for timeout in case of Running flow after 20 minutes

const TIMEOUT = process.env.ELASTICIO_TIMEOUT || 20 * 60 * 1000; // 20 minutes

The case:

  1. Create a flow;
  2. First step generates an array with 7000 int values;
  3. Second step (code-component) emits each array item individually with delay (500 ms).
  4. Run a flow.

An execution will continue 20 minutes and it stop emit messages even if an amount is less than 7000.

As a solution, there should be checked any activity during last 20 minutes before firing a timeout operation in order to keep a flow alive if it is still doing any job.

Update Sailor README to include more relevant information for developers

A subset of updates that would be useful to make to Sailor README - there are probably more on top of this.

Emitter

Add a section on the Emitter, which functions it is currently available from, what each of the options does, what is supported, where/how they should be used, with what parameters, etc.

The options we currently have defined for emittter are

  • this.emit('data', ...)
  • this.emit('error', ...)
  • this.emit('rebound', ...)
  • this.emit('snapshot', ...)
  • this.emit('updateSnapshot', ...)
  • this.emit('updateKeys', ...)
  • this.emit('httpReply', ...) <- not currently used anywhere on platform
  • this.emit('end')

Environment Variables

Add a section on list of available environment variables, their purposes.
Add instructions on how to set env variables on the platform.

Hooks

The README already has a section on the startup, shutdown, init hooks - add a section perhaps for all the other functions Sailor looks for? e.g. verifyCredentials, process, getMetaModel, Select Views.
Also make sure the information in this section is still up to date and relevant/correct.

General

  • add more examples throughout
  • update existing code examples to reflect 2019 syntax
  • add known limitations section
    • e.g. if snapshot or emitted keys contains a Date object, this Date object is converted to an ISO string in future executions
  • consider publishing this page to the docs for relevant information on interacting with Sailor for developers to be easily accessible

updateKeys should work as intended from all functions

Emitting updateKeys should work as intended when called from

  • verifyCredentials
  • init
  • startup
  • shutdown (?)
  • getMetaModel
  • Select Views functions

Or, if we are not implementing it for a given function, this should be reflected somewhere in the documentation.

The reason for adding this function to all these methods is that there have been cases already where it would have been useful in verifyCredentials and getMetaModel. It makes more sense to add it to all available methods than have to possibly come back to this issue again in the future

See #57 for details regarding implementation for verifyCredentials

For this issue to be resolved

  • ensure updateKeys works as intended in verifyCredentials
  • ensure updateKeys works as intended in init
  • ensure updateKeys works as intended in startup
  • ensure updateKeys works as intended in shutdown
  • ensure updateKeys works as intended in getMetaModel
  • ensure updateKeys works as intended in Select Views

Switch on/off passthrough feature

Every high-loaded project brings us a problem with passthrough. The problem affects rabbitmq and overflows message queues by message count or by size.
The passthrough feature is not required sometimes, that's why will be great to switch off it in favor of performance.
This feature is highly important from prospective of development new sailor_v3: https://github.com/elasticio/sailor-nodejs/tree/v3 and could be implemented there.

Save 75% of platform message size ๐Ÿคฆ๐Ÿปโ€โ™‚๏ธ

This place here returns a string with base64 encoded string in it. Base64 binary is roughly 75% larger than binary data. The publish method that sends data to the queue accepts a binary Buffer so it makes little sense to send a based64 string over it.
BTW publish method copies the data, so data copied 3 times - here, here when new Buffer is created and here when data is published to the queue

The main problem here when fixing it - maintain backwards compatibility.

Sailor enhancement: set custom timeout length with env variable

Right now, Sailor has a static timeout time of 20 minutes, before it automatically calls a forceful program termination.

Two enhancements here could be made:

  • throw an error in Sailor if the timeout time is ever reached, rather than quietly ending the program
  • refactor the TIMEOUT value into an optional environment variable, with a default time of 20 minutes. The purpose of this is that the current timeout time is quite arbitrary, and may be useful in some situations to be able to change this value

Changes to make for this enhancement:

  • make Sailor throw a descriptive error when the timeout has been reached
  • add a SAILOR_TIMEOUT env variable to the settings with a default value of 20 minutes
  • use this variable in the timeout functions instead of the static one
  • investigate if anything on the platform side needs to be changed regarding environment variables???

Emitting errors should work, and they should be displayed on the platform

There are two different cases that need to be handled for this issue:

verifyCredentials

Right now, both throwing an error and emitting an error successfully will mark the provided credentials as incorrect, but an error message does not display to the platform in either case.

For example,

verify(credentials) {
  this.emit('error', 'Credentials are invalid');
  throw new Error('Credentials are not working!!');
}

will both mark the credentials are invalid, but in both cases the logs will not show any sort of error.

This has been further discussed in these issues:
#58
#68

For this issue to be resolved,

  • emitting an error from verify should both invalidate the credentials and display the error message
  • throwing an error from verify should both invalidate the credentials and display the error message

init, startup, shutdown

Building off of #112, for these three functions it should be investigated and discussed whether we should implement emit error. If we are not implementing emit error for this function at this time, it should be noted in documentation that these functions are not currently supported

For this issue to be resolved,

  • investigate the implementation if this.emit('error') for these functions - also see #109
  • investigate if any platform changes would be needed
  • implement the change, or add documentation accordingly

this.emit() is not defined for verifyCredentials

Often authentication code emits 'updateKeys'. Often verifyCredentials calls authentication code. Currently this.emit is undefined in this function. At the least, this function should be defined. Ideally, updateKeys events from verifyCredentials should be persisted.

Emit errors for exceptions caught by process.on('uncaughtException')

Consider an action in a realtime flow that looks like this:

let someCache;

async function populateSomeCache() {
  // logic to refresh cache
}

exports.init = async function (cfg) {
  return setInterval(populateSomeCache, 60000);
};

exports.process = function() {
  // Return some subset of the cache
}

Observe that if any exceptions occur in populateSomeCache() they will not be reported to elastic.io UI. A developer could add a try...catch block inside populateSomeCache() however, that is boiler plate that they may not want/remember to write and it's not clear how that user would emit events from there. If we modify our handling of process.on('uncaughtException') to try to emit userland exceptions, we can solve this problem.

Proposal: exposing the option to parallelize actions/triggers

By exposing functionality that allows multiple messages to run through actions in parallel (when it makes sense, for example, in lookup actions), we can increase the time efficiency of performing these actions.

To do this, we want to expose the RABBITMQ_PREFETCH_SAILOR env variable, which controls how many messages are read from the queue at once. This variable is currently defaulted to 1. It does not make sense for this to be set as an env variable, as it is dependent per action/trigger and not per component.

We could implement the following changes to allow parallelizing actions run on our platform:

  • read an optional parallelize: bool field in from component.json inside every action/trigger
  • if this field exists, read in a number from component.json that represents the number of messages that should be read in parallel at once. This number should default to a value greater than 1 (2?) if not set. It should also be able to be configured as a config field by a user, as it would be dependent on the amount of computing power available
  • the RABBITMQ_PREFETCH_SAILOR should be set now to this value to run that many messages available, each time. It should be deprecated as an env variable as it does not make sense to use in that context
  • documentation should be added to explain what actions should and should not be run in parallel
  • investigation should be done to determine the capacities of running messages in parallel and how to calculate them

Update Sailor Tests

I think there are a few changes it would be smart to make to Sailor's tests before we make any significant updates to Sailor itself (e.g. enhancements, bug fixes, inevitably fixing some of the old tech debts, etc). The details of what should be done and the reason for need are detailed below:

  1. Fix the existing broken tests. On master, there is one jasmine test that does not pass, and a few of the mocha tests seem to be failing

  2. Migrate existing Jasmine tests to Mocha Chai

  • while this might seem like unnecessary work, the benefits of migrating tests from Jasmine to Mocha is that it will make making changes to Sailor safer as it will be EASIER to test and EASIER to see what the tests currently cover and don't cover, and where tests are located for a given function/file
  • having both Jasmine and Mocha actively used in unit testing doesn't really make much sense, and it is confusing (and seemingly arbitrary) which framework covers which tests
  • converting the Jasmine tests to Mocha/Chai shouldn't take a massive amount of work since both frameworks use fairly similar syntaxes, but will be a matter of removing unneeded packages and changing some of the expect syntax. There is actually a little package here that might help with the converting process
  1. Consider migrating our gulpfile to npm scripts
  • same reasons as above, mostly. Gulp only really has one task, and it is to run the test-coverage framework Istanbul, which could be done through an npm script
  1. Investigate test coverage using Istanbul, make sure all of Sailor is covered by existing tests.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.