These are chat archives for RBMHTechnology/eventuate

28th
Dec 2015
Mike Mazur
@mikem
Dec 28 2015 03:40
Is it safe to use stash() and unstashAll() in EventsourcedViews and EventsourcedActors? There’s MessageStash which implements stashing, but is that intended to replace Akka’s stashing functionality?
Mike Mazur
@mikem
Dec 28 2015 04:21
What’s the purpose of the second half of the “support user stash operations” spec? It looks like the intention is to verify that Pong(3) happens before Cmd(“d”, 1), but the tests don’t actually enforce that; the test still passes if lines 315 and 316 are swapped or if lines 322 and 323 are swapped.
Martin Krasser
@krasserm
Dec 28 2015 06:16

@Tvaroh I cannot reproduce that. For testing I used:

import akka.actor._

import com.rbmhtechnology.eventuate.EventsourcedActor
import com.rbmhtechnology.eventuate.log.leveldb.LeveldbEventLog

import scala.util._

class Example(val eventLog: ActorRef) extends EventsourcedActor {
  override val id = "example"

  private var state: Int = 0

  override def onCommand: Receive = {
    case i: Int => persist(i) {
      case Success(e) =>
        assert(e == i)
        println(s"persisted: $i (state = $state)")
      case Failure(t) => // ...
    }
  }

  override def onEvent: Receive = {
    case i: Int =>
      state += i
      println(s"handled:   $i (state = $state)")
  }
}

object Example extends App {
  val system = ActorSystem("example")
  val log = system.actorOf(LeveldbEventLog.props("example"))
  val actor = system.actorOf(Props(new Example(log)))

  actor ! 1
  actor ! 2
  actor ! 3
}

It works as expected. A first run prints:

handled:   1 (state = 1)
persisted: 1 (state = 1)
handled:   2 (state = 3)
persisted: 2 (state = 3)
handled:   3 (state = 6)
persisted: 3 (state = 6)

and a second run:

handled:   1 (state = 1)
handled:   2 (state = 3)
handled:   3 (state = 6)
handled:   1 (state = 7)
persisted: 1 (state = 7)
handled:   2 (state = 9)
persisted: 2 (state = 9)
handled:   3 (state = 12)
persisted: 3 (state = 12)

Can you please provide a complete running example so that I can reproduce?

Martin Krasser
@krasserm
Dec 28 2015 06:25

@mikem EventsourcedView and EventsourcedActor extend akka.actor.Stash which can be used for user stash operations. So yes, using stash() and unstashAll() in EventsourcedView and EventsourcedActor is safe. The MessageStash class is only used internally for separating internal stash operations from user stash operations.

The stash tests in EventsourcedActorSpec only test the relative order of Ping command processing. They don't test the relative order of command and event processing (as they use independent test probes for it). You're completely right that this can be improved by additionally testing the relative order of command and event processing. I just pushed RBMHTechnology/eventuate@345334e which does that. If you're now swapping the lines you mentioned, the test fails. Thanks for the hint!

Alexander Semenov
@Tvaroh
Dec 28 2015 06:28
Martin, you're calling persist synchronously while I do some async call first, then map its result (Future) and in that lambda do persist.
Martin Krasser
@krasserm
Dec 28 2015 06:30
You must call persist on the actor dispatcher thread. Calling it inside Future(...) or in one of its combinators/callbacks is not allowed.
When your async operation completes, send a the result to self and make the persist call then. Saying that, you should consider making the async call outside the actor and send the result to it.
Alexander Semenov
@Tvaroh
Dec 28 2015 06:33
aha, thanks for the hint, I will try
Martin Krasser
@krasserm
Dec 28 2015 06:34
btw, persist is an asynchronous operation i.e. does not block until the event is persisted.
Alexander Semenov
@Tvaroh
Dec 28 2015 06:34
yep, I understand
Martin Krasser
@krasserm
Dec 28 2015 06:36
In contrast to a Future.onComplete handler, however, the persist handler is called on an actor dispatcher thread too, so it's safe to access actor state within it.
If you think this needs further clarification in the docs, please create a PR which adds it to http://rbmhtechnology.github.io/eventuate/reference/event-sourcing.html#command-handler
Alexander Semenov
@Tvaroh
Dec 28 2015 09:46
Got it, thank you, Martin.
Martin Krasser
@krasserm
Dec 28 2015 13:05
You're welcome!
Alexander Semenov
@Tvaroh
Dec 28 2015 13:42
@krasserm what is the correct way to handle messages that are neither commands nor events in eventsourced-actor? Is it okay to define standard def receive like in an ordinary actor?
it will override behavior from EventsourcedView then...
so, that should probably be another command to persist events, right?
Martin Krasser
@krasserm
Dec 28 2015 13:54
@mikem I found an issue with user stash operations that interleave with internal stash operations #182. This should be fixed soon.
Mike Mazur
@mikem
Dec 28 2015 13:57
@krasserm great, glad we poked at it today
Martin Krasser
@krasserm
Dec 28 2015 13:58
@Tvaroh all messages that are not events must be handled in onCommand. Also, def receive is final in EventsourcedView.
Alexander Semenov
@Tvaroh
Dec 28 2015 13:58
awesome, thanks
Mike Mazur
@mikem
Dec 28 2015 13:58
Actually could you clarify the significance of the second parameter to processWrite in those specs? Should it increment with each call? The first two are 1, then the next two are 3 and 4.
Martin Krasser
@krasserm
Dec 28 2015 14:01
@mikem yes, it should increment, that's wrong in the test. For that test, however, it is not relevant, but I'll fix that anyway.
@mikem thanks for helping revealing #182 :smiley:
Mike Mazur
@mikem
Dec 28 2015 14:07
:+1:
Alexander Semenov
@Tvaroh
Dec 28 2015 19:55
@krasserm, do you think it's okay for an eventsourced actor to have private transient mutable state (read: var) side by side with "distributed" state managed by events?