Skip to content

Fluxtion Quickstart

This guide introduces Fluxtion through a series of progressively more capable examples. Each example adds new behaviour while the amount of orchestration code stays almost constant.

Fluxtion infers the execution pipeline from the relationships between components at compile time, so developers only write the business logic.


Install JBang

Examples use JBang so they can run without creating a full project.

Install JBang:

# macOS / Linux
curl -Ls https://sh.jbang.dev | bash

# Windows (powershell)
iex "& { $(iwr https://ps.jbang.dev) }"

More details: https://www.jbang.dev


1. Hello world

Create a simple event pipeline.

//DEPS com.telamin.fluxtion:fluxtion-builder:0.9.32
//JAVA 25

import com.telamin.fluxtion.builder.DataFlowBuilder;
import com.telamin.fluxtion.runtime.DataFlow;

void main() {
    DataFlow dataFlow = DataFlowBuilder
            .subscribe(String.class)
            .map(String::toUpperCase)
            .console("msg:{}")
            .build();

    dataFlow.onEvent("hello");
    dataFlow.onEvent("world");
}

Run:

jbang hello.java

Output:

msg:HELLO
msg:WORLD
Fluxtion automatically determines the execution order for the pipeline and generates the runtime event processor.


2. Streaming analytics

Compute a sliding window average from a real-time event stream.

//DEPS com.telamin.fluxtion:fluxtion-builder:0.9.32
//JAVA 25

import com.telamin.fluxtion.builder.DataFlowBuilder;
import com.telamin.fluxtion.runtime.DataFlow;
import com.telamin.fluxtion.runtime.flowfunction.helpers.Aggregates;

import java.util.Random;

record CarTracker(String id, double speed) { }

void main() throws InterruptedException {
    // 5 buckets of 200ms = 1 second sliding window
    DataFlow averageCarSpeed = DataFlowBuilder
            .subscribe(CarTracker::speed)
            .slidingAggregate(Aggregates.doubleAverageFactory(), 200, 5)
            .map(v -> "average speed: " + v.intValue() + " km/h")
            .sink("average car speed")
            .build();

    averageCarSpeed.addSink("average car speed", System.out::println);

    Random random = new Random();

    for (int i = 0; i < 100; i++) {
        averageCarSpeed.onEvent(
                new CarTracker("car-" + (i % 5), random.nextInt(100)));
        Thread.sleep(random.nextInt(100));
    }
}

Run:

jbang streamingAnalytics.java

Output:

average speed: 45 km/h
average speed: 41 km/h
average speed: 42 km/h
average speed: 45 km/h
average speed: 47 km/h
average speed: 55 km/h
average speed: 58 km/h
average speed: 63 km/h
average speed: 61 km/h
average speed: 56 km/h
average speed: 55 km/h

Fluxtion maintains the sliding window and automatically triggers downstream calculations.


3. Stateful node example

Fluxtion integrates directly with ordinary Java objects.

//DEPS com.telamin.fluxtion:fluxtion-builder:0.9.32
//JAVA 25

import com.telamin.fluxtion.builder.DataFlowBuilder;
import com.telamin.fluxtion.runtime.DataFlow;
import com.telamin.fluxtion.runtime.annotations.OnEventHandler;

void main() {
    DataFlow flow = DataFlowBuilder
            .subscribeToNode(new StatefulNode())
            .map(StatefulNode::getValue)
            .console("value:{}")
            .build();

    flow.onEvent("A");
    flow.onEvent("B");
    flow.onEvent("C");
    flow.onEvent("D");
    flow.onEvent("E");
    flow.onEvent("F");
}

public class StatefulNode {

    private String value;

    @OnEventHandler
    public boolean update(String input) {
        value = input;
        return true;
    }

    public String getValue() {
        return value;
    }
}

Run:

jbang statefulNode.java

Output:

value:A
value:B
value:C
value:D
value:E
value:F

Stateful objects participate directly in the event graph.


4. Multi‑feed event system

Real systems often combine multiple event streams. Fluxtion can also combine multiple event streams using joins.

