Search in sources :

Example 11 with ProgramRunner

use of io.cdap.cdap.app.runtime.ProgramRunner in project cdap by caskdata.

the class DefaultRuntimeJob method run.

@Override
public void run(RuntimeJobEnvironment runtimeJobEnv) throws Exception {
    // Setup process wide settings
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
    SLF4JBridgeHandler.removeHandlersForRootLogger();
    SLF4JBridgeHandler.install();
    // Get Program Options
    ProgramOptions programOpts = readJsonFile(new File(DistributedProgramRunner.PROGRAM_OPTIONS_FILE_NAME), ProgramOptions.class);
    ProgramRunId programRunId = programOpts.getProgramId().run(ProgramRunners.getRunId(programOpts));
    ProgramId programId = programRunId.getParent();
    Arguments systemArgs = programOpts.getArguments();
    // Setup logging context for the program
    LoggingContextAccessor.setLoggingContext(LoggingContextHelper.getLoggingContextWithRunId(programRunId, systemArgs.asMap()));
    // Get the cluster launch type
    Cluster cluster = GSON.fromJson(systemArgs.getOption(ProgramOptionConstants.CLUSTER), Cluster.class);
    // Get App spec
    ApplicationSpecification appSpec = readJsonFile(new File(DistributedProgramRunner.APP_SPEC_FILE_NAME), ApplicationSpecification.class);
    ProgramDescriptor programDescriptor = new ProgramDescriptor(programId, appSpec);
    // Create injector and get program runner
    Injector injector = Guice.createInjector(createModules(runtimeJobEnv, createCConf(runtimeJobEnv, programOpts), programRunId, programOpts));
    CConfiguration cConf = injector.getInstance(CConfiguration.class);
    // Initialize log appender
    LogAppenderInitializer logAppenderInitializer = injector.getInstance(LogAppenderInitializer.class);
    logAppenderInitializer.initialize();
    SystemArguments.setLogLevel(programOpts.getUserArguments(), logAppenderInitializer);
    ProxySelector oldProxySelector = ProxySelector.getDefault();
    RuntimeMonitors.setupMonitoring(injector, programOpts);
    Deque<Service> coreServices = createCoreServices(injector, systemArgs, cluster);
    startCoreServices(coreServices);
    // regenerate app spec
    ConfiguratorFactory configuratorFactory = injector.getInstance(ConfiguratorFactory.class);
    try {
        Map<String, String> systemArguments = new HashMap<>(programOpts.getArguments().asMap());
        File pluginDir = new File(programOpts.getArguments().getOption(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR));
        // create a directory to store plugin artifacts for the regeneration of app spec to fetch plugin artifacts
        DirUtils.mkdirs(pluginDir);
        if (!programOpts.getArguments().hasOption(ProgramOptionConstants.PLUGIN_DIR)) {
            systemArguments.put(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR);
        }
        // remember the file names in the artifact folder before app regeneration
        List<String> pluginFiles = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
        ApplicationSpecification generatedAppSpec = regenerateAppSpec(systemArguments, programOpts.getUserArguments().asMap(), programId, appSpec, programDescriptor, configuratorFactory);
        appSpec = generatedAppSpec != null ? generatedAppSpec : appSpec;
        programDescriptor = new ProgramDescriptor(programDescriptor.getProgramId(), appSpec);
        List<String> pluginFilesAfter = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
        if (pluginFilesAfter.isEmpty()) {
            systemArguments.remove(ProgramOptionConstants.PLUGIN_DIR);
        }
        // recreate it from the folders
        if (!pluginFiles.equals(pluginFilesAfter)) {
            systemArguments.remove(ProgramOptionConstants.PLUGIN_ARCHIVE);
        }
        // update program options
        programOpts = new SimpleProgramOptions(programOpts.getProgramId(), new BasicArguments(systemArguments), programOpts.getUserArguments(), programOpts.isDebug());
    } catch (Exception e) {
        LOG.warn("Failed to regenerate the app spec for program {}, using the existing app spec", programId, e);
    }
    ProgramStateWriter programStateWriter = injector.getInstance(ProgramStateWriter.class);
    RuntimeClientService runtimeClientService = injector.getInstance(RuntimeClientService.class);
    CompletableFuture<ProgramController.State> programCompletion = new CompletableFuture<>();
    try {
        ProgramRunner programRunner = injector.getInstance(ProgramRunnerFactory.class).create(programId.getType());
        // Create and run the program. The program files should be present in current working directory.
        try (Program program = createProgram(cConf, programRunner, programDescriptor, programOpts)) {
            ProgramController controller = programRunner.run(program, programOpts);
            controllerFuture.complete(controller);
            runtimeClientService.onProgramStopRequested(controller::stop);
            controller.addListener(new AbstractListener() {

                @Override
                public void completed() {
                    programCompletion.complete(ProgramController.State.COMPLETED);
                }

                @Override
                public void killed() {
                    // Write an extra state to make sure there is always a terminal state even
                    // if the program application run failed to write out the state.
                    programStateWriter.killed(programRunId);
                    programCompletion.complete(ProgramController.State.KILLED);
                }

                @Override
                public void error(Throwable cause) {
                    // Write an extra state to make sure there is always a terminal state even
                    // if the program application run failed to write out the state.
                    programStateWriter.error(programRunId, cause);
                    programCompletion.completeExceptionally(cause);
                }
            }, Threads.SAME_THREAD_EXECUTOR);
            if (stopRequested) {
                controller.stop();
            }
            // Block on the completion
            programCompletion.get();
        } finally {
            if (programRunner instanceof Closeable) {
                Closeables.closeQuietly((Closeable) programRunner);
            }
        }
    } catch (Throwable t) {
        controllerFuture.completeExceptionally(t);
        if (!programCompletion.isDone()) {
            // We log here so that the logs would still send back to the program logs collection.
            // Only log if the program completion is not done.
            // Otherwise the program runner itself should have logged the error.
            LOG.error("Failed to execute program {}", programRunId, t);
            // If the program completion is not done, then this exception
            // is due to systematic failure in which fail to run the program.
            // We write out an extra error state for the program to make sure the program state get transited.
            programStateWriter.error(programRunId, t);
        }
        throw t;
    } finally {
        stopCoreServices(coreServices, logAppenderInitializer);
        ProxySelector.setDefault(oldProxySelector);
        Authenticator.setDefault(null);
        runCompletedLatch.countDown();
    }
}
Also used : ApplicationSpecification(io.cdap.cdap.api.app.ApplicationSpecification) ConfiguratorFactory(io.cdap.cdap.internal.app.deploy.ConfiguratorFactory) HashMap(java.util.HashMap) Closeable(java.io.Closeable) ProgramRunnerFactory(io.cdap.cdap.app.runtime.ProgramRunnerFactory) DefaultProgramRunnerFactory(io.cdap.cdap.app.guice.DefaultProgramRunnerFactory) ProxySelector(java.net.ProxySelector) LogAppenderInitializer(io.cdap.cdap.logging.appender.LogAppenderInitializer) CompletableFuture(java.util.concurrent.CompletableFuture) ProgramStateWriter(io.cdap.cdap.app.runtime.ProgramStateWriter) MessagingProgramStateWriter(io.cdap.cdap.internal.app.program.MessagingProgramStateWriter) Injector(com.google.inject.Injector) AbstractListener(io.cdap.cdap.internal.app.runtime.AbstractListener) ProgramDescriptor(io.cdap.cdap.app.program.ProgramDescriptor) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) UncaughtExceptionHandler(io.cdap.cdap.common.logging.common.UncaughtExceptionHandler) DistributedProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedProgramRunner) DistributedMapReduceProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedMapReduceProgramRunner) DistributedWorkerProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedWorkerProgramRunner) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner) DistributedWorkflowProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedWorkflowProgramRunner) RuntimeClientService(io.cdap.cdap.internal.app.runtime.monitor.RuntimeClientService) ProgramController(io.cdap.cdap.app.runtime.ProgramController) Program(io.cdap.cdap.app.program.Program) Arguments(io.cdap.cdap.app.runtime.Arguments) SystemArguments(io.cdap.cdap.internal.app.runtime.SystemArguments) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) Cluster(io.cdap.cdap.runtime.spi.provisioner.Cluster) RuntimeClientService(io.cdap.cdap.internal.app.runtime.monitor.RuntimeClientService) Service(com.google.common.util.concurrent.Service) ProfileMetricService(io.cdap.cdap.internal.profile.ProfileMetricService) LogAppenderLoaderService(io.cdap.cdap.logging.appender.loader.LogAppenderLoaderService) MessagingService(io.cdap.cdap.messaging.MessagingService) AbstractIdleService(com.google.common.util.concurrent.AbstractIdleService) MessagingHttpService(io.cdap.cdap.messaging.server.MessagingHttpService) MetricsCollectionService(io.cdap.cdap.api.metrics.MetricsCollectionService) ProgramId(io.cdap.cdap.proto.id.ProgramId) CConfiguration(io.cdap.cdap.common.conf.CConfiguration) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) ProgramOptions(io.cdap.cdap.app.runtime.ProgramOptions) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) File(java.io.File)

