Reputation: 1007
I want to know if the following code will close over the id value in the ask 'callback' in the map function.
val id = if (model.id.isEmpty) UUID.randomUUID().toString else model.id
val result = couchbaseActor ? SetDoc(s"user:$id", model.toJson.compactPrint)
result map {
case true => sender ! Right(Success(id))
case false => sender ! Left(makeFailureFromErrorEnum(ErrorCode.DbSaveFailed, List("User", "Error occurred while saving to Couchbase")))
}
Thanks, Aaron
Eventual Solution:
Message Handler:
case SaveUserReq(model) => saveDocument[User](sender, "User", model.id, model)
Definition:
def saveDocument[T:JsonWriter](requester: ActorRef, prefix: String, id: String, model: T): Unit = {
couchbaseActor ? SetDoc(s"${prefix.toLowerCase}:$id", model.toJson.compactPrint) map {
case true => requester ! Right(Success(id))
case false => requester ! Left(makeFailureFromErrorEnum(ErrorCode.DbSaveFailed, List(prefix, errorCouchbaseSaveFailed)))
}
}
Thank you to all who assisted.
Upvotes: 2
Views: 225
Reputation: 2401
Well, I think that id
is used as is. It is a constant, isn't it?
Victor Klang gives the source of error: the access to sender
method of this
actor. Your code actually looks like
val id = if (model.id.isEmpty) UUID.randomUUID().toString else model.id
val result = couchbaseActor ? SetDoc(s"user:$id", model.toJson.compactPrint)
result map {
case true => this.sender.tell(Right(Success(id)), self)
case false => this.sender.tell(Left(makeFailureFromErrorEnum(ErrorCode.DbSaveFailed, List("User", "Error occurred while saving to Couchbase"))), self)
}
It seems that it closes over this
.
Probably rewriting the code the following way:
val id = if (model.id.isEmpty) UUID.randomUUID().toString else model.id
val theSender = sender
val result = couchbaseActor ? SetDoc(s"user:$id", model.toJson.compactPrint)
result map {
case true => theSender ! Right(Success(id))
case false => theSender ! Left(makeFailureFromErrorEnum(ErrorCode.DbSaveFailed, List("User", "Error occurred while saving to Couchbase")))
}
can help.
Upvotes: 2
Reputation: 26579
sender/getSender() disappears when I use Future in my Actor, why?
"When using future callbacks, inside actors you need to carefully avoid closing over the containing actor’s reference, i.e. do not call methods or access mutable state on the enclosing actor from within the callback. This breaks the actor encapsulation and may introduce synchronization bugs and race conditions because the callback will be scheduled concurrently to the enclosing actor. Unfortunately there is not yet a way to detect these illegal accesses at compile time.
Read more about it in the docs for Actors and the JMM"
Upvotes: 3