//DEPS com.telamin.fluxtion:fluxtion-builder:0.9.32
//JAVA 25

import com.telamin.fluxtion.builder.DataFlowBuilder;
import com.telamin.fluxtion.builder.flowfunction.JoinFlowBuilder;
import com.telamin.fluxtion.runtime.DataFlow;
import com.telamin.fluxtion.runtime.flowfunction.groupby.GroupBy;
import com.telamin.fluxtion.runtime.flowfunction.helpers.Tuples;

import java.util.List;
import java.util.stream.Collectors;

public record Pupil(int year, String school, String name) {
}

public record School(String name) {
}

void main(String[] args) {
    var pupils = DataFlowBuilder.subscribe(Pupil.class).groupByToList(Pupil::school);
    var schools = DataFlowBuilder.subscribe(School.class).groupBy(School::name);

    DataFlow processor = JoinFlowBuilder
            .innerJoin(schools, pupils)
            .mapValues(Tuples.mapTuple(Helper::prettyPrint))
            .map(GroupBy::toMap)
            .console()
            .build();

    //register some schools
    processor.onEvent(new School("RGS"));
    processor.onEvent(new School("Belles"));

    //register some pupils
    processor.onEvent(new Pupil(2015, "RGS", "Bob"));
    processor.onEvent(new Pupil(2013, "RGS", "Ashkay"));
    processor.onEvent(new Pupil(2013, "Belles", "Channing"));
    processor.onEvent(new Pupil(2013, "RGS", "Chelsea"));
    processor.onEvent(new Pupil(2013, "Belles", "Tamsin"));
    processor.onEvent(new Pupil(2013, "Belles", "Ayola"));
    processor.onEvent(new Pupil(2015, "Belles", "Sunita"));
}

public static class Helper{
    public static String prettyPrint(School schoolName, List<Pupil> pupils) {
        return pupils.stream().map(Pupil::name).collect(Collectors.joining(",", "pupils[", "]"));
    }
}

Run:

jbang multiJoin.java

Output:

{}
{}
{RGS=pupils[Bob]}
{RGS=pupils[Bob,Ashkay]}
{Belles=pupils[Channing], RGS=pupils[Bob,Ashkay]}
{Belles=pupils[Channing], RGS=pupils[Bob,Ashkay,Chelsea]}
{Belles=pupils[Channing,Tamsin], RGS=pupils[Bob,Ashkay,Chelsea]}
{Belles=pupils[Channing,Tamsin,Ayola], RGS=pupils[Bob,Ashkay,Chelsea]}
{Belles=pupils[Channing,Tamsin,Ayola,Sunita], RGS=pupils[Bob,Ashkay,Chelsea]}

Fluxtion composes multiple streams while maintaining deterministic execution.


5. Robotics / defence example

Fluxtion is well suited for deterministic control systems such as drones or robotics.

This example reacts to altitude events and triggers a safety warning.

//DEPS com.telamin.fluxtion:fluxtion-builder:0.9.32
//JAVA 25

import com.telamin.fluxtion.builder.DataFlowBuilder;
import com.telamin.fluxtion.runtime.DataFlow;

record Altitude(double meters) {
}


void main(String[] args) {
    DataFlow droneSafety = DataFlowBuilder
            .subscribe(Altitude::meters)
            .filter(a -> a > 120)
            .map(a -> "WARNING: altitude limit exceeded " + a)
            .console("{}")
            .build();

    // sensor events
    droneSafety.onEvent(new Altitude(80));
    droneSafety.onEvent(new Altitude(95));
    droneSafety.onEvent(new Altitude(140));
}

Run:

jbang altitudeMonitor.java

Output:

WARNING: altitude limit exceeded 140.0

Because the execution graph is deterministic, behaviour can be analysed, tested, and replayed — an important property for safety-critical systems.


Next steps

Now that you have seen how Fluxtion coordinates logic, explore how to run it in a production runtime:

See the Why Fluxtion exists guide for a deeper look at the architecture.