He-Pin opened a new issue, #3691:
URL: https://github.com/apache/pekko/issues/3691

   ## Summary
   
   `ClusterShardingGuardian` creates one `Replicator` per role as its own child 
and caches the `ActorRef`, but never watches it. If the replicator stops, the 
cached ref stays in the map and is handed out to every later caller, so the 
remember-entities store and the shard coordinator end up sending to dead 
letters with no path to recovery.
   
   ## Evidence
   
   
`cluster-sharding/src/main/scala/org/apache/pekko/cluster/sharding/ClusterSharding.scala:723`
 declares the guardian; `:731` the cache; `:751-764` the accessor:
   
   ```scala
     private def replicator(role: Option[String], settings: 
ClusterShardingSettings): ActorRef = {
       // one Replicator per role
       replicatorByRole.get(role) match {
         case Some(ref) => ref
         case None      =>
           val name = role match {
             case Some(r) => URLEncoder.encode(r, StandardCharsets.UTF_8) + 
"Replicator"
             case None    => "replicator"
           }
           val ref = context.actorOf(Replicator.props(replicatorSettings(role, 
settings)), name)
           replicatorByRole = replicatorByRole.updated(role, ref)
           ref
       }
     }
   ```
   
   The file contains no `context.watch` and no `case Terminated` at all. 
`Replicator.props` 
(`distributed-data/src/main/scala/org/apache/pekko/cluster/ddata/Replicator.scala:365-370`)
 is a plain `Props` with no backoff supervision:
   
   ```scala
     def props(settings: ReplicatorSettings): Props = {
       require(
         settings.durableKeys.isEmpty || (settings.durableStoreProps != 
Right(Props.empty)),
         "durableStoreProps must be defined when durableKeys are defined")
       Props(new 
Replicator(settings)).withDeploy(Deploy.local).withDispatcher(settings.dispatcher)
     }
   ```
   
   Callers of `replicator(...)` are `:783` (the 
`DdataRememberEntitiesShardStore` / coordinator store) and `:809` (the 
coordinator itself).
   
   ## When the replicator actually stops
   
   The default supervision strategy restarts, and a restart preserves the 
`ActorRef`, so an ordinary failure does not trigger this. The reachable path is 
the replicator stopping *itself* — `Replicator.scala:2468-2470`:
   
   ```scala
     def receiveMemberRemoved(m: Member): Unit = {
       if (m.address == selfAddress)
         context.stop(self)
   ```
   
   reached from the dispatch at `:1620-1621`:
   
   ```scala
       case MemberRemoved(m, _) => receiveMemberRemoved(m)
       case ClusterShuttingDown => receiveMemberRemoved(cluster.selfMember)
   ```
   
   So a node that is removed from the cluster (or whose cluster shuts down) 
stops its replicator while the guardian keeps the stale ref. Any later 
`replicator(role, settings)` call — for example starting a shard region again 
on the same `ActorSystem` after rejoining — returns the dead ref.
   
   ## Impact
   
   Remember-entities reads and writes, and coordinator state propagation, 
silently go to dead letters. There is no log line pointing at the cause and no 
automatic re-creation, so the shard type is unusable for the lifetime of that 
`ActorSystem`.
   
   ## Suggested direction
   
   `context.watch` the replicator when caching it and drop the 
`replicatorByRole` entry on `Terminated`, so the next `replicator(...)` call 
creates a fresh one. Whether a stale-ref caller should instead fail fast is a 
separate question, but at minimum the cache should not keep serving a ref known 
to be dead.
   
   ## Test
   
   
`cluster-sharding/src/test/scala/org/apache/pekko/cluster/sharding/ClusterShardingLeaseSpec.scala`
 and `ShardWithLeaseSpec.scala` already build sharding setups over `TestLease`; 
a ddata-mode case can watch the replicator, stop it, then start another shard 
region of the same type and assert the new replicator is alive rather than a 
terminated ref.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to