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:

  1. Track goods that are stored in the warehouse
  2. 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.2.0

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(warehouse) {
    // Save the warehouse and initialize an empty map of items.
    this.state.warehouse = warehouse;
    this.state.items = {};

    // Create the first segment.
    return 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(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.
    return 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(warehouse) {
    // Save the warehouse and initialize an empty map of employee activity.
    this.state.warehouse = warehouse;
    this.state.employees = {};

    // Create the first segment.
    return 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(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.
    return this.append();
  },

  /**
   * Leave the warehouse.
   * @param {string} employee - the name of the employee
   */
  leave(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.
    return 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.

Referencing segments

We are tracking employees and goods in two separate processes. That is good, but it would be nice to be able to link them together. Imagine for example that we would like to know which employee stored which item. We will leverage the built-in refs feature, where a segment can reference other segments.

Let’s simulate a possible flow to record that information. First of all, Bob enters the warehouse: let’s create a segment in the employees process recording that event.

Bob enters warehouse

Note the linkHash of that segment (here it’s a5c0449c96941a6faa1baa3f68925ee3e713e313fcc05c67da8e83f9b1ee20bb).

Then Bob stores a book: let’s create a segment in the goods process. But this time we’ll click the button at the bottom of the pop-up to reference the segment recording Bob’s entrance.

Bob references segment

We can see that the generated segment contains a reference to the previous segment, displayed in red.

Mapexplorer reference

This feature can be very useful to implement complex real-life scenario.

Exercises

  1. Track goods that are removed from the warehouse
  2. Record the employees associated to each item action