Browse Source
Started work on making the processing of images concurrent on a per engine basis
master
Started work on making the processing of images concurrent on a per engine basis
master
Drew Short
11 years ago
4 changed files with 147 additions and 0 deletions
-
4src/main/resources/application.conf
-
136src/main/scala/com/sothr/imagetools/ConcurrentEngine.scala
-
3src/main/scala/com/sothr/imagetools/Engine.scala
-
4src/test/resources/application.conf
@ -0,0 +1,4 @@ |
|||||
|
akka { |
||||
|
event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] |
||||
|
loglevel = "DEBUG" |
||||
|
} |
@ -0,0 +1,136 @@ |
|||||
|
package com.sothr.imagetools |
||||
|
|
||||
|
import java.io.File |
||||
|
import akka.actor.{Actor, Props, ActorLogging} |
||||
|
import akka.routing.{Broadcast, RoundRobinRouter} |
||||
|
import akka.event.Logging |
||||
|
import scala.collection.mutable.MutableList |
||||
|
import com.sothr.imagetools.image.Image |
||||
|
|
||||
|
//exeternal cases |
||||
|
case class EngineProcessFile(file:File) |
||||
|
case object EngineNoMoreFiles |
||||
|
case object EngineIsProcessingFinished |
||||
|
case object EngineGetProcessingResults |
||||
|
|
||||
|
//internal cases |
||||
|
case class EngineFileProcessed(image:Image) |
||||
|
case object EngineActorProcessingFinished |
||||
|
case object EngineActorReactivate |
||||
|
|
||||
|
class ConcurrentEngine extends Actor with ActorLogging { |
||||
|
val imageCache = AppConfig.cacheManager.getCache("images") |
||||
|
val numOfRouters = 10 |
||||
|
val router = context.actorOf(Props[ConcurrentEngineActor].withRouter(RoundRobinRouter(nrOfInstances = numOfRouters))) |
||||
|
|
||||
|
var images:MutableList[Image] = new MutableList[Image]() |
||||
|
var toProcess = 0 |
||||
|
var processed = 0 |
||||
|
|
||||
|
var processorsFinished = 0 |
||||
|
|
||||
|
override def preStart() = { |
||||
|
// initialization code |
||||
|
} |
||||
|
|
||||
|
override def receive = { |
||||
|
case command:EngineProcessFile => processFile(command) |
||||
|
case command:EngineFileProcessed => fileProcessed(command) |
||||
|
case EngineNoMoreFiles => requestWrapup() |
||||
|
case EngineActorProcessingFinished => actorProcessingFinished() |
||||
|
case EngineIsProcessingFinished => isProcessingFinished() |
||||
|
case EngineGetProcessingResults => getResults() |
||||
|
case _ => log.info("received unknown message") |
||||
|
} |
||||
|
|
||||
|
def processFile(command:EngineProcessFile) = { |
||||
|
log.debug(s"Started evaluating ${command.file.getAbsolutePath}") |
||||
|
toProcess += 1 |
||||
|
if (imageCache.isKeyInCache(command.file.getAbsolutePath)) { |
||||
|
log.debug(s"${command.file.getAbsolutePath} was already processed") |
||||
|
self ! EngineFileProcessed(imageCache.get(command.file.getAbsolutePath).getObjectValue.asInstanceOf[Image]) |
||||
|
} else { |
||||
|
router ! command |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
def fileProcessed(command:EngineFileProcessed) = { |
||||
|
processed += 1 |
||||
|
if (command.image != null) { |
||||
|
log.debug(s"processed image: ${command.image.imagePath}") |
||||
|
images += command.image |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* |
||||
|
*/ |
||||
|
def requestWrapup() = { |
||||
|
router ! Broadcast(EngineNoMoreFiles) |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Record that a processor is done |
||||
|
*/ |
||||
|
def actorProcessingFinished() = { |
||||
|
processorsFinished += 1 |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Check if processing is done |
||||
|
*/ |
||||
|
def isProcessingFinished() = { |
||||
|
try { |
||||
|
if (processorsFinished >= numOfRouters) sender ! true else sender ! false |
||||
|
} catch { |
||||
|
case e: Exception ⇒ |
||||
|
sender ! akka.actor.Status.Failure(e) |
||||
|
throw e |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Get the results of the processing |
||||
|
*/ |
||||
|
def getResults() = { |
||||
|
try { |
||||
|
processorsFinished = 0 |
||||
|
toProcess = 0 |
||||
|
processed = 0 |
||||
|
sender ! images.toList |
||||
|
images.clear() |
||||
|
} catch { |
||||
|
case e: Exception ⇒ |
||||
|
sender ! akka.actor.Status.Failure(e) |
||||
|
throw e |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class ConcurrentEngineActor extends Actor with ActorLogging { |
||||
|
var ignoreMessages = false |
||||
|
override def receive = { |
||||
|
case command:EngineProcessFile => processFile(command) |
||||
|
case EngineNoMoreFiles => finishedProcessingFiles() |
||||
|
case EngineActorReactivate => ignoreMessages = false |
||||
|
case _ => log.info("received unknown message") |
||||
|
} |
||||
|
|
||||
|
def processFile(command:EngineProcessFile) = { |
||||
|
if (!ignoreMessages) { |
||||
|
val image = ImageService.getImage(command.file) |
||||
|
if (image != null) { |
||||
|
sender ! EngineFileProcessed(image) |
||||
|
} else { |
||||
|
log.debug(s"Failed to process image: ${command.file.getAbsolutePath}") |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
def finishedProcessingFiles() = { |
||||
|
if (!ignoreMessages) { |
||||
|
ignoreMessages = true |
||||
|
sender ! EngineActorProcessingFinished |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,4 @@ |
|||||
|
akka { |
||||
|
event-handlers = ["akka.event.slf4j.Slf4jEventHandler"] |
||||
|
loglevel = "DEBUG" |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue