/txjs

Dynamic nodejs transaction processing engine with REST api

Primary LanguageJavaScript

txjs

Dynamic nodejs transaction processing engine with REST api

Getting Started

Create a collection of actions with the following interface:

$ cat example/actions/log.js

async function execute(context) {
  console.log({ context });
  return true;
}

async function unexecute(context, error) {
  console.log({ context, error });
  return true;
}

module.exports = {
  name: 'log',
  execute,
  unexecute,
}

Mount these to /actions in the expelledboy/txjs docker image:

$ cat example/docker-compose.yml

version: '3.4'

services:

  mongo:
    image: mongo:latest
    restart: always
    volumes:
      - data:/data/db
    ports:
      - 27017:27017

  api:
    image: expelledboy/txjs
    ports:
      - 3000:3000
    volumes:
      - ./actions:/actions
    depends_on:
      - mongo
    environment:
      - NODE_ENV=production
      - SYSTEM_PASSWORD=secret
      - DEBUG=tx:*
    command:
      npm start

volumes:
  data:

Send a transaction specification to the REST API:

$ cat example/test.sh

#!/bin/bash

source .env

read -r -d '' TRX <<EOF
{
  "trx_id": "$(uuidgen)",
  "actions": [
    {"name":"log","params":{"data":true}}
  ]
}
EOF

curl -v \
	-u system:secret \
	-H 'content-type: application/json'\
	"http://localhost:3000/api/transaction" \
	-d "$TRX"

The result of the transaction might look similar to:

{
  "status": "completed",
  "resolved": true,
  "results": [true]
}

Where the results list order correlates to each action.

Or if there was an error during that step:

{
  "status": "rolledback",
  "resolved": true,
  "results": [
    {
      "status": "rolledback",
      "result": true,
      "error": {"perform":{"name":"Error","message":"myCrash"}}
    }
  ]
}

Specification

Transaction

- UUID trx_id
- LIST<Action> actions
- INTEGER timeout (optional)

Action

- STRING name
- MAP<STRING,STRING> params

The params can also include key value pairs that allow introspection into results of actions already executed in the transaction.

Lets take the following Transaction specification:

{
  "trx_id": "40863B4E-8BC8-4C35-9425-2C01D58EC5B3",
  "actions": [
    {"name":"get_accounts","params":{}},
    {"name":"check_balance","params":{}},
    {"name":"get_accounts","params":{}},
    {"name":"pay","params":{"_from_account":"_.get_accounts[1].accounts[0]"}}
  ]
}

Where 'get_accounts' resolved twice with the result:

{
  "accounts": [
    "loan",
    "cheque"
  ]
}

The params passed to the 'pay' action will be:

{
  "from_account": "loan"
}