Example 12 with ProgramRunner

use of io.cdap.cdap.app.runtime.ProgramRunner in project cdap by caskdata.

the class DistributedWorkflowProgramRunner method setupLaunchConfig.

@Override
protected void setupLaunchConfig(ProgramLaunchConfig launchConfig, Program program, ProgramOptions options, CConfiguration cConf, Configuration hConf, File tempDir) throws IOException {
    WorkflowSpecification spec = program.getApplicationSpecification().getWorkflows().get(program.getName());
    List<ClassAcceptor> acceptors = new ArrayList<>();
    acceptors.add(launchConfig.getClassAcceptor());
    // Only interested in MapReduce and Spark nodes.
    // This is because CUSTOM_ACTION types are running inside the driver
    Set<SchedulableProgramType> runnerTypes = EnumSet.of(SchedulableProgramType.MAPREDUCE, SchedulableProgramType.SPARK);
    Iterable<ScheduleProgramInfo> programInfos = spec.getNodeIdMap().values().stream().filter(WorkflowActionNode.class::isInstance).map(WorkflowActionNode.class::cast).map(WorkflowActionNode::getProgram).filter(programInfo -> runnerTypes.contains(programInfo.getProgramType()))::iterator;
    // Can't use Stream.forEach as we want to preserve the IOException being thrown
    for (ScheduleProgramInfo programInfo : programInfos) {
        ProgramType programType = ProgramType.valueOfSchedulableType(programInfo.getProgramType());
        ProgramRunner runner = programRunnerFactory.create(programType);
        try {
            if (runner instanceof DistributedProgramRunner) {
                // Call setupLaunchConfig with the corresponding program.
                // Need to constructs a new ProgramOptions with the scope extracted for the given program
                ProgramId programId = program.getId().getParent().program(programType, programInfo.getProgramName());
                Map<String, String> programUserArgs = RuntimeArguments.extractScope(programId.getType().getScope(), programId.getProgram(), options.getUserArguments().asMap());
                ProgramOptions programOptions = new SimpleProgramOptions(programId, options.getArguments(), new BasicArguments(programUserArgs));
                ((DistributedProgramRunner) runner).setupLaunchConfig(launchConfig, Programs.create(cConf, program, programId, runner), programOptions, cConf, hConf, tempDir);
                acceptors.add(launchConfig.getClassAcceptor());
            }
        } finally {
            if (runner instanceof Closeable) {
                Closeables.closeQuietly((Closeable) runner);
            }
        }
    }
    // Set the class acceptor
    launchConfig.setClassAcceptor(new AndClassAcceptor(acceptors));
    // Find out the default resources requirements based on the programs inside the workflow
    // At least gives the Workflow driver 768 mb of container memory
    Map<String, Resources> runnablesResources = Maps.transformValues(launchConfig.getRunnables(), this::getResources);
    Resources defaultResources = maxResources(new Resources(768), findDriverResources(spec.getNodes(), runnablesResources));
    // Clear and set the runnable for the workflow driver.
    launchConfig.clearRunnables();
    // Extract scoped runtime arguments that only meant for the workflow but not for child nodes
    Map<String, String> runtimeArgs = RuntimeArguments.extractScope("task", "workflow", options.getUserArguments().asMap());
    launchConfig.addRunnable(spec.getName(), new WorkflowTwillRunnable(spec.getName()), 1, runtimeArgs, defaultResources, 0);
}
Also used : URL(java.net.URL) Inject(com.google.inject.Inject) LoggerFactory(org.slf4j.LoggerFactory) ClusterMode(io.cdap.cdap.app.guice.ClusterMode) ProgramRunnerFactory(io.cdap.cdap.app.runtime.ProgramRunnerFactory) Resources(io.cdap.cdap.api.Resources) WorkflowNode(io.cdap.cdap.api.workflow.WorkflowNode) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) Configuration(org.apache.hadoop.conf.Configuration) Map(java.util.Map) Closeables(com.google.common.io.Closeables) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner) EnumSet(java.util.EnumSet) TwillController(org.apache.twill.api.TwillController) Collection(java.util.Collection) ApplicationSpecification(io.cdap.cdap.api.app.ApplicationSpecification) WorkflowNodeType(io.cdap.cdap.api.workflow.WorkflowNodeType) ResourceSpecification(org.apache.twill.api.ResourceSpecification) Set(java.util.Set) SchedulableProgramType(io.cdap.cdap.api.schedule.SchedulableProgramType) ScheduleProgramInfo(io.cdap.cdap.api.workflow.ScheduleProgramInfo) List(java.util.List) Constants(io.cdap.cdap.common.conf.Constants) Workflow(io.cdap.cdap.api.workflow.Workflow) WorkflowForkNode(io.cdap.cdap.api.workflow.WorkflowForkNode) WorkflowSpecification(io.cdap.cdap.api.workflow.WorkflowSpecification) Program(io.cdap.cdap.app.program.Program) Programs(io.cdap.cdap.app.program.Programs) ProgramType(io.cdap.cdap.proto.ProgramType) ArrayList(java.util.ArrayList) YarnConfiguration(org.apache.hadoop.yarn.conf.YarnConfiguration) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) ProgramOptions(io.cdap.cdap.app.runtime.ProgramOptions) TwillRunner(org.apache.twill.api.TwillRunner) SystemArguments(io.cdap.cdap.internal.app.runtime.SystemArguments) WorkflowActionNode(io.cdap.cdap.api.workflow.WorkflowActionNode) ClassAcceptor(org.apache.twill.api.ClassAcceptor) ProgramController(io.cdap.cdap.app.runtime.ProgramController) Logger(org.slf4j.Logger) RuntimeArguments(io.cdap.cdap.api.common.RuntimeArguments) ProgramId(io.cdap.cdap.proto.id.ProgramId) Impersonator(io.cdap.cdap.security.impersonation.Impersonator) IOException(java.io.IOException) Maps(com.google.common.collect.Maps) File(java.io.File) CConfiguration(io.cdap.cdap.common.conf.CConfiguration) Closeable(java.io.Closeable) Preconditions(com.google.common.base.Preconditions) WorkflowConditionNode(io.cdap.cdap.api.workflow.WorkflowConditionNode) Collections(java.util.Collections) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) WorkflowActionNode(io.cdap.cdap.api.workflow.WorkflowActionNode) Closeable(java.io.Closeable) ArrayList(java.util.ArrayList) ClassAcceptor(org.apache.twill.api.ClassAcceptor) ProgramId(io.cdap.cdap.proto.id.ProgramId) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) ProgramOptions(io.cdap.cdap.app.runtime.ProgramOptions) WorkflowSpecification(io.cdap.cdap.api.workflow.WorkflowSpecification) SchedulableProgramType(io.cdap.cdap.api.schedule.SchedulableProgramType) SchedulableProgramType(io.cdap.cdap.api.schedule.SchedulableProgramType) ProgramType(io.cdap.cdap.proto.ProgramType) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) Resources(io.cdap.cdap.api.Resources) ScheduleProgramInfo(io.cdap.cdap.api.workflow.ScheduleProgramInfo) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner)

