Skip to main content

Releasing Tremor v0.10!

· 5 min read

v0.10

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 more pleasant, we added new release artefacts. We've 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 effectively 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 that most of the aforementioned formats do not support raw binary data (except msgpack). But times have changed.

With Tremor, you can now receive, assemble and send binary data. Receiving is 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 conveniently 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 written:

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

we can now express 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