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

   ## Summary
   
   `startDefaultLoggers` resolves and creates each configured logger inside a 
single for-comprehension. If entry *N* cannot be resolved, entries *1..N-1* 
have already been created as system actors, but the `loggers` field is only 
assigned after the whole comprehension succeeds — so the teardown path never 
sees them.
   
   ## Evidence
   
   `actor/src/main/scala/org/apache/pekko/event/Logging.scala:137-159`:
   
   ```scala
         val myloggers =
           for {
             loggerName <- defaultLoggers
             if loggerName != StandardOutLogger.getClass.getName
           } yield {
             system.dynamicAccess
               .getClassFor[Actor](loggerName)
               .map { actorClass =>
                 addLogger(system, actorClass, level, logName)   // creates the 
actor
               }
               .recover {
                 case e =>
                   throw new ConfigurationException(
                     "Logger specified in config can't be loaded [" + 
loggerName +
                     "] due to [" + e.toString + "]", e)
               }
               .get                                              // throws here
           }
         guard.lock()
         try {
           loggers = myloggers                                   // :159 — 
never reached
   ```
   
   `addLogger` (`:216-226`) creates the actor and blocks on initialization:
   
   ```scala
       val actor = 
system.systemActorOf(Props(clazz).withDispatcher(system.settings.LoggersDispatcher),
 name)
       implicit def timeout: Timeout = system.settings.LoggerStartTimeout
       ...
         try Await.result(actor ? InitializeLogger(this), timeout.duration)
   ```
   
   `stopDefaultLoggers` (`:192-209`) iterates the `loggers` field:
   
   ```scala
       for {
         logger <- loggers
         if logger != StandardOutLogger
       } {
         // this is very necessary, else you get infinite loop with DeadLetter
         unsubscribe(logger)
         logger match {
           case ref: InternalActorRef => ref.stop()
           case _                     =>
         }
       }
   ```
   
   ## Impact
   
   With `pekko.loggers = [<valid>, <invalid>]`, the valid logger is created as 
a system actor and initialized, then the `ConfigurationException` propagates 
before `loggers = myloggers` executes. System creation fails, and 
`stopDefaultLoggers` iterates a `loggers` value that does not contain the 
already-started actor — so it is neither unsubscribed nor stopped. A 
partially-initialized logging setup outlives the failed `ActorSystem` creation.
   
   ## Suggested direction
   
   Resolve every class name first and fail fast before creating any actor, then 
create the loggers. Alternatively, accumulate successfully-created loggers so 
the failure path can unsubscribe and stop them.
   
   ## Test
   
   `actor-tests/src/test/scala/org/apache/pekko/event/LoggerSpec.scala` — a 
case configuring one valid plus one unresolvable logger, asserting that system 
creation fails with `ConfigurationException` and that the valid logger actor 
has been stopped and unsubscribed.
   


-- 
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