Handling Exceptions

A component should create exceptions belonging to one of the two following types:

  1. FailureRestart : As a part of any handler, if an exception can be handled by restarting the component, an exception of type FailureRestart should be thrown to let the framework restart the component. The component’s state will be cleared/reinitialized. The onInitialize handler will be invoked again.

    Scala
    sourcecase class HcdNotFoundException() extends FailureRestart("Could not resolve hcd location. Initialization failure.")
    
    private def resolveHcd(): Future[Option[AkkaLocation]] = {
      val maybeConnection = componentInfo.connections.find(connection => connection.componentId.componentType == ComponentType.HCD)
      maybeConnection match {
        case Some(hcd) =>
          cswCtx.locationService.resolve(hcd.of[AkkaLocation], 5.seconds).map {
            case loc @ Some(akkaLocation) => loc
            case None                     =>
              // Hcd connection could not be resolved for this Assembly. One option to handle this could be to automatic restart which can give enough time
              // for the Hcd to be available
              throw HcdNotFoundException()
          }
        case _ => Future.successful(None)
      }
    }
    Java
    sourceclass HcdNotFoundException extends FailureRestart {
        HcdNotFoundException() {
            super("Could not resolve hcd location. Initialization failure.");
        }
    }
    
    private CompletableFuture<Optional<AkkaLocation>> resolveHcd() {
        // find a Hcd connection from the connections provided in componentInfo
        Optional<Connection> mayBeConnection = componentInfo.getConnections().stream()
                .filter(connection -> connection.componentId().componentType() == JComponentType.HCD)
                .findFirst();
    
        // If an Hcd is found as a connection, resolve its location from location service and create other
        // required worker actors required by this assembly
        if (mayBeConnection.isPresent()) {
            CompletableFuture<Optional<AkkaLocation>> resolve = locationService.resolve(mayBeConnection.orElseThrow().<AkkaLocation>of(), Duration.ofSeconds(5));
            return resolve.thenCompose((Optional<AkkaLocation> resolvedHcd) -> {
                if (resolvedHcd.isPresent())
                    return CompletableFuture.completedFuture(resolvedHcd);
                else
                    throw new ConfigNotAvailableException();
            });
        } else
            return CompletableFuture.completedFuture(Optional.empty());
    }
  2. FailureStop : As a part of any handler, an exception can be thrown of type FailureStop which will result in terminating the component. The onShutdown handler will be invoked to facilitate graceful shutdown.

    Scala
    sourcecase class ConfigNotAvailableException() extends FailureStop("Configuration not available. Initialization failure.")
    
    private def getAssemblyConfig: Future[ConfigData] = {
    
      configClientService.getActive(Paths.get("tromboneAssemblyContext.conf")).flatMap {
        case Some(config) => Future.successful(config) // do work
        case None         =>
          // required configuration could not be found in the configuration service. Component can choose to stop until the configuration is made available in the
          // configuration service and started again
          throw ConfigNotAvailableException()
      }
    }
    Java
    sourceclass ConfigNotAvailableException extends FailureStop {
        ConfigNotAvailableException() {
            super("Configuration not available. Initialization failure.");
        }
    }
    
    private CompletableFuture<ConfigData> getAssemblyConfig() throws ConfigNotAvailableException {
        // required configuration could not be found in the configuration service. Component can choose to stop until the configuration is made available in the
        // configuration service and started again
        return configClient.getActive(Paths.get("tromboneAssemblyContext.conf"))
                .thenApply((Optional<ConfigData> maybeConfigData) -> {
                    return maybeConfigData.<ConfigNotAvailableException>orElseThrow(() -> new ConfigNotAvailableException());
                });
    }