def findUser(screenName: String): Future[User] = ...
def findFollowers(user: User): Future[Set[User]] = ...
def unfollowAtRandom(user: User, followers: Set[User]): Future[Unit] = ...
def domainLogic(screenName: String) = atomically {
for {
user <- findUser(screenName)
followers <- findFollowers(user)
_ <- unfollowAtRandom(user, followers)
} yield ()
}
こんな感じで独立した非同期呼び出しを簡単に同一トランザクションにしたい。
全体の Future
が成功したらcommit, 失敗したらrollbackしてくれる感じ。
atomically
がネストしてたら同一のトランザクションにしてくれるとなお嬉しい。
def atomically[A](f: => Future[A]): Future[A]
トランザクション制御は JTA を使用して抽象化したい。
Future
の内部計算はどのスレッドで実行されるかコントロールできないので、
DynamicVariable
や ThreadLocal
で共有する方法は使えない。
そもそも javax.transaction.Transaction
の実装や、
各 XAResource
の実装がスレッドセーフだとは思えないので
Transaction
インスタンス等へのアクセスは
シングルスレッドで動かす保障をした方がいい。
Actor
使う?
→ Future
モデルと Actor
モデルの合成とか茨の道感
Executors.singleThreadPool()
な FuturePool
を用意して
Transaction
インスタンス等へのアクセスは必ずその FuturePool
で行う。
こっちのが現実的か。
トランザクションが並列に大量発生したらどうする?
その FuturePool
をトランザクション毎に作成すればいい?
findUser
や findFollowers
の内部実装では、
どうにかして現在のトランザクションを知る必要がある。
これはどうやって取得するべきか。
implicit parameter 使う? → ドメインロジックのAPIになるべくそういうIFは入れたくない。