Inicio automático de servicios, start, stop, restart, status.

0
19346

Monitorización de servicios: start, stop, restart, status

En este tutorial os voy a mostrar como lanzar un aplicación en modo servicio con las siguientes características:

  • El servicio respondará a los mensajes: start, stop, restart, status.
  • El servicio se iniciará automáticamente cuando se inicie la máquina.
  • El servicio se iniciará automáticamente en caso de que sea detenido.

Como veis son muchas tareas las que vamos a realizar, asi que empezemos poco a poco.

Uno de los problemas que tenemos que resolver es saber cuando un servicio está obreciendo servicio a sus clientes.
La mejor forma de saberlo es haciéndole una petición para ver si contexta.
Para este ejemplo, vamos a crear un Thread que será facilmente integrable con cualquier aplicación y que simplemente contexta
una petición UDP sobre un puerto determinado retornando un «ok» al cliente, es decir algo parecido a un PING.

Código fuente que necesitamos integrar en nuestros servicios:
    
package com.autentia.tutoriales.servicemonitor;

import java.net.*;

/**
 * Esta clase recibe proporciona funcionalidad de monitorización del estado del servicio.
 * @author Carlos García. Autentia.
 */
public class StatusListener extends Thread {

	private DatagramSocket socket;

	/**
	 * Constructor
	 * @param listen_port Puerto en el que se desea escuchar
	 * @throws SocketException En caso de que el socket no se pueda enlazar al puerto especificado
	 */
	public StatusListener(int listen_port) throws SocketException {
		this.socket = new DatagramSocket(listen_port);
	}
	
	/* 
	 * Iniciamos el proceso de monitorización de estado.
	 * @see java.lang.Thread#run()
	 */
	public void run(){
		byte[]		   inbytes  = new byte[128];	
		DatagramPacket request  = new DatagramPacket(inbytes, inbytes.length);
		DatagramPacket response = null;
		byte[]		   ok	    = "ok".getBytes();	
		
		
		try {
			while (true){
				try {
					// Esperamos las peticiones de consulta de estado. (Es un método bloqueante)
					socket.receive(request);
					
					// Hemos recibido una petición. Creamos la respuestsa
					response = new DatagramPacket(ok, 0, ok.length, request.getAddress(), request.getPort());
					
					
					// Enviamos la respuesta
					socket.send(response);
					
				} catch (java.io.IOException ex){
					// Se ha producido un error en el tratamiento de la petición actual.  
					// No pasa nada, seguimos dando servicio a otras peticiones.
				}
			}	// fin while
		} finally { 
			// Liberamos recursos
			
			try {
				socket.disconnect();
			} catch (Exception ex) {
				// Ignoramos las excepciones
			}
			
			try {
				socket.close();
			} catch (Exception ex) {
				// Ignoramos las excepciones
			}				
		}
	}
}
Código fuente de ejemplo de integración en un servicio:
package com.autentia.tutoriales.servicemonitor;

/**
 * Esta clase no hace más que mostrar como se integraría el StatusListener 
 * dentro de nuestra lógica de negocio de cada aplicación.
 * @author Carlos García. Autentia.
 */
public class ServiceMonitorApp extends Thread {
	
	private StatusListener status;
	
	/**
	 * Constructor
	 */
	public ServiceMonitorApp() {
		try {
			// Escuchará las peticiones de estado en el puerto 5000. 
			// (Debería ser leido de un archivo de configuración)
			this.status  = new StatusListener(5000);	
		} catch (java.net.SocketException ex){
			throw new java.lang.InstantiationError(ex.getMessage());
		}
		
		this.start();
		
	}
	
	/* 
	 * @see java.lang.Thread#run()
	 */
	public void run(){
		// Activamos la escucha de peticiones de estado.
		status.start();
		
		try {
			while (true){
				// Esta aplicación no hace nada, solo lanza el Thread de escucha de peticiones de estado
				Thread.sleep(1000);
			}
		} catch (java.lang.InterruptedException ex){
			// El proceso ha sido interrumpido
		}
		
		// Detenemos la escucha de peticiones de estado
		status.interrupt();
	}
	
	/**
	 * Inicia el servidor de ejemplo con escuchas de estado integrado.
	 */
	public static void main(String[] args) {
		new ServiceMonitorApp();
	}
}

