Zenaton is a tool designed to greatly simplify execution and management of long running tasks. You can see it as a much simpler but more powerful version of Airflow. To demonstrate how Zenaton works, we will focus on a simple but reasonably realistic use case: a workflow to collect rent from an apartment tenant. It goes like this:

  • Send an email to remind the tenant to pay the rent.
  • Wait for the payment for up to two weeks.
  • If no payment has been received, notify the apartment’s owner.

Introduction

The Zenaton stack revolves around two entities: the workflow and the tasks.

You can write a task with your favorite programming language, like Javascript, as:

module.exports.handle = async function (...input) {
    return 42;
};

This one is very simple, but it could contain much more: calling databases, sending emails, logging… You name it.

Workflows are like scenarios that describe how tasks must be orchestrated: in what order, under which conditions… To define a workflow, Airflow asks you to define a Directed Acyclic Graph. To be easier and more versatile, Zenaton lets you directly code it in your favorite language.

module.exports.handle = function* (...input) {
  yield this.run.task("SimpleTask", ...inputA);
};

Zenaton has many advantages for the developer:

  • Simplified infrastructure. You no longer carry the burden of managing a job scheduler and a message broker. Everything is handled and hosted for you. You just have to code.
  • Out-of-the-box monitoring, with the capability to retry failed tasks with a simple button click, as well as pause, resume or kill your workflows at will.
  • No weird DSL. You can program your business logic using your favorite language: javascript, PHP, Python, Ruby (soon .NET and Java).

Our use case

For our example, the workflow can be simply written as:

module.exports.handle = function* (...input) {
  yield this.run.task("AskForRentPayment", ...inputA);
};

  const event = yield this.wait.event("RentPaid").for(2*7*24*3600);

    if (event) {
      yield this.run.task("SlackPayment", ...data);
      return;
    }
  yield this.run.task("NotifyOwnerOfNonPayment", ...data);
});
  • handle generator describes the tasks orchestration. Zenaton provides a wait function to manage time-sensitive executions. Here, the workflow is waiting for a “RentPaid” event, but for no more than 2 weeks. AskForRentPayment,NotifyOwnerOfNonPayment and SlackPayment are tasks that do what their name describes.

To start a new instance of this workflow, you just have to dispatch it:

const id = `TENANT#${tenantId}-PLACE#${placeId}-MONTH#${month}-YEAR#${year}`;

zenaton.run.workflow("CollectRent", { tenantId, placeId, month, year });

The interesting part in this workflow is the ability to wait for two weeks (without a scheduler or cron job!) for a RentPaid event that can be emitted at any time and induce the execution of the rest of the workflow. For example in an Express middleware:

const express = require("express");
const client = require("./client");

const app = express();

app.post("/pay-rent/:placeId/:tenantId", (req, res, next) => {
  const { placeId, tenantId } = req.params;
  const { month, year } = req.query;
  const id = `TENANT#${tenantId}-PLACE#${placeId}-MONTH#${month}-YEAR#${year}`;
  
  const selector = zenaton.select.workflow("CollectRent");
  selector.send("RentPaid", ...<event data>);

});

Following an HTTP call informing us that the rent has been paid, we emit a RentPaid event to the corresponding instance of RentWorkflow. The workflow will then resume its execution and end.

Conclusion

The example shown here is very simple, and Zenaton allows for much more convoluted and complex business logic. You can find all the information required to jump aboard in the documentation.

If you want to play with the code and experiment with the Zenaton API, you can download the full implementation here.

You can also download more examples from the NodeJS Zenaton GitHub example repository (available in other languages as well).

If you have any questions, feel free to contact me or the Zenaton team at any time.