All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.utils.SpawnProcessKeepAliveChecker Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite 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
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * When using CTG, might end up with many, many processes that are spawn.
 * However, if a controlling process fails (eg Maven) or is killed, it might
 * not properly shut down the spawn processes (JVM hooks only apply if JVM terminates
 * normally). As such, each spawn process should query at regular intervals if it
 * still can keep running.
 *
 * Created by Andrea Arcuri on 26/11/15.
 */
public class SpawnProcessKeepAliveChecker {

    private static final Logger logger = LoggerFactory.getLogger(SpawnProcessKeepAliveChecker.class);

    private final static SpawnProcessKeepAliveChecker instance = new SpawnProcessKeepAliveChecker();

    private final static ExecutorService executor = Executors.newCachedThreadPool();
    private final static String STILL_ALIVE = "still_alive";
    private final static int DELTA_MS = 5_000;

    private volatile ServerSocket server;
    private volatile Thread serverThread;
    private volatile Thread clientThread;

    public static SpawnProcessKeepAliveChecker getInstance(){
        return instance;
    }


    public int startServer() throws IllegalStateException{

        if(server != null || serverThread != null){
            throw  new IllegalStateException("Recorder already running");
        }

        try {
            server = new ServerSocket(0, -1, InetAddress.getLoopbackAddress());
        } catch (IOException e) {
            return -1;
        }

        serverThread = new Thread(){
            @Override public void run(){
                while(! isInterrupted() && server!=null && !server.isClosed()){
                    try {
                        Socket socket = server.accept();
                        socket.setKeepAlive(true);
                        executor.submit(new KeepAliveTask(socket));
                        logger.info("Registered remote process from "+socket.getRemoteSocketAddress());
                    } catch (IOException e) {
                        //fine, expected
                        return;
                    }
                }

            }
        };
        serverThread.start();

        int port = server.getLocalPort();
        logger.info("Started spawn process manager on port {}", port);

        return port;
    }

    public void stopServer(){
        logger.info("Stopping spawn process manager");
        try {
            if(server != null) {
                server.close();
                server = null;
            }
        } catch (IOException e) {
            logger.error(e.toString());
        }

        if(serverThread != null) {
            serverThread.interrupt();
            serverThread = null;
        }
    }

    public void registerToRemoteServerAndDieIfFails(final int port) throws IllegalStateException{
        if(clientThread != null){
            throw new IllegalStateException("Already registered");
        }

        clientThread = new Thread(){
          @Override public void run(){

              boolean failed = false;

              try {
                  Socket socket = new Socket(InetAddress.getLoopbackAddress(), port);
                  Scanner in = new Scanner(socket.getInputStream());

                  sleep(DELTA_MS);

                  while(! isInterrupted()){
                      if(! in.hasNext()){
                          failed = true;
                          break;
                      } else {
                          in.nextLine();
                      }

                      sleep(DELTA_MS);
                  }

              } catch (IOException e) {
                  failed = true;
              } catch (InterruptedException e) {
                  //this is fine, and expected when process ends
                  failed = false;
              }

              if(failed){
                  logger.error("Failed to receive keep alive message. Going to shutdown the process.");
                  try { sleep(200); } catch (InterruptedException e) {}

                  System.exit(1);
              }
          }
        };
        clientThread.start();
    }

    public void unRegister(){
        if(clientThread != null){
            clientThread.interrupt();
            clientThread = null;
        }
    }


    private static class KeepAliveTask implements Runnable{

        private final Socket socket;

        public KeepAliveTask(Socket s){
            socket = s;
        }

        @Override
        public void run() {
            try {
                PrintWriter out = new PrintWriter(socket.getOutputStream());
                while (socket.isConnected()) {
                    out.println(STILL_ALIVE);
                    Thread.sleep(DELTA_MS);
                }
            } catch (Exception e){
                //expected when remote host dies
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy