Tremor
Fork me on GitHub

Releasing Tremor v0.10!

Releasing Tremor v0.10

v0.10

Montage based upon photo by Ádám Berkecz on Unsplash

Summary

This release is the last minor release before we start turning tremor into a truly distributed event processing and data distribution engine. We focused on small things that improve usability and ironed out some rough edges here and there.

TL;DR

  • We extended our type system and codecs by the binary type.
  • Elasticsearch offramp now supports Linked Transport.
  • String interpolation done right, now with #{} instead of just {}
  • Release now includes prebuilt binaries, DEB packages and RPMs

New Release Artefacts

To make your life easier installing and Tremor we added new release artefacts. We now got prebuilt binaries wrapped up in a tar.gz for amd64 linux, DEB and RPM packages. And lets not forget our well-known docker image.

install prebuilt binary

We are going to explore more channels for release artefacts in the future to get you up and running with Tremor in no time.

In addition to those new release channels, we enabled thin-lto for all builds, which should improve compile-time while providing all the benefits of full link time optimization (LTO). We also link OpenSSL now statically to avoid incompatibilities with OpenSSL versions provided by the OS.

Binary Type and Binary Codec

Tremor is built for handling JSON-like structured data. It can very easily handle wire formats like JSON, YAML, msgpack and many more. We can represent them all with the same internal model of dynamic structured Values. One blind spot up to now has been binary data. The reason for this was simply that most of the aforementioned formats do not support raw binary data (except msgpack). But times changed.

With tremor you can now receive, assemble and send binary data. Receiving is easily done by configuring your onramp of choice with the binary codec. Imagine building a HTTP proxy with tremor that is not interested in the actual body payload but does its internal routing work only by looking at the headers. Previously Tremor had to parse and deserialize the whole body payload. Now it is able to simply pass those bytes through without ever touching them and thus be even faster and more efficient for similar use cases.

Here is an example config for the needed onramps and offramps;

onramp:
  - id: http_input
    type: rest
    codec: binary
    linked: true
    config:
      host: 0.0.0.0
      port: 8080

offramp:
  - id: http_output1
    type: rest
    codec: binary
    linked: true
    config:
      endpoint: http://host01.example.com
      method: GET

And here is a very simple corresponding pipeline:

select event
from in
where $request.method == "GET" && array::contains($request.headers["content-type"], "application/json")
into out;

You are able to assemble complex binary events from structured data within tremor-script itself, like TCP packets:

let tcp_packet = <<
  event.src.port:16,  event.dst.port:16,
  event.seq:32,
  event.ack:32,
  event.offset:4, event.res:4, event.flags:8, event.win:16,
  event.checksum:16, event.urgent:16,
  event.data/binary
>>;

Elasticsearch offramp as Linked Transport

We enhanced our elastic offramp to emit 1 event back to tremor for each document indexed to elasticsearch, be it successful or not. You will get all the elasticsearch metadata like the _version and _id of the indexed document and also the whole payload to be indexed, which is especially useful in the face of indexing errors, e.g. from mismatched document schemas.

An elastic offramp configured like this:

offramp:
  - id: elastic
    type: elastic
    linked: true
    config:
      nodes:
        - elastic01:9200
        - elastic02:9200
        - elastic03:9200

will, for an event like this:

{"data": [1, 2, 3]}

send you back a response payload like this if everything went well via the offramps out port:

{
    "source": {
        "event_id": "1:0:0",
        "origin": "tremor-file://root/data.json"
    },
    "payload": {
        "data": [1, 2, 3]
    },
    "success": true
}

with the following document metadata in $elastic:

{
    "id": "TxQutncB0ovN9WdBcg2i",
    "index": "tremor_test",
    "doc_type": "_doc",
    "version": 1
}

And in case indexing failed, you would get an event like this via the offramps err port:

{
   "source": {
        "event_id": "1:0:0",
        "origin": "tremor-file://root/data.json"
    },
    "payload": {
        "data": [1, 2, 3]
    },
    "success": false,
    "error": {
        "caused_by": {
            "reason": "Current token (VALUE_NUMBER_INT) not of boolean type\n at [Source: (byte[])\"POST //_bulk HTTP/1.1\r\ncontent-type: application/json\r\ncontent-length: 346\r\nuser-agent: reqwest/0.9.24\r\naccept: */*\r\naccept-encoding: gzip\r\nhost: 127.0.0.1:9200\r\n\r\n{\"index\":{\"_index\":\"tremor_test\",\"_type\":\"_doc\"}}\n{\"data\":\"[1, 2, 3]\"}\n\"[truncated 10 bytes]; line: 1, column: 13]",
            "type": "json_parse_exception"
        },
        "reason": "failed to parse field [data] of type [boolean] in document with id 'TxQutncB0ovN9WdBcg2i'. Preview of field's value: '1'",
        "type": "mapper_parsing_exception"}
}

Such an error message will also contain the same metadata behing the $elastic metadata key. Having detailed error data and the original payload at hand will enable users to handle success and error in new ways: Retries in case of errors, signalling upstream applications, try something completely different with that event payload…

String Interpolation done right

We changed the syntax for String interpolation to now use #{} for interpolating arbitrary expressions into a string literal, as we discovered some quirks in how it worked before (with {}). Creating JSON object Strings {"key": "value"} or regex quantifiers [1-9][0-9]{2, 3} have been inconvenient to write and there were surprises together with using the string::format function.

Where we previously had write:

let json_string = """
{{ "key": "value"}}
""";
let regex = "[1-9][0-9]\{2, 3\}";

We can now express those as:

let json_string = """
{ "key": "value"}
""";
let regex = "[1-9][0-9]{2, 3}";

Which is much better e.g. for templating purposes.

Questions/Comments

On the Community Discord: https://chat.tremor.rs

Published by in general and tagged releases using 820 words.