A lightweight, fast, and efficient stateful actor system for resource-constrained environments! (Working in progress)
Unlike heavyweight frameworks like Akka, or sidecar based actor model like Spawn, Dapr and others, Synapsys is designed to be lightweight and blazing fast, making it perfect for small devices, embedded systems, and applications that need a minimal footprint. 🚀
It provides a simple and intuitive API for building concurrent, stateful actors while keeping things efficient.
"Big brains in small packages!" – Synapsys motto 😆
✅ Lightweight – Optimized for minimal resource usage.
✅ Fast – Built for high-performance message processing.
✅ Simple API – Easy to use and extend.
✅ Concurrency Made Easy – Uses Erlang inspired preemptive scheduler.
✅ Stateful Actors – Actors persist and maintain their state across messages.
1️⃣ Install Synapsys
To use Synapsys, add the following dependency to your Gradle (Kotlin DSL):
dependencies {
implementation("io.eigr.synapsys:synapsys-core:0.1.0")
}
Or for Maven users:
<dependency>
<groupId>io.eigr.synapsys</groupId>
<artifactId>synapsys-core</artifactId>
<version>0.1.0</version>
</dependency>
2️⃣ Define a Stateful Actor 🎭
Synapsys actors are stateful by default, meaning they retain their state across multiple messages:
import io.eigr.synapsys.core.actor.Actor
import io.eigr.synapsys.core.actor.Context
import org.slf4j.LoggerFactory
data class Message(private val text: String?)
class MyActor(id: String?, initialState: Int?) : Actor<Int, Message, String>(id, initialState) {
private val log = LoggerFactory.getLogger(MyActor::class.java)
override fun onReceive(message: Message, ctx: Context<Int>): Pair<Context<Int>, String> {
log.info("Received message on Actor {}: {} with previous state: {}", id, message, ctx.state)
val newCtx = ctx.update(ctx.state!! + 1)
return ctx to "Processed: $message with new state: ${newCtx.state}"
}
}
3️⃣ Run the Actor System 🚀
import io.eigr.synapsys.core.actor.ActorSystem
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
ActorSystem.start()
val actors: listOf<ActorPointer<Any>>() = (0..1000).map { i ->
ActorSystem.actorOf("my-actor-$i", 0) { id, initialState ->
MyActor(
id,
initialState
)
}
}
actors.forEach { actor ->
repeat(100) {
actor.send(Message("Hello"))
// or use ask pattern
//val resp = actor.ask<String>(Message("Hello"))
//println("Actor response is $resp")
}
}
delay(120000)
}
See more examples in example project
Unlike traditional message processing models, stateful actors allow you to:
✅ Keep track of internal state across multiple messages.
✅ Reduce database interactions by maintaining state in-memory.
✅ Simplify business logic with event-driven processing.
But what makes Synapsys even more powerful is that actors can persist their state in different ways:
-
In-memory for high-speed ephemeral processing.
-
Embedded databases like SQLite for lightweight persistence.
-
Traditional databases (e.g., PostgreSQL, MySQL) for long-term storage.
This makes Synapsys perfect for use cases like:
-
A chat system where users reconnect and keep their conversation history.
-
A bank account service where transactions update and persist balances.
-
An IoT controller that maintains device states even after a restart.
Synapsys is built for speed and efficiency. Here's what you get out of the box:
⚡ Low-latency message processing
⚡ Efficient memory usage
⚡ Scales effortlessly across multiple actors
⚡ State persistence for long-running actors
Run the example and see the results for yourself! 🚀
If you need more advanced features, a business-oriented context, or support for environments beyond the JVM and Android devices, consider using Spawn. While Synapsys excels as a lightweight actor library for JVM-based applications, Spawn offers a broader polyglot and distributed runtime for scalable, multi-environment deployments.
We ❤️ contributions! Found a bug? Want to add a feature? Open an issue or submit a pull request.
📜 License: MIT
Give it a ⭐ if you like it! 🎉