2016-07-22 4 views
0

私は滑らかなSqLiteを使用しているプレースケールのアプリケーションを持っています。私のテーブルは次のように定義されています。アクターでのスリックなデータベースアクセス

@Singleton 
class DataSets @Inject()(protected val dbConfigProvider: DatabaseConfigProvider, keys: PublicKeys) extends DataSetsComponent 
    with HasDatabaseConfigProvider[JdbcProfile] { 
    import driver.api._ 

    val DataSets = TableQuery[DataSetsTable] 

    def all = db.run(DataSets.sortBy { _.id }.result) 
    ... 
} 

私のコントローラはDI経由でのアクセスを取得:

@Singleton 
class DataSetsController @Inject() (dataSets: DataSets, env: play.Environment) extends Controller { 
... 

は、どのように私は俳優でデータベース・ハンドルを得るのですか?

class TrainActor @Inject() (dataSets: DataSets) extends Actor { 
... 

もちろん、GuiceはDataSetsクラスを見つけられないため動作しません。

編集:明らかにするには:私はコントローラのデータベースアクセス(askを介して)を使用するのではなく、要求後にコントローラからリソースを消費する計算を開始し、後でdbに格納します(async )。

class MyController @Inject()(@Named("injected-train-actor") trainActor: ActorRef) { 

    def endpointTest = Action.async { 
    for { 
     items <- (trainActor ? FetchAll).mapTo[Seq[DataSetsTableRow]] 
    } yield Ok(Json.toJson(items)) 
    } 

} 

答えて

1

これで、official documentationに厳密に従って、DIと統合する方法が見つかりました。 ActorContextが必要なため、InjectedActorSupportActorでしか継承できません。これは、新しい「労働者」俳優をインスタンス化して開始すること以外のことをしない俳優を作成しなければならないことを意味します。たぶん簡単な方法がありますが、これは正しく動作します。

TrainActor.scala

package actors 

import javax.inject.Inject 

import akka.actor._ 
import com.google.inject.assistedinject.Assisted 
import models.{DataSet, Model, PublicKey} 
import play.api.Logger 
import tables.DataSets 

import scala.concurrent.ExecutionContext.Implicits.global 

object TrainActor { 
    case object Start 
    case class LoadData(d: DataSet, k: PublicKey) 

    trait Factory { 
    def apply(model: Model): Actor 
    } 
} 

class TrainActor @Inject() (val dataSets: DataSets, @Assisted val model: Model) extends Actor { 
    import TrainActor._ 

    def receive = { 
    case Start => 
     dataSets.findWithKey(model.id.get) 
     ... 

TrainActorStarter.scala

package actors 

import javax.inject.Inject 

import akka.actor.{Actor, ActorRef} 
import models.Model 
import play.api.libs.concurrent.InjectedActorSupport 

object TrainActorStarter { 
    case class StartTraining(model: Model) 
} 

/** 
    * https://www.playframework.com/documentation/2.5.x/ScalaAkka#Dependency-injecting-actors 
    * @param childFactory 
    */ 
class TrainActorStarter @Inject() (childFactory: TrainActor.Factory) extends Actor with InjectedActorSupport { 
    import TrainActorStarter._ 

    def receive = { 
    case StartTraining(model: Model) => 
     val trainer: ActorRef = injectedChild(childFactory(model), s"train-model-model-${model.id.get}") 
     trainer ! TrainActor.Start 
    } 
} 

ActorModule.scala:そして最後に、コントローラで

package actors 

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

class ActorModule extends AbstractModule with AkkaGuiceSupport { 
    def configure(): Unit = { 
    bindActor[TrainActorStarter]("train-actor-starter") 
    bindActorFactory[TrainActor, TrainActor.Factory] 
    } 
} 

package controllers 

import javax.inject._ 

import actors.{TrainActorStarter, TrainCallbackActor} 
import akka.actor.{ActorRef, ActorSystem, _} 
import akka.stream.Materializer 
... 

@Singleton 
class ModelsController @Inject() (implicit system: ActorSystem, materializer: Materializer, ..., @Named("train-actor-starter") trainActorStarter: ActorRef) extends Controller with InjectedActorSupport { 

    def startTraining(model: Model): Unit = { 
    if(model.id.isEmpty) return 
    trainActorStarter ! TrainActorStarter.StartTraining(model) 
    } 
0

あなたは俳優に依存性を注入することができますDataSetsDAOとして機能することができる単純なスカラオブジェクト

object DataSets 

、その後、俳優にちょうどそうただの副作用を回避するためにonCompleteに俳優に自己にメッセージをスケジュールし、その結果タイプは将来になることを心に留めてちょうどDataSets.dbOperationを使用しています。

+0

コントローラにメッセージを送信する代わりに、新しいアクタをインスタンス化できるようにしたい場合はどうすればよいですか? – joni

0

代わりの

@Singleton 
class DataSets 

1のようにそれを宣言することができた:コントローラーにそのちょうど注入俳優の後

import com.google.inject.AbstractModule 
import play.api.libs.concurrent.AkkaGuiceSupport 

class MyModule extends AbstractModule with AkkaGuiceSupport { 
    def configure = { 
    bindActor[TrainActor]("injected-train-actor") 
    } 
} 

+0

hmこれは簡単な解決策だと思うが、テストが不可能になっている – joni

+0

テストデータベースで統合テストを実行することができます。そうでなければ、コントローラから注入されたDataSetsインスタンスをアクターのProps http://doc.akka .io/docs/akka/2.4.8/scala/actors.html#小道具 –

関連する問題