Example 13 with ProgramRunner

use of io.cdap.cdap.app.runtime.ProgramRunner in project cdap by caskdata.

the class InMemoryProgramRunnerModule method configure.

/**
 * Configures a {@link com.google.inject.Binder} via the exposed methods.
 */
@Override
protected void configure() {
    // Bind ServiceAnnouncer for service.
    bind(ServiceAnnouncer.class).to(DiscoveryServiceAnnouncer.class);
    // Bind the ArtifactManager implementation and expose it.
    // It could used by ProgramRunner loaded through runtime extension.
    install(new FactoryModuleBuilder().implement(ArtifactManager.class, LocalArtifactManager.class).build(ArtifactManagerFactory.class));
    expose(ArtifactManagerFactory.class);
    // Bind ProgramRunner
    MapBinder<ProgramType, ProgramRunner> runnerFactoryBinder = MapBinder.newMapBinder(binder(), ProgramType.class, ProgramRunner.class);
    // Programs with multiple instances have an InMemoryProgramRunner that starts threads to manage all of their
    // instances.
    runnerFactoryBinder.addBinding(ProgramType.MAPREDUCE).to(MapReduceProgramRunner.class);
    runnerFactoryBinder.addBinding(ProgramType.WORKFLOW).to(WorkflowProgramRunner.class);
    runnerFactoryBinder.addBinding(ProgramType.WORKER).to(InMemoryWorkerRunner.class);
    runnerFactoryBinder.addBinding(ProgramType.SERVICE).to(InMemoryServiceProgramRunner.class);
    // Bind program runners in private scope
    // They should only be used by the ProgramRunners in the runnerFactoryBinder
    bind(ServiceProgramRunner.class);
    bind(WorkerProgramRunner.class);
    // ProgramRunnerFactory should be in local mode
    bind(ProgramRuntimeProvider.Mode.class).toInstance(ProgramRuntimeProvider.Mode.LOCAL);
    bind(ProgramRunnerFactory.class).to(DefaultProgramRunnerFactory.class).in(Scopes.SINGLETON);
    // Note: Expose for test cases. Need to refactor test cases.
    expose(ProgramRunnerFactory.class);
    // Bind and expose runtime service
    bind(ProgramRuntimeService.class).to(InMemoryProgramRuntimeService.class).in(Scopes.SINGLETON);
    expose(ProgramRuntimeService.class);
}
Also used : FactoryModuleBuilder(com.google.inject.assistedinject.FactoryModuleBuilder) ArtifactManagerFactory(io.cdap.cdap.internal.app.runtime.artifact.ArtifactManagerFactory) InMemoryProgramRuntimeService(io.cdap.cdap.internal.app.runtime.service.InMemoryProgramRuntimeService) ProgramType(io.cdap.cdap.proto.ProgramType) WorkerProgramRunner(io.cdap.cdap.internal.app.runtime.worker.WorkerProgramRunner) WorkflowProgramRunner(io.cdap.cdap.internal.app.runtime.workflow.WorkflowProgramRunner) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner) ServiceProgramRunner(io.cdap.cdap.internal.app.runtime.service.ServiceProgramRunner) MapReduceProgramRunner(io.cdap.cdap.internal.app.runtime.batch.MapReduceProgramRunner) InMemoryServiceProgramRunner(io.cdap.cdap.internal.app.runtime.service.InMemoryServiceProgramRunner) ServiceAnnouncer(org.apache.twill.api.ServiceAnnouncer)

