code: private void initializeAppLauncherAndServices() throws Exception {
      // Done to preserve backwards compatibility with the previously hard-coded timeout of 5 minutes
      Properties properties = ConfigUtils.configToProperties(this.config);
      if (!properties.contains(ServiceBasedAppLauncher.APP_STOP_TIME_SECONDS)) {
        properties.setProperty(ServiceBasedAppLauncher.APP_STOP_TIME_SECONDS, Long.toString(300));
      }
      this.applicationLauncher = new ServiceBasedAppLauncher(properties, this.clusterName);
  
      // create a job catalog for keeping track of received jobs if a job config path is specified
      if (this.config.hasPath(GobblinClusterConfigurationKeys.GOBBLIN_CLUSTER_PREFIX
          + ConfigurationKeys.JOB_CONFIG_FILE_GENERAL_PATH_KEY)) {
        String jobCatalogClassName = ConfigUtils.getString(config, GobblinClusterConfigurationKeys.JOB_CATALOG_KEY,
            GobblinClusterConfigurationKeys.DEFAULT_JOB_CATALOG);
  
        this.jobCatalog =
            (MutableJobCatalog) GobblinConstructorUtils.invokeFirstConstructor(Class.forName(jobCatalogClassName),
            ImmutableList.of(config
                .getConfig(StringUtils.removeEnd(GobblinClusterConfigurationKeys.GOBBLIN_CLUSTER_PREFIX, "."))
                .withFallback(this.config)));
      } else {
        this.jobCatalog = null;
      }
  
      SchedulerService schedulerService = new SchedulerService(properties);
      this.applicationLauncher.addService(schedulerService);
      this.jobScheduler = buildGobblinHelixJobScheduler(config, this.appWorkDir, getMetadataTags(clusterName, applicationId),
          schedulerService);
      this.applicationLauncher.addService(this.jobScheduler);
      this.jobConfigurationManager = buildJobConfigurationManager(config);
      this.applicationLauncher.addService(this.jobConfigurationManager);
    }
docs: Create the service based application launcher and other associated services
  @throws Exception