I had an Actor whose code grew to be quite large, so this is the result of
a refactoring.
The new class performs actions on behalf of the actor, impersonating it, so
to speak. It caries out various send operations, sets up state with
un/become, etc.
The refactor produces clearer and more testable code, although I do
appreciate why ActorContext (or any other internal state) should be handled
with caution.
My code is as follows:
*(note: CheckEmailAddressAvailability follows a similar pattern - code
omitted as you'll already get the idea!)*
class UserRegistry(fulfilRegistration: FulfilRegistration) extends
EventsourcedProcessor {
override def receiveRecover: Receive = {
case UserSubmittedRegistration(registration) =>
fulfilRegistration(registration)
}
override def receiveCommand: Receive = {
case registrationEvent: UserSubmittedRegistration =>
persist(registrationEvent) { event =>
fulfilRegistration(event.registration)
}
}
}
trait FulfilRegistration {
def apply(registration: Registration)(implicit context: ActorContext):
Unit
}
class FulfilRegistrationImpl(implicit checkEmailAddressAvailability:
CheckEmailAddressAvailability)
extends FulfilRegistration{
def apply(registration: Registration)(implicit context: ActorContext):
Unit =
FulfilRegistration
.beginTransaction(registration)
}
object FulfilRegistration {
def beginTransaction(registration: Registration)(implicit context:
ActorContext, checkEmailAddressAvailability:
CheckEmailAddressAvailability): Unit = {
val name = transactionActorName(registration.newUserId)
val actorRef = context.actorOf(transactionProps, name)
actorRef forward registration
}
def transactionActorName(userId: UserId): String =
userId.toString
private def transactionProps(implicit checkEmailAddressAvailability:
CheckEmailAddressAvailability): Props =
Props(new RecoverableActor {
override protected def initialState: Receive = notRegistered
override def receiveRecover: Receive = {
case UserRegistered() =>
context stop self
case RegistrationDeniedDueToDuplicateEmail() =>
context stop self
}
private def notRegistered: Receive = {
case Registration(newUserId, _, EmailCredential(emailAddress, _)) =>
val registrant = sender()
def allowRegistration(): Unit = {
val event = UserRegistered()
registrant ! event // Informing registrant is part of the
registration so occurs before committing the event.
persist(event) { _ =>
context stop self
}
}
def denyRegistration(): Unit = {
val event = RegistrationDeniedDueToDuplicateEmail()
registrant ! event // Informing registrant is part of the
denial so occurs before committing the event.
persist(event) { _ =>
context stop self
}
}
checkEmailAddressAvailability(emailAddress) {
emailAddressAvailable =>
if (emailAddressAvailable)
allowRegistration()
else
denyRegistration()
}
}
})
}
On Wednesday, May 28, 2014 4:45:52 PM UTC+1, Konrad Malawski wrote:
>
> We strongly advertise against exposing your ActorContext - it's scary what
> could happen with it being accessed from outside of the respective actor.
>
> What's your use case? Perhaps there is a better way to test / abstract it?
>
>
> On Wed, May 28, 2014 at 4:56 PM, Lawrence Wagerfield <
> [email protected] <javascript:>> wrote:
>
>> Hi Konrad,
>>
>> I'm currently using TestActorRef to obtain the underlying ActorContext.
>> I am using this to assert the actor is passing its own context as an
>> argument to a mocked-out dependency.
>>
>> Can you think of another way using existing TestKit probes, or is this
>> the best way?
>>
>> Thanks,
>> Lawrence
>>
>>
>>
>> On Wednesday, May 28, 2014 3:48:26 PM UTC+1, Konrad Malawski wrote:
>>
>>> Hello Lawrence,
>>> Because of the processor’s inner workings (how it interacts with the
>>> Journal) it does not make sense to test it using the *synchronous* test
>>> utilities (such as TestActorRef).
>>> Please do not use TestActorRef with Akka-Persistence - use the plain
>>> TestKit and it’s probes and other utils.
>>>
>>> // We had such issue reported, and marked as won’t fix
>>> https://github.com/akka/akka/issues/15293
>>>
>>>
>>>
>>> On Wed, May 28, 2014 at 4:20 PM, Lawrence Wagerfield <
>>> [email protected]> wrote:
>>>
>>>> Using TestActorRef on implementations of Processor (and
>>>> EventsourcedProcessor) appears to introduce a deadlock at the point of
>>>> calling into the snapshot store actor.
>>>>
>>>> The result is an actor-under-test that never completes recovery.
>>>>
>>>> I have worked-around this issue by providing .withDispatcher(
>>>> Dispatchers.DefaultDispatcherId) on the Props object I construct the
>>>> TestActorRef with.
>>>>
>>>> Should I raise this as an issue? Currently using Akka 2.3.3.
>>>>
>>>> --
>>>> >>>>>>>>>> Read the docs: http://akka.io/docs/
>>>> >>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/
>>>> current/additional/faq.html
>>>> >>>>>>>>>> Search the archives: https://groups.google.com/
>>>> group/akka-user
>>>> ---
>>>> You received this message because you are subscribed to the Google
>>>> Groups "Akka User List" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>> an email to [email protected].
>>>> To post to this group, send email to [email protected].
>>>>
>>>> Visit this group at http://groups.google.com/group/akka-user.
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>>
>>>
>>> --
>>> Cheers,
>>> Konrad 'ktoso' Malawski
>>> hAkker - Typesafe, Inc
>>>
>>> <http://scaladays.org>
>>>
>> --
>> >>>>>>>>>> Read the docs: http://akka.io/docs/
>> >>>>>>>>>> Check the FAQ:
>> http://doc.akka.io/docs/akka/current/additional/faq.html
>> >>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Akka User List" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected]<javascript:>
>> .
>> Visit this group at http://groups.google.com/group/akka-user.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
>
> --
> Cheers,
> Konrad 'ktoso' Malawski
> hAkker - Typesafe, Inc
>
> <http://scaladays.org>
>
--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ:
>>>>>>>>>> http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka
User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.