org.ow2.proactive.scheduler.task.executors.ForkedTaskExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive.scheduler.task.executors.ForkedTaskExecutor.java

Source

/*
 * ProActive Parallel Suite(TM):
 * The Open Source library for parallel and distributed
 * Workflows & Scheduling, Orchestration, Cloud Automation
 * and Big Data Analysis on Enterprise Grids & Clouds.
 *
 * Copyright (c) 2007 - 2017 ActiveEon
 * Contact: contact@activeeon.com
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation: version 3 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 */
package org.ow2.proactive.scheduler.task.executors;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;

import org.apache.commons.io.FileUtils;
import org.objectweb.proactive.extensions.processbuilder.OSProcessBuilder;
import org.ow2.proactive.scheduler.common.task.TaskId;
import org.ow2.proactive.scheduler.task.TaskResultImpl;
import org.ow2.proactive.scheduler.task.context.TaskContext;
import org.ow2.proactive.scheduler.task.context.TaskContextSerializer;
import org.ow2.proactive.scheduler.task.exceptions.ForkedJvmProcessException;
import org.ow2.proactive.scheduler.task.executors.forked.env.ExecuteForkedTaskInsideNewJvm;
import org.ow2.proactive.scheduler.task.utils.ProcessStreamsReader;
import org.ow2.proactive.utils.CookieBasedProcessTreeKiller;

/**
 * Executor in charge to fork a new process for running a non forked task in a dedicated JVM.
 *
 * @see ExecuteForkedTaskInsideNewJvm#fromForkedJVM(String)
 * @see InProcessTaskExecutor
 */
public class ForkedTaskExecutor implements TaskExecutor {

    private final ForkedProcessBuilderCreator forkedJvmProcessBuilderCreator = new ForkedProcessBuilderCreator();

    private final TaskContextSerializer taskContextSerializer = new TaskContextSerializer();

    private final File workingDir;

    public ForkedTaskExecutor(File workingDir) {
        this.workingDir = workingDir;
    }

    @Override
    public TaskResultImpl execute(TaskContext context, PrintStream outputSink, PrintStream errorSink) {
        CookieBasedProcessTreeKiller taskProcessTreeKiller = null;
        Process process = null;
        ProcessStreamsReader processStreamsReader = null;
        File serializedContext = null;

        try {
            if (!workingDir.exists()) {
                FileUtils.forceMkdir(workingDir);
            }
            serializedContext = taskContextSerializer.serializeContext(context, workingDir);

            OSProcessBuilder processBuilder = forkedJvmProcessBuilderCreator.createForkedProcessBuilder(context,
                    serializedContext, outputSink, errorSink, workingDir);

            TaskId taskId = context.getTaskId();

            String cookieNameSuffix = "Job" + taskId.getJobId().value() + "Task" + taskId.value();

            taskProcessTreeKiller = CookieBasedProcessTreeKiller.createProcessChildrenKiller(cookieNameSuffix,
                    processBuilder.environment());

            process = processBuilder.start();
            processStreamsReader = new ProcessStreamsReader(taskId.toString(), process, outputSink, errorSink);

            int exitCode = process.waitFor();

            if (exitCode != 0) {
                try {
                    Object error = deserializeTaskResult(serializedContext);
                    if (error instanceof TaskContext) {
                        return createTaskResult(context,
                                new IOException("Forked JVM process returned with exit code " + exitCode
                                        + ", see task logs for more information"));
                    } else {
                        Throwable exception = (Throwable) error;
                        return createTaskResult(context, exception);
                    }
                } catch (Throwable cannotDeserializeResult) {
                    return createTaskResult(context, cannotDeserializeResult);
                }
            }

            return (TaskResultImpl) deserializeTaskResult(serializedContext);
        } catch (Throwable throwable) {
            return createTaskResult(context, throwable);
        } finally {
            FileUtils.deleteQuietly(serializedContext);

            if (process != null) {
                process.destroy();
            }
            if (taskProcessTreeKiller != null) {
                taskProcessTreeKiller.kill();
            }
            if (processStreamsReader != null) {
                processStreamsReader.close();
            }
        }
    }

    private TaskResultImpl createTaskResult(TaskContext context, Throwable throwable) {
        return new TaskResultImpl(context.getTaskId(),
                new ForkedJvmProcessException("Failed to execute task in a forked JVM", throwable));
    }

    // 4 called by forker
    private Object deserializeTaskResult(File pathToFile) throws IOException, ClassNotFoundException {
        try (ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(pathToFile))) {
            return inputStream.readObject();
        } catch (IOException e) {
            throw new ForkedJvmProcessException(
                    "Could not read serialized task result (forked JVM may have been killed by the task or could not write to local space)",
                    e);
        } finally {
            FileUtils.deleteQuietly(pathToFile);
        }
    }

}