Example 14 with ProgramRunner

use of io.cdap.cdap.app.runtime.ProgramRunner in project cdap by caskdata.

the class DefaultProgramRunnerFactory method create.

@Override
public ProgramRunner create(ProgramType programType) {
    ProgramRuntimeProvider provider = runtimeProviderLoader.get(programType);
    ProgramRunner runner;
    if (provider != null) {
        LOG.trace("Using runtime provider {} for program type {}", provider, programType);
        runner = provider.createProgramRunner(programType, mode, injector);
    } else {
        Provider<ProgramRunner> defaultProvider = defaultRunnerProviders.get(programType);
        if (defaultProvider == null) {
            throw new IllegalArgumentException("Unsupported program type: " + programType);
        }
        runner = defaultProvider.get();
    }
    // In distributed mode, program state changes are recorded in the event handler by Twill AM.
    return (mode == ProgramRuntimeProvider.Mode.LOCAL || publishProgramState) ? wrapProgramRunner(runner) : runner;
}
Also used : ProgramRuntimeProvider(io.cdap.cdap.app.runtime.ProgramRuntimeProvider) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner)

Example 15 with ProgramRunner

use of io.cdap.cdap.app.runtime.ProgramRunner in project cdap by cdapio.

the class DefaultRuntimeJob method run.