La integración se puede observar en las líneas 19, 33 y 45.

Código fuente para consultar el estado del servicio:
package com.autentia.tutoriales.servicemonitor;
import java.net.*;


/**
 * Testea que el servicio esté funcionando correctamente.
 * @author Carlos García. Autentia.
 */
public class ServiceStatusTest {

	/**
	 * Realiza una consulta de estado al servicio
	 * @param args Son requeridos los siguientes parámetros: , 
	 */
	public static void main(String[] args) {
		DatagramSocket	socket	 = null;
		DatagramPacket	packet	 = null;
		DatagramPacket	received = null;
		SocketAddress	target	 = null;	
		byte[]			bytes1	 = "STATUS".getBytes();
		byte[]			bytes2	 = new byte[64];
		String			receivedData = null;
		
		try {
			if (args.length != 2){
				System.err.println("Formato: ServiceStatusTest  ");
				return;
			}
			
			// Dirección y puerto del servicio.
			target = new InetSocketAddress(args[0], Integer.parseInt(args[1]));	// (ip y puerto)
			
			// Creamos el paquete de consulta
			packet = new DatagramPacket(bytes1, bytes1.length, target);
			
			
			// Instanciamos el socket y configuramos un tiempo máximo de 5 segundos para obetener una respuesta del servicio
			socket = new DatagramSocket();
			socket.setSoTimeout(5000);
			
			// Enviamos la petición
			socket.send(packet);
			
			// Leemos la respuesta
			received = new DatagramPacket(bytes2, bytes2.length);
			socket.receive(received);
			
			receivedData = new String(received.getData(), 0, received.getLength());
			
		} catch (Exception ex){
			// No hacemos nada especial.
			// (El tratamiento se hace en el finally).
		} finally { 
			// Liberamos recursos
			try {
				socket.close();
			} catch (Exception ex){}
			
			// Devolvemos el código de respuesta
			if ("ok".equalsIgnoreCase(receivedData)){
				Runtime.getRuntime().exit(0);	// OK
			} else {
				Runtime.getRuntime().exit(-1);	// KO
			}			
		}
	}
}

A continuación vamos a hacer que el servicio responda a las peticiones: start, stop, restart, status.

En Unix, los servicios suelen responder a estos mensajes (al menos a start y stop). Para ellos cada servicio tiene un script en el directorio /etc/init.d.

Script de inicio, parada, reinicio, status. example_service.sh:.

(Lo debemos crear en el directorio /etc/init.d)

        #!/bin/bash
        
        # ------------------------------------------------------------------------
        # Este Script para iniciar, parar y monitorizar el servicio de ejemplo 
        # debe ser colocado en el directorio /etc/init.d 
        # ------------------------------------------------------------------------
        
        SERVICE_PATH="/home/carlosgarcia"
        
        case "$1" in
        	start)
        	  sh $SERVICE_PATH/example_service_start.sh
        	  ;;
        	stop)	  
        	  sh $SERVICE_PATH/example_service_stop.sh
        	  ;;
        	restart)
        	  sh $SERVICE_PATH/example_service_restart.sh
        	  ;;
        	status)
        	  sh $SERVICE_PATH/example_service_status.sh
        	  ;;	  
        	*)
        	  echo "Uso: $0 {start|stop|restart|status)}"
        	  exit 1
        	  ;;
        esac
        
        exit 0
    
Reinicia el servicio de ejemplo. example_service_restart.sh:
      #!/bin/bash
      # Este Script reinicia el servicio de ejemplo 
      
      SERVICE_PATH="/home/carlosgarcia"
      
      sh $SERVICE_PATH/example_service_stop.sh
      sh $SERVICE_PATH/example_service_start.sh
    
Inicia el servicio de ejemplo para este tutorial. example_service_start.sh:
      #!/bin/bash
      # Este Script para inicia el servicio de ejemplo para este tutorial
       
      SERVICE_PATH="/home/carlosgarcia"
      PID_FILE="$SERVICE_PATH/example_service.pid"
      
      cd $SERVICE_PATH
      
      # Iniciamos el servicio de ejemplo
      $JAVA_HOME/bin/java -cp $SERVICE_PATH com.autentia.tutoriales.servicemonitor.ServiceMonitorApp &
      
      # Guardamos el PID del proceso en un archivo
      echo $! > "$PID_FILE"
    
