Skip to content

v12technology/fluxtion

Repository files navigation

Github build Maven Central

Fluxtion embedded stream processing

Fluxtion is a Java library and code generation utility designed for building high-performance, low-latency streaming applications. It provides a lightweight framework for event-driven programming, particularly suited for applications such as financial trading systems, real-time analytics, and sensor data processing. Fluxtion emphasizes simplicity, efficiency, and ease of use in handling streaming data.

  • Streaming event processing
  • AOT compiled for fast cloud start
  • Spring integration
  • Optimised to reduce processing costs
  • Low latency nanosecond response with zero gc
  • 30 million events per second per core

Application integration

Embed a Fluxtion stream processing engine in your application, freeing your business logic from messaging vendor lock-in.

Performance

See the performance section for jmh and hdr results

  • 33 million events processed per second
  • Average latency is 30 nanoseconds to process one event including app logic
  • The Fluxtion event processor is in the low nanosecond range for event processing overhead
  • Zero gc
  • Single threaded application

Code sample

Fluxtion supports both imperative service style and functional patterns. Below is an example of functional coding style that adds two numbers from independent data streams and logs when the sum is greater than 100.

/**
 * Simple Fluxtion hello world stream example. Add two numbers and log when sum > 100
 * <ul>
 *     <li>Subscribe to two event streams, Data1 and Data1</li>
 *     <li>Map the double values of each stream using getter</li>
 *     <li>Apply a stateless binary function {@link Double#sum(double, double)}</li>
 *     <li>Apply a filter that logs to console when the sum > 100</li>
 * </ul>
 */
public class HelloWorld {
    public static void main(String[] args) {
        //builds the EventProcessor
        EventProcessor eventProcessor = Fluxtion.interpret(cfg -> {
            var data1Stream = subscribe(Data1.class)
                    .console("rcvd -> {}")
                    .mapToDouble(Data1::value);

            subscribe(Data2.class)
                    .console("rcvd -> {}")
                    .mapToDouble(Data2::value)
                    .map(Double::sum, data1Stream)
                    .filter(d -> d > 100)
                    .console("OUT: sum {} > 100");
        });
        //init and send events
        eventProcessor.init();
        //no output < 100
        eventProcessor.onEvent(new Data1(20.5));
        //no output < 100
        eventProcessor.onEvent(new Data2(63));
        //output > 100 - log to console
        eventProcessor.onEvent(new Data1(56.8));
    }

    public record Data1(double value) {
    }

    public record Data2(double value) {
    }
}

Execution output

rcvd -> Data1[value=20.5]
rcvd -> Data2[value=63.0]
rcvd -> Data1[value=56.8]
OUT: sum 119.8 > 100

Process finished with exit code 0

Processing graph

flowchart TB
    
    style EventProcessor fill:#e9ebe4,stroke:#333,stroke-width:1px
    classDef eventHandler color:#022e1f,fill:#aaa3ff,stroke:#000;
    classDef graphNode color:#022e1f,fill:#00cfff,stroke:#000;
    classDef exportedService color:#022e1f,fill:#aaa3ff,stroke:#000;

    
    EventA><b>InputEvent</b>::Event_A]:::eventHandler 
    EventB><b>InputEvent</b>::Event_B]:::eventHandler 
    
    HandlerA[<b>Subscriber</b>::Event_A]:::graphNode 
    HandlerB[<b>Subscriber</b>::Event_A]:::graphNode 
    
    MapData1[<b>Map</b> -> mapToDouble]:::graphNode 
    MapData2[<b>Map</b> -> mapToDouble]:::graphNode 
    
    MapDefaultData1[<b>Map</b> -> defaultValue]:::graphNode 
    MapDefaultData2[<b>Map</b> -> defaultValue]:::graphNode 
    
    BiMapSum[<b>BiMap</b> -> Double::sum]:::graphNode 
    
    Console1[<b>Peek</b> -> console]:::graphNode 
    Filter[<b>Filter</b> -> d > 100]:::graphNode 
    Console2[<b>Peek</b> -> console]:::graphNode 
    
    EventA --> HandlerA
    EventB --> HandlerB
    
    subgraph EventProcessor
      HandlerA --> MapData1 --> MapDefaultData1 --> BiMapSum
      HandlerB --> MapData2 --> MapDefaultData2 --> BiMapSum
      BiMapSum --> Console1 --> Filter --> Console2
    end
    

Top level components

There are two major components provided by Fluxtion the developer uses to build event driven logic.

Compiler

The compiler analyses the configuration information provided by the programmer and builds a dependency injection container that houses all the user components or beans combined with pre-calculated event dispatch. Outputs from the compiler are either

  • In memory di container running in an interpreted mode
  • A container generated ahead of time and serialised to code

Runtime

The runtime provides the dependency injection container with a core set of libraries required at runtime. An AOT generated container only requires the runtime to function, no compiler libraries are required.

Donations

The guys from ej technologies kindly donated their java profiler JProfiler to allow me to optimise Fluxtion, many thanks.

Contributing

We welcome contributions to the project. Detailed information on our ways of working will be written in time. In brief our goals are:

License

Fluxtion is licensed under the Server Side Public License. This license is created by MongoDb, for further info see FAQ and comparison with AGPL v3.0.