The Reactor is one of the most flexible and powerful features of the EVRYTHNG Platform, available as part of the Enterprise API. It lets developers write logic in JavaScript and associate it with a Platform application. That application then provides reactionary logic to certain types of events that occur to other types of resources, such as Thngs or actions.

These scripts run asynchronously, including any updates that occur because of a script execution. Take this into account when planning and developing a Reactor-based solution. Scripts can consist of many files and include other npm modules as dependencies, allowing a virtually free-form environment.

For a general introduction to Reactor, read the Reactor section in the API Reference, and come back here for a practical introduction.

📘

Note

This walkthrough assumes a basic understanding of some EVRYTHNG Platform resources, including projects, applications, and Thngs. You can read more about them in the API Reference section.


Example Use Cases

Reactor is most useful in scenarios where some programmatic logic can derive insights from raw data, react to discrete events, or enable deeper integrations with external APIs and services. Some general examples include:

  • Using a simple event to calculate and update more meaningful metadata on the resource. For example, Reactor can count the number of times a Thng QR code has been scanned or conditionally update custom fields or tags.
  • Detecting irregular stock movements when an action is created on a Thng that describes a stage in the supply chain. For example, Reactor can record an alert if the item is arriving at the wrong warehouse or is far away from the expected region (suggesting a shipment was stolen).
  • Keeping track of the number of items at each storage location to help predict or analyze potential stock-outs and optimize warehouse stock levels.
  • Enabling integration with external APIs and data storage systems. For example, Reactor could enable discount code generation and redemption, pull data from external sources, or notify other systems to some EVRYTHNG-related update. Using Reactor lets you drive deeper experiences for users.

Creating a Reactor Script

One Reactor script allocation is available per application. A single project can have many Reactor scripts if you create multiple applications inside it. Code inside the Reactor script can be virtually any Node.js v14 compatible code (see the limitations). Using the included package.json file, the script can require other Node/npm modules, vastly enhancing the possibilities and use-cases. For example, you can include the request module to talk to other external services and APIs, allowing complex integrations, or the jsonschema module to validate actions.

Code can be uploaded to an application Reactor in two ways and in two formats—through the API or in the Dashboard, as a plain-text string in a single file or in a .zip bundle. Uploading a script through the API allows integration with other tools and deployment systems. The bundle format allows more complex, multi-file scripts to be uploaded, including additional supporting data and files.

After new code has been submitted, the Reactor script is built and deployed to the Platform. During the update, no invocations occur. You can see the status of a Reactor script update on the Dashboard on the application page above the script editor (see ProjectName > Applications > ApplicationName > Reactor).

470

📘

Info

Some newer JavaScript conventions and syntax might trigger warnings when you paste the code in the Reactor, but the code works correctly when you run it.


Running a Reactor Script

An application's Reactor script is executed in response to one or more types of events. A handler function for each type of event provides the entry point where execution starts. For the script to run, at least one of the handlers below must be implemented in the main script file:

  • onActionCreated() - When an action is created on a Thng, product, or collection.
  • onThngPropertiesChanged() - When a Thng’s properties are created or updated.
  • onProductPropertiesChanged() - When a product’s properties are created or updated.
  • onScheduledEvent() - At a specific time or time interval. You can instead use a custom function name with the correct configuration.

See the example script below for examples of each of these. See the relevant section of the API Reference for more information about how these scripts are implemented.

Two important factors determine whether a Reactor script is executed:

  • The resource that's triggering it must be correctly scoped to the application's project. For example, an application in a hypothetical ‘Demos’ project only runs its Reactor script if the Thng being updated is also scoped to that project.
  • The authenticating API key making an event-triggering request must also be in the same project scope. Such a key could be the application’s Trusted Application API Key or an Application User API Key belonging to the same application.

When the script has finished, it must call the built-in global done() function, to inform the Platform that the operation is completed. Only then are any logs created with the built-in global logger object displayed in the Dashboard and available through the API. If this isn't called, logs don't appear, and an automatic retry is attempted, which could have unintended side effects.

In cases where many executions are triggered, we strongly recommend you use Reactor filters to specify when the script should and should not run, based on the properties of the resource that would have triggered it, before it's executed. For example, only a certain action type or property name.


Example Reactor Script

The following example Reactor script logs a message to the application’s Reactor logs when one of the types of events occurs. This is a good starting point for most Reactor script implementations.

Each of the corresponding event type handlers is present and unfiltered to receive all possible events. Note that done() is always called as expected to enable logs to be saved in the Platform.

// When an action is created
function onActionCreated(event) {
  logger.info(`Action created:\n${JSON.stringify(event)}`);
  done();
}

// When a Thng's properties have changed
function onThngPropertiesChanged(event) {
  logger.info(`Thng properties changed:\n${JSON.stringify(event)}`);
  done();
}

// When a product's properties have changed
function onProductPropertiesChanged(event) {
  logger.info(`Product properties changed:\n${JSON.stringify(event)}`);
  done();
}

// When a Reactor Schedule runs
function onScheduledEvent(event) {
  logger.info(`Scheduled event:\n${JSON.stringify(event)}`);
  done();
}
{
  "dependencies": {
    "evrythng-extended": "^4.1.0"
  }
}

Conclusion

Now that you have seen the basic concepts and a short example script, read the next section for a more in-depth look at some recommended patterns to build Reactor scripts yourself.