gin

gin is a simple distributed workflow engine, including task brokerage and staefulness, written in go.

It contains three components; of which there may be a multitude of instances:

And a couple of dependencies:

A workflow is made up of tasks and variables and collated in a runner which stores state via a simple state machine.

Master and Job nodes may be run right out of the box. Job nodes, however, come with very few configured jobs out the box and so it becomes simpler to create a project which initialises a JobManager object.

who what
dockerhub https://hub.docker.com/r/gincorp/gin/
circleci https://circleci.com/gh/gincorp/gin
licence MIT

Master Nodes

Master nodes are run with:

$ gin -mode master -amqp amqp://guest:guest@localhost/vhost -redis redis://localhost:6379/0

Or via docker:

$ docker run -p8080:8080 jspc/gin -mode master -amqp amqp://guest:guest@localhost/vhost -redis redis://localhost:6379/0

Master nodes compile and broker workflow tasks via a runner.

Job Nodes

Job nodes are run with:

$ gin -mode job -amqp amqp://guest:guest@localhost/vhost

Or via docker:

$ docker run -p8080:8080 jspc/gin -mode job -amqp amqp://guest:guest@localhost/vhost

Job nodes receive formatted tasks via rabbitmq, execute the task and return outputs and metadata.

API Nodes

API nodes are run with:

$ gin -mode job -amqp amqp://guest:guest@localhost/vhost -redis redis://localhost:6379/0 -host 0.0.0.0 -port 8080

Or via docker:

$ docker run -p8080:8080 jspc/gin -mode job -amqp amqp://guest:guest@localhost/vhost -redis redis://localhost:6379/ -host 0.0.0.0 -port 8080

API nodes provide an interface to the engine; for starting and configuring workflows.

Note: There is no auth-n, auth-z nor much of anything in front of the API. You should either use an API gateway or router in front of the tool. It probably wont be included in this project; it seems out of scope.

Architecture

naive gin architecture diagram

Workflows

A workflow definition looks like:

{
    "name": "do stuff",
    "variables": {
        "echo_url": "http://172.17.0.1:8000/some-endpoint",
        "content_type": "application/data"
    },
    "steps": [{
        "name": "Test Stuff",
        "type": "post-to-web",
        "context": {
            "url": "",
            "content-type": "",
            "data": "foo=bar"
        },
        "register": "echo_data"
    }, {
        "name": "Templatery Stuff",
        "type": "log",
        "context": {
            "message": ""
        },
        "register": "something"
    }]
}

The initial set of variables are accessible via the .Defaults key in context templates. These templates allow:

To access the output of a previous step, one must register the step with a unique name. This will be recognisable by ansible users, for example (in fact: thats where I stole the idea).

A workflow is kicked off via an api call:

curl -X POST -d '{"Name": "nontrivial workflow", "Variables":{"foo": "bar"} }' localhost:8080/wf/

The object Variables may be omitted: this is useful for data which is not known until runtime, and is made availabled via the .Rumtime key in context templates; in an identical fashion to how .Defaults works.

The request mints, and returns, a UUID. A workflow runner is attached to this uuid. This uuid can be used to view the status of a workflow; like the follow failed workflow:

$ curl localhost:8080/wf/7423bbb5-b020-4410-91b6-a5e2754e6a47

Returning:

{
  "EndTime": "2016-12-14T11:40:54.367619801Z",
  "ErrorMessage": "Step \"Test Stuff\" failed. See below",
  "Last": "Test Stuff",
  "StartTime": "2016-12-14T11:34:32.703863903Z",
  "State": "failed",
  "UUID": "7423bbb5-b020-4410-91b6-a5e2754e6a47",
  "Variables": {
    "Defaults": {
      "content_type": "application/data",
      "echo_url": "http://172.17.0.1:8000/some-endpoint"
    }
  },
  "Workflow": {
    "Name": "do stuff",
    "Steps": [
      {
        "Context": {
          "content-type": "application/data",
          "data": "foo=bar",
          "url": "http://172.17.0.1:8000/some-endpoint"
        },
        "Duration": "2 ms",
        "End": "2016-12-14T11:36:06",
        "ErrorMessage": "Post http://172.17.0.1:8000/some-endpoint: dial tcp 172.17.0.1:8000: getsockopt: connection refused",
        "Failed": true,
        "Name": "Test Stuff",
        "Register": "echo_data",
        "Start": "2016-12-14T11:36:06",
        "Type": "post-to-web",
        "UUID": ""
      },
      {
        "Context": {
          "message": ""
        },
        "Duration": "",
        "End": "",
        "ErrorMessage": "",
        "Failed": false,
        "Name": "Templatery Stuff",
        "Register": "something",
        "Start": "",
        "Type": "log",
        "UUID": ""
      }
    ],
    "Variables": {
      "content_type": "application/data",
      "echo_url": "http://172.17.0.1:8000/some-endpoint"
    }
  }
}

Here we see the first step has been compiled, yet the second step has npt. This is because a step is compiled right before it is run, to allow it access to the latest data. We can also see the runner has failed; it could not get access to a service and thus bombs out.

Licence

MIT License

Copyright (c) 2016 jspc

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.