@Override
public void run(RuntimeJobEnvironment runtimeJobEnv) throws Exception {
    // Setup process wide settings
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler());
    SLF4JBridgeHandler.removeHandlersForRootLogger();
    SLF4JBridgeHandler.install();
    // Get Program Options
    ProgramOptions programOpts = readJsonFile(new File(DistributedProgramRunner.PROGRAM_OPTIONS_FILE_NAME), ProgramOptions.class);
    ProgramRunId programRunId = programOpts.getProgramId().run(ProgramRunners.getRunId(programOpts));
    ProgramId programId = programRunId.getParent();
    Arguments systemArgs = programOpts.getArguments();
    // Setup logging context for the program
    LoggingContextAccessor.setLoggingContext(LoggingContextHelper.getLoggingContextWithRunId(programRunId, systemArgs.asMap()));
    // Get the cluster launch type
    Cluster cluster = GSON.fromJson(systemArgs.getOption(ProgramOptionConstants.CLUSTER), Cluster.class);
    // Get App spec
    ApplicationSpecification appSpec = readJsonFile(new File(DistributedProgramRunner.APP_SPEC_FILE_NAME), ApplicationSpecification.class);
    ProgramDescriptor programDescriptor = new ProgramDescriptor(programId, appSpec);
    // Create injector and get program runner
    Injector injector = Guice.createInjector(createModules(runtimeJobEnv, createCConf(runtimeJobEnv, programOpts), programRunId, programOpts));
    CConfiguration cConf = injector.getInstance(CConfiguration.class);
    // Initialize log appender
    LogAppenderInitializer logAppenderInitializer = injector.getInstance(LogAppenderInitializer.class);
    logAppenderInitializer.initialize();
    SystemArguments.setLogLevel(programOpts.getUserArguments(), logAppenderInitializer);
    ProxySelector oldProxySelector = ProxySelector.getDefault();
    RuntimeMonitors.setupMonitoring(injector, programOpts);
    Deque<Service> coreServices = createCoreServices(injector, systemArgs, cluster);
    startCoreServices(coreServices);
    // regenerate app spec
    ConfiguratorFactory configuratorFactory = injector.getInstance(ConfiguratorFactory.class);
    try {
        Map<String, String> systemArguments = new HashMap<>(programOpts.getArguments().asMap());
        File pluginDir = new File(programOpts.getArguments().getOption(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR));
        // create a directory to store plugin artifacts for the regeneration of app spec to fetch plugin artifacts
        DirUtils.mkdirs(pluginDir);
        if (!programOpts.getArguments().hasOption(ProgramOptionConstants.PLUGIN_DIR)) {
            systemArguments.put(ProgramOptionConstants.PLUGIN_DIR, DistributedProgramRunner.PLUGIN_DIR);
        }
        // remember the file names in the artifact folder before app regeneration
        List<String> pluginFiles = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
        ApplicationSpecification generatedAppSpec = regenerateAppSpec(systemArguments, programOpts.getUserArguments().asMap(), programId, appSpec, programDescriptor, configuratorFactory);
        appSpec = generatedAppSpec != null ? generatedAppSpec : appSpec;
        programDescriptor = new ProgramDescriptor(programDescriptor.getProgramId(), appSpec);
        List<String> pluginFilesAfter = DirUtils.listFiles(pluginDir, File::isFile).stream().map(File::getName).collect(Collectors.toList());
        if (pluginFilesAfter.isEmpty()) {
            systemArguments.remove(ProgramOptionConstants.PLUGIN_DIR);
        }
        // recreate it from the folders
        if (!pluginFiles.equals(pluginFilesAfter)) {
            systemArguments.remove(ProgramOptionConstants.PLUGIN_ARCHIVE);
        }
        // update program options
        programOpts = new SimpleProgramOptions(programOpts.getProgramId(), new BasicArguments(systemArguments), programOpts.getUserArguments(), programOpts.isDebug());
    } catch (Exception e) {
        LOG.warn("Failed to regenerate the app spec for program {}, using the existing app spec", programId, e);
    }
    ProgramStateWriter programStateWriter = injector.getInstance(ProgramStateWriter.class);
    RuntimeClientService runtimeClientService = injector.getInstance(RuntimeClientService.class);
    CompletableFuture<ProgramController.State> programCompletion = new CompletableFuture<>();
    try {
        ProgramRunner programRunner = injector.getInstance(ProgramRunnerFactory.class).create(programId.getType());
        // Create and run the program. The program files should be present in current working directory.
        try (Program program = createProgram(cConf, programRunner, programDescriptor, programOpts)) {
            ProgramController controller = programRunner.run(program, programOpts);
            controllerFuture.complete(controller);
            runtimeClientService.onProgramStopRequested(controller::stop);
            controller.addListener(new AbstractListener() {

                @Override
                public void completed() {
                    programCompletion.complete(ProgramController.State.COMPLETED);
                }

                @Override
                public void killed() {
                    // Write an extra state to make sure there is always a terminal state even
                    // if the program application run failed to write out the state.
                    programStateWriter.killed(programRunId);
                    programCompletion.complete(ProgramController.State.KILLED);
                }

                @Override
                public void error(Throwable cause) {
                    // Write an extra state to make sure there is always a terminal state even
                    // if the program application run failed to write out the state.
                    programStateWriter.error(programRunId, cause);
                    programCompletion.completeExceptionally(cause);
                }
            }, Threads.SAME_THREAD_EXECUTOR);
            if (stopRequested) {
                controller.stop();
            }
            // Block on the completion
            programCompletion.get();
        } finally {
            if (programRunner instanceof Closeable) {
                Closeables.closeQuietly((Closeable) programRunner);
            }
        }
    } catch (Throwable t) {
        controllerFuture.completeExceptionally(t);
        if (!programCompletion.isDone()) {
            // We log here so that the logs would still send back to the program logs collection.
            // Only log if the program completion is not done.
            // Otherwise the program runner itself should have logged the error.
            LOG.error("Failed to execute program {}", programRunId, t);
            // If the program completion is not done, then this exception
            // is due to systematic failure in which fail to run the program.
            // We write out an extra error state for the program to make sure the program state get transited.
            programStateWriter.error(programRunId, t);
        }
        throw t;
    } finally {
        stopCoreServices(coreServices, logAppenderInitializer);
        ProxySelector.setDefault(oldProxySelector);
        Authenticator.setDefault(null);
        runCompletedLatch.countDown();
    }
}
Also used : ApplicationSpecification(io.cdap.cdap.api.app.ApplicationSpecification) ConfiguratorFactory(io.cdap.cdap.internal.app.deploy.ConfiguratorFactory) HashMap(java.util.HashMap) Closeable(java.io.Closeable) ProgramRunnerFactory(io.cdap.cdap.app.runtime.ProgramRunnerFactory) DefaultProgramRunnerFactory(io.cdap.cdap.app.guice.DefaultProgramRunnerFactory) ProxySelector(java.net.ProxySelector) LogAppenderInitializer(io.cdap.cdap.logging.appender.LogAppenderInitializer) CompletableFuture(java.util.concurrent.CompletableFuture) ProgramStateWriter(io.cdap.cdap.app.runtime.ProgramStateWriter) MessagingProgramStateWriter(io.cdap.cdap.internal.app.program.MessagingProgramStateWriter) Injector(com.google.inject.Injector) AbstractListener(io.cdap.cdap.internal.app.runtime.AbstractListener) ProgramDescriptor(io.cdap.cdap.app.program.ProgramDescriptor) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) UncaughtExceptionHandler(io.cdap.cdap.common.logging.common.UncaughtExceptionHandler) DistributedProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedProgramRunner) DistributedMapReduceProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedMapReduceProgramRunner) DistributedWorkerProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedWorkerProgramRunner) ProgramRunner(io.cdap.cdap.app.runtime.ProgramRunner) DistributedWorkflowProgramRunner(io.cdap.cdap.internal.app.runtime.distributed.DistributedWorkflowProgramRunner) RuntimeClientService(io.cdap.cdap.internal.app.runtime.monitor.RuntimeClientService) ProgramController(io.cdap.cdap.app.runtime.ProgramController) Program(io.cdap.cdap.app.program.Program) Arguments(io.cdap.cdap.app.runtime.Arguments) SystemArguments(io.cdap.cdap.internal.app.runtime.SystemArguments) BasicArguments(io.cdap.cdap.internal.app.runtime.BasicArguments) Cluster(io.cdap.cdap.runtime.spi.provisioner.Cluster) RuntimeClientService(io.cdap.cdap.internal.app.runtime.monitor.RuntimeClientService) Service(com.google.common.util.concurrent.Service) ProfileMetricService(io.cdap.cdap.internal.profile.ProfileMetricService) LogAppenderLoaderService(io.cdap.cdap.logging.appender.loader.LogAppenderLoaderService) MessagingService(io.cdap.cdap.messaging.MessagingService) AbstractIdleService(com.google.common.util.concurrent.AbstractIdleService) MessagingHttpService(io.cdap.cdap.messaging.server.MessagingHttpService) MetricsCollectionService(io.cdap.cdap.api.metrics.MetricsCollectionService) ProgramId(io.cdap.cdap.proto.id.ProgramId) CConfiguration(io.cdap.cdap.common.conf.CConfiguration) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) ProgramOptions(io.cdap.cdap.app.runtime.ProgramOptions) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException) ProgramRunId(io.cdap.cdap.proto.id.ProgramRunId) SimpleProgramOptions(io.cdap.cdap.internal.app.runtime.SimpleProgramOptions) File(java.io.File)

