configurations { quasar }
dependencies { compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version") // compile("co.paralleluniverse:quasar-core:$quasar_version:jdk8") // quasar compile("co.paralleluniverse:quasar-actors:$quasar_version") // compile("co.paralleluniverse:quasar-kotlin:$quasar_version") // quasar "co.paralleluniverse:quasar-core:$quasar_version:jdk8" // java- //... }
tasks.withType(JavaForkOptions) { //uncomment if there are problems with fibers //systemProperty 'co.paralleluniverse.fibers.verifyInstrumentation', 'true' jvmArgs "-javaagent:${(++configurations.quasar.iterator())}" }
co.paralleluniverse.fibers.verifyInstrumentation
is responsible for checking in runtime correctness of bytecode manipulations. Of course, if this check is enabled, then everything starts to slow down :) def createRunScript(String scriptPath, String type) { def file = new File(scriptPath) file.createNewFile() file.setExecutable(true) def preamble = "@echo off" if (type == "sh") { preamble = "#!/bin/bash" } def deps = configurations.quasar.files.collect { "-Xbootclasspath/a:\"libs/${it.name}\"" }.join(" ") def flags = "-Dco.paralleluniverse.fibers.detectRunawayFibers=false" def quasarAgent = configurations.quasar.files.find { it.name.contains("quasar-core") }.name file.text = """$preamble java -classpath "./*.jar" -javaagent:"libs/$quasarAgent" $deps $flags -jar ${project.name}.jar """ }
task release(dependsOn: ['build']) { group = "Build" def targetDir = "$buildDir/release" doLast { copy { from "$buildDir/libs/${project.name}.jar" into targetDir } copy { // quasar, javaagent from(configurations.quasar.files) into "$targetDir/libs" } copy { // , from("src/main/resources/application.yml") into targetDir } // createRunScript("$targetDir/${project.name}.bat", "bat") createRunScript("$targetDir/${project.name}.sh", "sh") } }
co.paralleluniverse.kotlin.Actor
with the receive
method. For a permanent exchange, we had to implement a small layer: abstract class BasicActor : Actor() { @Suspendable abstract fun onReceive(message: Any): Any? @Suspendable override fun doRun() { while (true) { receive { onReceive(it!!) } } } fun <T> reply(incomingMessage: RequestMessage<T>, result: T) { RequestReplyHelper.reply(incomingMessage, result) } }
// TODO Was "(Any) -> Any?" but in 1.1 the compiler would call the base Java method and not even complain about ambiguity! Investigate and possibly report inline protected fun receive(proc: (Any?) -> Any?) { receive(-1, null, proc) }
BasicActor
had to make a wrapper for receive
. Well, for clarity, the reply
method and the extenstion ask
method were made: @Suspendable fun <T> ActorRef<Any>.ask(message: RequestMessage<T>): T { return RequestReplyHelper.call(this, message) }
RequestMessage
. This slightly limits the messages that can be exchanged in the question-answer format.@Suspendable
annotation is very important - when using quasar, it must be hung up on all methods that apply to other actors or lightweight streams, otherwise you will get the SuspendExecution
exception in SuspendExecution
, and there will be no sense from “lightness”. From the point of view of the library's developers, it is obvious that this is necessary for the java-agent, but from the programmer-user’s point of view, this is inconvenient (it is possible to do this automatically , but it will be far from free).onReceive
method, which can be done quite simply with when
, doing something depending on the type of message: override fun onReceive(message: Any) = when (message) { is SomeMessage -> { // Do stuff val someotherActor = ActorRegistry.getActor("other actor") someotherActor.send(replyOrSomeCommand) } is SomeOtherMessage -> { process(message.parameter) // smart-cast val replyFromGuru = guruActor.ask(Question("Does 42 equals 7*6?")) doSomething() } else -> throw UnknownMessageTypeException(message) }
ActorRegistry.getActor
, which returns a reference to the actor by a string identifier. val myActor = MySuperDuperActor() val actorRef = spawn(register(MY_ACTOR_ID, myActor))
class WatcherActor : BasicActor(), ILogging by Logging<WatcherActor>() { override fun handleLifecycleMessage(lcm: LifecycleMessage): Any? { return onReceive(lcm) } override fun onReceive(message: Any): Any? = when (message) { is ExitMessage -> { log.fatal("Actor ${message.actor.name} got an unhandled exception. Terminating the app. Reason: ", message.getCause()) exit(-2) } else -> { log.fatal("Got unknown message for WatcherActor: $message. Terminating the app") exit(-1) } } }
@Suspendable fun registerAndWatch(actorId: String, actorObject: Actor<*, *>): ActorRef<*> { val ref = spawn(register(actorId, actorObject)) watcherActor.link(ref) return ref }
fun <T : Actor<Any?, Any?>> T.finish() { this.ref().send(ExitMessage(this.ref(), null)) this.unregister() }
ActorRegistry.clear()
, which removes ALL actors, but if you get into his gut, you can see the following: public static void clear() { if (!Debug.isUnitTest()) throw new IllegalStateException("Must only be called in unit tests"); if (registry instanceof LocalActorRegistry) ((LocalActorRegistry) registry).clear(); else throw new UnsupportedOperationException(); }
boolean isUnitTest = false; StackTraceElement[] stack = Thread.currentThread().getStackTrace(); for (StackTraceElement ste : stack) { if (ste.getClassName().startsWith("org.junit") || ste.getClassName().startsWith("junit.framework") || ste.getClassName().contains("JUnitTestClassExecuter")) { isUnitTest = true; break; } } unitTest = isUnitTest;
ActorRegistry.shutdown()
method, it will surely cause the closure of every actor! We look at the implementation of the abstract method in LocalActorRegistry
: @Override public void shutdown() { }
Thread.sleep()
. Quasar didn’t like it very much, and he spat on the logs with exceptions: they say, Thread.sleep()
blocks the stream and this will have a bad effect on performance (see details here ). At the same time, there are no specific recipes for how to fix it (except for stupidly disabling the logging of such errors with the system flag) or at least “understand and forgive” only for third-party libraries.Source: https://habr.com/ru/post/350182/
All Articles