Hi Gunnar, absolutely we could do with your help. Thanks for offering. At
Litbit iota is an integral part of the IoT platform we are building. It is an
integral part of the SMACK stack (Spark, Mesos, Akka, Cassandra and Kafka) on
which the platform is based. I assume you have taken a look at the iota website
(http://iota.incubator.apache.org/ <http://iota.incubator.apache.org/>) if not
it would be a good place to start.
Let’s begin with an overview of iota. iota consists of
1) The Fey engine - An Akka based framework that facilitates the definition of
Fey actors each actor implementing a Fey component. Fey actors extend a generic
Fey Actor FeyGenericActor and override generic functions, like onStart and
execute , to define an autonomous computation. Each Fey actor should be
provided through a .jar which the Fey engine loads to access the actors
functionality. Note this comes from the README.md file under the fey-core
directory. There is a lot of technical information in the README.md file. Take
a look and let us know what you think? Perhaps we need to have a new place for
this documentation.
2) Fey performers - Think of them as standalone continously operating
agents/actors/functions. The can process messages that are sent to them, they
can send messages down stream to other performers. Performers can also directly
interact with the technologies that they interact with. For example a Kafka
performer might directly interact with a Kafka Broker reading messages of a
particular type and sending them on as messages in Fey to other performers that
they are connected to. The same Kafta performer might process messages that it
is being sent from other Performers and send them as messages to the Kafka
Broker.
Here is the “Hello World” performer that will propagate the message “Hello
World” to any connected performers downstream. It will also propagate “Hello
World” when it receives a message from performers upstream from the performer.
Here is a snippet of code for such a performer: The performer below would
generate a fey-HelloWorld.jar file that is what get’s used to deploy the
Performer
package org.apache.iota.fey.performer
import akka.actor.ActorRef
import org.apache.iota.fey.FeyGenericActor
import scala.collection.immutable.Map
import scala.concurrent.duration._
class HelloWorld(override val params: Map[String, String] = Map.empty,
override val backoff: FiniteDuration = 1.minutes,
override val connectTo: Map[String, ActorRef] = Map.empty,
override val schedulerTimeInterval: FiniteDuration = 30.seconds,
override val orchestrationName: String = "",
override val orchestrationID: String = "",
override val autoScale: Boolean = false) extends
FeyGenericActor {
override def onStart = {
}
override def onStop = {
}
override def onRestart(reason: Throwable) = {
}
override def processMessage[T](message: T, sender: ActorRef): Unit = {
propagateMessage(“Hello World”)
}
override def execute() = {
propagateMessage(“Hello World")
}
Note each performer in iota should supply a README.md file that explains what
it does and gives a sample of how it is connected to other performers. A
network of integrating performers is known as an orchestration when each
performer is operating autonomously. Here is an example of an orchestration for
the HelloWorld performer. Note you could run this orchestration without
knowing the inner workings (coding) of any of the performers used. They are
just software components with a well know behavior that you can put together in
a network. The network below is degenerate in that it is simple a single
performer that is running continuously calling the execute method of the
performer every 1000 milliseconds (1 second). Since it’s not connected to
anything nothing can send it a message so the processMessage method of the
performer is never called here.
{
"guid": “Hello World Orchestration",
"command": "CREATE",
"timestamp": "591997890",
"name": “HelloWorld",
"ensembles": [
{
"guid": “MyHelloWorldEnsemble",
"command": "NONE",
"performers": [
{
"guid": "Timestamp",
"schedule": 1000,
"backoff": 0,
"source": {
"name": “fey-helloWorld.jar",
"classPath": "org.apache.iota.fey.performer.HelloWorld",
"parameters": {
}
}
}
],
"connections": [
]
}
]
}
Note the Fey engine uses a repository of performers (.jar file) and one or more
orchestrations to define a computation and hence compute. The repository of
performers and the orchestrations are stored in well defined locations see the
README.md documents for details.
Let’s create a a more complete orchestration. We first define a performer which
bundles HelloWorld, Alive and LogMessage functionality into a single performer
(.jar file). We will call this the tutorial.jar
package org.apache.iota.fey.performer
import akka.actor.ActorRef
import org.apache.iota.fey.FeyGenericActor
import scala.collection.immutable.Map
import scala.concurrent.duration._
class HelloWorld(override val params: Map[String, String] = Map.empty,
override val backoff: FiniteDuration = 1.minutes,
override val connectTo: Map[String, ActorRef] = Map.empty,
override val schedulerTimeInterval: FiniteDuration = 30.seconds,
override val orchestrationName: String = "",
override val orchestrationID: String = "",
override val autoScale: Boolean = false) extends
FeyGenericActor {
override def processMessage[T](message: T, sender: ActorRef): Unit = {
propagateMessage(“Hello World”)
}
override def execute() = {
propagateMessage(“Hello World")
}
package org.apache.iota.fey.performer
import akka.actor.ActorRef
import org.apache.iota.fey.FeyGenericActor
import scala.collection.immutable.Map
import scala.concurrent.duration._
class Alive(override val params: Map[String, String] = Map.empty,
override val backoff: FiniteDuration = 1.minutes,
override val connectTo: Map[String, ActorRef] = Map.empty,
override val schedulerTimeInterval: FiniteDuration = 30.seconds,
override val orchestrationName: String = "",
override val orchestrationID: String = "",
override val autoScale: Boolean = false) extends
FeyGenericActor {
override def execute() = {
propagateMessage(“Alive")
}
package org.apache.iota.fey.performer
import akka.actor.ActorRef
import org.apache.iota.fey.FeyGenericActor
import scala.collection.immutable.Map
import scala.concurrent.duration._
class LogMessage(override val params: Map[String, String] = Map.empty,
override val backoff: FiniteDuration = 1.minutes,
override val connectTo: Map[String, ActorRef] = Map.empty,
override val schedulerTimeInterval: FiniteDuration = 30.seconds,
override val orchestrationName: String = "",
override val orchestrationID: String = "",
override val autoScale: Boolean = false) extends
FeyGenericActor {
override def processMessage[T](message: T, sender: ActorRef): Unit = {
log.info(message)
}
The following Orchestration shows how performers can interact with each other.
Note that in the ConnectedWorldEnsemble instantiates three “actors" an instance
of the Alive performer is connected an instance of the HelloWorld performer.
The HelloWorld Performer is connected to the LogMessage Performer. This
orchestration is driven by messages being generated every second by the Alive
Performer. The HelloWorld performer will itself generated the “Hello World”
message on receiving the “Alive” message. In turn the logMessage performer will
print the message “Hello World” to the log file.
{
"guid": “Connected Orchestration",
"command": "CREATE",
"timestamp": "591997890",
"name": “ConnectedWorldEnsembles",
"ensembles": [
{
"guid": “ConnectedWorldEnsemble",
"command": "NONE",
"performers": [
{
"guid": “Alive",
"schedule": 1000,
"backoff": 0,
"source": {
"name": “fey-tutorial.jar",
"classPath": "org.apache.iota.fey.performer.Alive",
"parameters": {
}
}
},
{
"guid": “HellowWorld",
"schedule": 0,
"backoff": 0,
"source": {
"name": “fey-tutorial.jar",
"classPath": "org.apache.iota.fey.performer.HelloWorld",
"parameters": {
}
}
},
{
"guid": “LogMessage",
"schedule": 0,
"backoff": 0,
"source": {
"name": “fey-tutorial.jar",
"classPath": "org.apache.iota.fey.performer.LogMessage",
"parameters": {
}
}
}
],
"connections": [ { “Alive": [
"HelloWorld"
]
} ,
{ “HelloWorld": [
“LogMessage"
]
}
]
}
]
}
Gunnar is this helpful? Note for brevity I may have skipped some the code
details in the snippets above.
Thanks
-Tony