Aggregations

ProgramRunner (io.cdap.cdap.app.runtime.ProgramRunner)22 Program (io.cdap.cdap.app.program.Program)10 ProgramRunnerFactory (io.cdap.cdap.app.runtime.ProgramRunnerFactory)10 ProgramType (io.cdap.cdap.proto.ProgramType)10 DefaultProgramRunnerFactory (io.cdap.cdap.app.guice.DefaultProgramRunnerFactory)8 BasicArguments (io.cdap.cdap.internal.app.runtime.BasicArguments)8 SimpleProgramOptions (io.cdap.cdap.internal.app.runtime.SimpleProgramOptions)8 ProgramOptions (io.cdap.cdap.app.runtime.ProgramOptions)6 ProgramRuntimeProvider (io.cdap.cdap.app.runtime.ProgramRuntimeProvider)6 ProgramStateWriter (io.cdap.cdap.app.runtime.ProgramStateWriter)6 CConfiguration (io.cdap.cdap.common.conf.CConfiguration)6 Closeable (java.io.Closeable)6 ArrayList (java.util.ArrayList)6 ProgramId (io.cdap.cdap.proto.id.ProgramId)5 IOException (java.io.IOException)5 AbstractModule (com.google.inject.AbstractModule)4 FactoryModuleBuilder (com.google.inject.assistedinject.FactoryModuleBuilder)4 ApplicationSpecification (io.cdap.cdap.api.app.ApplicationSpecification)4 ProgramDescriptor (io.cdap.cdap.app.program.ProgramDescriptor)4 ProgramController (io.cdap.cdap.app.runtime.ProgramController)4