Detiene el servicio de ejemplo para este tutorial. example_service_stop.sh:
        #!/bin/bash
        # Este Script detiene el servicio de ejemplo 
        
        SERVICE_PATH="/home/carlosgarcia"
        PID_FILE="$SERVICE_PATH/example_service.pid"
        
        # Cargamos en una variable el PID del proceso que estaba almacenado en un archivo.
        read  PID_VAR     
    
    
Consulta el estado del servicio de ejemplo para este tutorial. example_service_status.sh:
        #!/bin/bash
        # Este Script consulta el estado del servicio de ejemplo
        
        SERVICE_PATH="/home/carlosgarcia"
        
        $JAVA_HOME/bin/java -cp $SERVICE_PATH com.autentia.tutoriales.servicemonitor.ServiceStatusTest
        
        if test $? -eq 0
        then
        	echo "Estado: OK"	
        else
         	echo "Estado: KO"
        fi    
    
Consulta el estado del servicio de ejemplo para este tutorial. example_service_status.sh:
#!/bin/bash
        # Este Script consulta el estado del servicio de ejemplo
        
        SERVICE_PATH="/home/carlosgarcia"
        
        $JAVA_HOME/bin/java -cp $SERVICE_PATH com.autentia.tutoriales.servicemonitor.ServiceStatusTest
        
        if test $? -eq 0
        then
        	echo "Estado: OK"	
        else
         	echo "Estado: KO"
        fi    

A continuación mostramos las comandos que deberíamos escribir para iniciar, detener, reiniciar y consultar el estado del servicio.

  • /etc/init.d/example_service start
  • /etc/init.d/example_service stop
  • /etc/init.d/example_service restart
  • /etc/init.d/example_service status

Monitorización del servicio para iniciarlo automáticamente en caso de que esté detenido.

Inicia el servicio en caso de que no responda a la consulta de STATUS example_service_monitor.sh:
      #!/bin/bash
      
      # Este Script inicia el servicio en caso de que no responda a la consulta de STATUS
      
      SERVICE_PATH="/home/carlosgarcia"
      
      $JAVA_HOME/bin/java -cp $SERVICE_PATH com.autentia.tutoriales.servicemonitor.ServiceStatusTest
      
      # Consultamos el valor de retorno. (
      if test $? -ne 0
      then
      	sh $SERVICE_PATH/example_service_restart.sh	
      fi    
    

(Observe las líneas 61 y 63 del cliente ServiceStatusTest)

Ahora tecleamos las dos líneas siguientes para monitorizar el estado del servicio

Vamos a apoyarnos en el cron (gestor de tarea programadas) para que monitorize el estado del servicio cada 5 segundos

(La siguiente línea abrirá un editor para editar el archivo crontab del usuario)
crontab -e

      
(Debemos introducir esa linea para monitorizar el estado cada 5 segundos)
*/5 * * * * "sh /home/carlosgarcia/example_service_monitor.sh"
      
  • (La siguiente línea abrirá un editor para editar el archivo crontab del usuario)
    crontab -e
  • (Debemos introducir esa linea para monitorizar el estado cada 5 segundos)
    */5 * * * * «sh /home/carlosgarcia/example_service_monitor.sh»

Ojo!! En algunas versiones de cron no funciona */5, pruebe con un 5.

Iniciando el servicio en el arranque de la máquina

Si deseamos que el servicio de ejemplo se inicie automáticamente cuando la máquina arranque debemos seguir los siguientes pasos:

  • Copiamos o movemos el archivo example_service en el directorio /etc/init.d (Si no lo habíamos hecho ya).
  • (Creamos un enlaze simbólico en el nivel de arranque 2.

    ln -s /etc/init.d/example_service /etc/rc2.d/S99example_service.

    Dentro del sistema operativo, existen varios niveles de arranque (de 0 a N) y dentro de cada nivel los servicios se inician según un orden (0-99).
    La S significa «START».

    Para saber en que nivel arranca tu sistema, deberás consultar la propiedad initdefault del archivo /etc/inittab

Un saludo.

Carlos García. Autentia.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad