/kontraktor

lightweight and efficient Actor implementation in Java

Primary LanguageJava

kontraktor

lightweight and efficient Actor implementation in Java. The threading model implemented has many similarities to node.js, go's and Dart's model of concurrency.

Kontraktor implements a typed actor model to avoid message definition+handling boilerplate code. Additionally this integrates well with code completion and refactoring of modern IDEs.

Blogposts (kontraktor version > 2.0):

###2.0 beta

  • package name change, requires jdk 1.8
  • each actor now has dedicated queues, 1.x style scheduling (many actors from one per-thread-queue) caused issues in some scenarios.
  • New: Elastic Scheduler scales up actors horizontally by adding cores if needed based on profiling data
  • New: Actor Remoting: TCP, HTTP-WebService, WebSockets
  • New: Spores
  • Streamlined API, added new utils
  • added many sanity checks to help spotting actor contract violations for beginners
  • Documentation see 2.0-beta wiki page (in progress)

2.0 beta State:

  • Core Actor functionality stable.
  • TCP remoting also stable, probably issues in corner cases (e.g. dynamically connecting/disconnecting etc.).
  • WebSocket Remoting functionality requires unreleased sub project "netty-kontraktor" (see source).
  • Single line WebService actor publishing lacks documentation, zero test coverage (uses kson/json encoding)
  • Still unoptimized. Currently: 4-5 million messages per second in-process, ~1.0 million messages per second via TCP-Remoting/fast-serialization 2.x (ofc depends on number of arguments/message size).
<dependency>
    <groupId>de.ruedigermoeller</groupId>
    <artifactId>kontraktor</artifactId>
    <version>2.0-beta-1</version>
</dependency>

###Productive 1.x

Requires JDK 1.7+, but JDK 8 is recommended as readability is much better with lambda's and now optional "final" modifier.

Documentation is work in progress,

SampleApp - a nio http 1.0 webserver skeleton done with actors

<dependency>
    <groupId>de.ruedigermoeller</groupId>
    <artifactId>kontraktor</artifactId>
    <version>1.15</version>
</dependency>

Kontraktor uses runtime-generated (javassist) proxy instances which put all calls to the proxy onto a queue. A DispatcherThread then dequeues method invocations (=messages) ensuring single-threadedness of actor execution.

E.g.

    public static class BenchSub extends Actor<BenchSub> {
        int count;
        
        public void benchCall(String a, String b, String c) {
            count++;
        }
          
        public Future<Integer> getResult() {
            return new Promise(count);
        }
    }

    public static main(..) 
    {
        final BenchSub bsProxy = Actors.SpawnActor(BenchSub.class); // create proxy + actor instance
        for (int i : new int[10] ) {
            bsProxy.benchCall("u", "o", null); // actually enqueues
        }
        // all communication is async
        bsProxy.getResult().then( (res,err) -> bs.stop() );
    }

Kontrakor internally uses a high performance bounded queue implementation of the Jaq-In-A-Box project and can pass up to 9 million messages per second (on i7 laptop, method with 3 arguments passed).