Handle some corner case states when receiving StartEntity (#29176)

This commit is contained in:
Johan Andrén 2020-06-04 10:52:53 +02:00 committed by GitHub
parent 1254595c7d
commit 078d7bd2fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 199 additions and 10 deletions

View file

@ -738,21 +738,28 @@ private[akka] class Shard(
ackTo.foreach(_ ! ShardRegion.StartEntityAck(entityId, shardId))
case _: RememberingStart =>
entities.rememberingStart(entityId, ackTo)
case RememberedButNotCreated =>
// already remembered, just start it - this will be the normal path for initially remembered entities
log.debug("Request to start (already remembered) entity [{}]", entityId)
case state @ (RememberedButNotCreated | WaitingForRestart) =>
// already remembered or waiting for backoff to restart, just start it -
// this is the normal path for initially remembered entities getting started
log.debug("Request to start entity [{}] (in state [{}])", entityId, state)
getOrCreateEntity(entityId)
touchLastMessageTimestamp(entityId)
ackTo.foreach(_ ! ShardRegion.StartEntityAck(entityId, shardId))
case Passivating(_) =>
// since StartEntity is handled in deliverMsg we can buffer a StartEntity to handle when
// passivation completes (triggering an immediate restart)
messageBuffers.append(entityId, ShardRegion.StartEntity(entityId), ackTo.getOrElse(ActorRef.noSender))
case RememberingStop =>
// Optimally: if stop is already write in progress, we want to stash, if it is batched for later write we'd want to cancel
// but for now
stash()
case NoState =>
// started manually from the outside, or the shard id extractor was changed since the entity was remembered
// we need to store that it was started
log.debug("Request to start entity [{}] and ack to [{}]", entityId, ackTo)
entities.rememberingStart(entityId, ackTo)
rememberUpdate(add = Set(entityId))
case other =>
// FIXME what do we do here?
throw new IllegalStateException(s"Unhandled state when wanting to start $entityId: $other")
}
}
@ -858,8 +865,7 @@ private[akka] class Shard(
if (entities.isPassivating(id)) {
log.debug("Passivation already in progress for [{}]. Not sending stopMessage back to entity", id)
} else if (messageBuffers.getOrEmpty(id).nonEmpty) {
log.debug("Passivation when there are buffered messages for [{}], ignoring", id)
// FIXME should we buffer the stop message then?
log.debug("Passivation when there are buffered messages for [{}], ignoring passivation", id)
} else {
if (verboseDebug)
log.debug("Passivation started for [{}]", id)
@ -924,7 +930,7 @@ private[akka] class Shard(
} else {
if (verboseDebug)
log.debug("StartEntity({}) from [{}], starting", start.entityId, snd)
startEntity(start.entityId, Some(sender()))
startEntity(start.entityId, Some(snd))
}
case _ =>
entities.entityState(entityId) match {
@ -1010,7 +1016,8 @@ private[akka] class Shard(
// Now there is no deliveryBuffer we can try to redeliver
// and as the child exists, the message will be directly forwarded
messages.foreach {
case (msg, snd) => deliverMessage(msg, snd)
case (ShardRegion.StartEntity(entityId), snd) => startEntity(entityId, Some(snd))
case (msg, snd) => deliverMessage(msg, snd)
}
touchLastMessageTimestamp(entityId)
}