Part 3: Handling multiple processes
In this tutorial, we’ll show how a single Indigo project can handle multiple processes to help manage a warehouse. We will be able to:
- Track goods that are stored in the warehouse
- Record when employees enter and leave the warehouse
While related, these two features belong to distinct processes - but we are able to support them on the same Indigo network.
The full code for the project is available here: https://github.com/stratumn/indigo-tutorials/tree/part3-v0.1.1
Generating our project
We will generate a new project using the SDK, called warehouse
:
strat generate warehouse
Choose option 1 (type 1 then press enter) to generate a JavaScript project.
What would you like to generate?
1: A basic Javascript agent
2: A Stratumn configuration
? 1
It will prompt you for project settings such as your name. For the development store, choose the default option (Stratumn Indigo Node With File Store). For the development fossilizer, choose the default option (None). The rest of the settings are up to you.
When prompted for the list of process names, enter the names of the two
processes we want to handle: goods
and employees
.
List of process names: (separator ",")
? goods, employees
After the wizard is done generating our project, you can launch it locally by
running strat up
within the project’s directory.
cd warehouse
strat up
While the project is running, open a browser and navigate to
http://localhost:4000
. You should now see two processes: goods
and
employees
.
Defining our warehouse processes
Tracking goods
Open ./agent/lib/actions-goods.js
with your text editor of choice. Replace the
init
function to receive the name of the warehouse:
/**
* Creates a new warehouse goods tracker.
* @param {string} warehouse - the name of the warehouse
*/
init: function(warehouse) {
// Save the warehouse and initialize an empty map of items.
this.state.warehouse = warehouse;
this.state.items = {};
// Create the first segment.
this.append();
},
Next we’ll define an action for storing goods inside the warehouse:
/**
* Store a new item inside the warehouse.
* @param {string} id - a unique identifier for the item
* @param {string} description - a description of the item
*/
storeItem: function(id, description) {
if (!id) {
return this.reject('an id is required');
}
if (!description) {
return this.reject('a description is required');
}
// Make sure ID doesn't already exist.
if (this.state.items[id]) {
return this.reject('this item is already inside the warehouse');
}
// Insert new item.
this.state.items[id] = {
description: description
};
// Append the new segment.
this.append();
},
We want to make sure that warehouses have a name and the generated segment
contains an items
object, so let’s update our validation rules. Open
./validation/rules.json
and change the goods
section to:
"goods": [
{
"type": "init",
"schema": {
"type": "object",
"properties": {
"warehouse": {
"type": "string"
}
},
"required": [
"warehouse"
]
}
},
{
"type": "storeItem",
"schema": {
"type": "object",
"properties": {
"items": {
"type": "object"
}
},
"required": [
"items"
]
}
}
]
The json validation rules cannot validate that the elements of the items
object contain a description, so we still have to do this in our action’s method
code.
Let’s try it out. Open http://localhost:4000
in your web browser (refresh the
page if it was already open). Create a new map for the goods
process, and
store a few items in it.
Recording employees
Open ./agent/lib/actions-employees.js
with your text editor of choice. Replace
the init
function to receive the name of the warehouse, just like what we did
for goods:
/**
* Creates a new warehouse goods tracker.
* @param {string} warehouse - the name of the warehouse
*/
init: function(warehouse) {
// Save the warehouse and initialize an empty map of employee activity.
this.state.warehouse = warehouse;
this.state.employees = {};
// Create the first segment.
this.append();
},
Next we’ll define actions to track when employees enter and leave the warehouse:
/**
* Enter the warehouse.
* @param {string} employee - the name of the employee
*/
enter: function(employee) {
if (!employee) {
return this.reject('employee name is required');
}
// Initialize the employee activity record if needed
if (!this.state.employees[employee]) {
this.state.employees[employee] = [];
}
// Insert the current time.
this.state.employees[employee].push({
activity: "enter",
date: Date.now()
});
// Append the new segment.
this.append();
},
/**
* Leave the warehouse.
* @param {string} employee - the name of the employee
*/
leave: function(employee) {
if (!employee) {
return this.reject('employee name is required');
}
// Initialize the employee activity record if needed
if (!this.state.employees[employee]) {
this.state.employees[employee] = [];
}
// Insert the current time.
this.state.employees[employee].push({
activity: "leave",
date: Date.now()
});
// Append the new segment.
this.append();
},
We want to make sure that warehouses have a name and employees are correctly
stored in the segment, so let’s update our validation rules. Open
./validation/rules.json
and change the employees
section to:
"employees": [
{
"type": "init",
"schema": {
"type": "object",
"properties": {
"warehouse": {
"type": "string"
}
},
"required": [
"warehouse"
]
}
},
{
"type": "enter",
"schema": {
"type": "object",
"properties": {
"employees": {
"type": "object"
}
},
"required": [
"employees"
]
}
},
{
"type": "leave",
"schema": {
"type": "object",
"properties": {
"employees": {
"type": "object"
}
},
"required": [
"employees"
]
}
}
]
The json validation rules cannot check the content of the employees
array
elements, it can only validate that the resulting segment will have an
employees
field of type object
. We still need to validate in code that the
employee name is provided.
Let’s try it out. Open http://localhost:4000
in your web browser (refresh the
page if it was already open). Create a new map for the employees
process, and
store some employee activity in it.
Exercises
- Track goods that are removed from the warehouse
- Record the employees associated to each item action