Publicidad furry

Cerveza Albul - Chico Temido
Cerveza Albul – Chico Temido

Saben, empiezo a pensar que eso de vender cosas con mascotas animales antropomórficas es de hecho una cosa generacional que va a crecer/envejecer con nosotros y adaptarse a los productos acorde a la edad 😛

Anuncios

Configurar la zona horaria de MySQL en Fedora Linux

Configuración MySQL
Configuración MySQL

Después de instalar un servidor MySQL nuevo en su sistema Fedora Linux es muy posible que sus programas le empiecen a mandar errores al conectarse al nuevo servidor, mencionando algo relacionado con la zona horaria, si eso le pasa aquí esta la solución.

Archivo de configuración

En Fedora el archivo de configuración de MySQL se encuentra en la ruta /etc/my.cnf editelo como root y agregue la siguiente linea

default-time-zone = "-06:00"

Aquí le esta indicando al servidor cual zona horaria desea usar, estas se deben poner en el formato de zonas horarias GMT indicando cuantas horas hay que sumar o restar de la hora de Greenwich [1].

Hecho esto reinicie el servidor MySQL con los siguientes comandos, todo esto como usuario root

systemctl stop mysqld.service
systemctl start mysqld.service

Y listo, con eso ya queda configurada la zona horaria de la base de datos.

Referencias

Consulte la zona horaria GMT – http://es.thetimenow.com/gmt/greenwich_mean_time


Espero que esta entrada le sea de utilidad y si desea cooperar con la causa.

ko-fi

Evitando que un error detenga un Timer

Error, pero el programa continua funcionando
Error, pero el programa continua funcionando

La razón mas común por la que usuaria un Timer en su aplicación Java es el tener funciones corriendo en segundo plano, usualmente para transmitir o recibir datos en forma periódica durante un periodo prolongado, usualmente todo el día y sin demasiada vigilancia por parte de un usuario y esto implica preparar su aplicación para que una excepción no trabe o cierra la aplicación, por que le garantizo eso siempre pasara en el peor momento posible.

¿Que detiene un Timer?

El Timer se detiene en el caso de que una excepción no manejada ocurra dentro del método run del TimerTask siendo ejecutado por el Timer, esto es una excepción que no tenga un catch para manejarla, esta excepción saltara mas arriba en su código y en el proceso detendrá el Timer.

¿Como nos afecta esto? bueno recuerde que aunque el compilador le exige capturar algunas excepciones hay varias que pueden aparecer sin avisar como CommunicationsException (la cual aparece si la conexion a una base de datos se pierde por causa de la red) o un error al convertir un JSON a objeto, o una excepción aritmética resultado de una división con mas decimales de lo esperado.

Por fortuna prevenir esto es muy sencillo.

Prevenir que una excepción detenga el Timer.

La mejor forma de prevenir el Timer de ser detenido por una excepción es capturar todas las excepciones posibles y aunque eso es posible capturando cualquier objeto de la clase o subclase Exception se recomienda aprovechar que cada excepción significa algo diferente y excepto algunas cosas como fallos de red o de conexión a base de datos seguro habrá varios casos que pueda corregir

Pero suficiente teoría pasemos a un ejemplo.

Ejemplo.

Usaremos de ejemplo un caso que seguramente le a pasado, que la conexión a una base de datos ser pierda por un momento, esto lo simularemos parando el servicio MySQL mientras el programa corre.

package mx.hashCode.TimerError;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

public class TimerSQL extends TimerTask {
    static private final Logger LOGGER = Logger.getLogger("mx.hashCode.TimerError.TimerSQL");

    public Connection crearConexion() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String usuario = "archivista";
        String passwd = "123456789";

        Connection cx = DriverManager.getConnection ("jdbc:mysql://127.0.0.1:3306/"+ "?useSSL=false&" + "user="+ usuario + "&" + "password=" + passwd + "");

        return cx;
    }

    @Override
    public void run() {
        try {
            String sql = "SELECT * FROM pruebas.juegos;";            
            
            try(Connection cx = this.crearConexion(); Statement consulta = cx.createStatement()) {
                ResultSet data = consulta.executeQuery(sql);

                LOGGER.log(Level.INFO, "Presentaremos los datos");
                System.out.println("");
                while(data.next() == true) {
                    System.out.print(data.getString("nombre") + " ");
                    System.out.println(data.getString("consola"));
                }
                System.out.println("");
                data.close();
            }

        } catch (SQLException | ClassNotFoundException e) {
            LOGGER.log(Level.SEVERE, "OCURRIO UN ERROR DE ACCESO A DB!!!");
            LOGGER.log(Level.SEVERE, "Pero el ciclo deberia repetirse sin problema");
            //LOGGER.log(Level.SEVERE, null, e);
        }
    }

}
package mx.hashCode.TimerError;

import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Hello world!
 *
 */
public class App 
{
    private static final Logger LOGGER = Logger.getLogger("mx.hashCode.TimerError.App");

    public static void main( String[] args )
    {
        LOGGER.log(Level.INFO, "Inicializamos el timer");
        Timer timer = new Timer();
        TimerSQL timerSQL = new TimerSQL();

        timer.schedule(timerSQL, 0, 1000*10);
    }
}

Esta es la tabla que consulta el programa.

CREATE TABLE `juegos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `consola` varchar(100) DEFAULT NULL,
  `nombre` varchar(100) DEFAULT NULL,
  `obtenido` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1

Obviamente deberá modificar los datos de conexión poner algún que otro dato en la tabla, hecho eso corra el programa con el servicio MySQL activo y vera la siguiente salida

Salida Correcta
Salida Correcta

Ahora desactive el servicio MySQL (esto variara dependiendo de su sistema operativo) y vera

Salida sin MySQL
Salida sin MySQL

Y sin embargo el programa no se a caído, como puede ver espera el tiempo que le indicamos, realiza la conexión y si algo sale mal (cosa que se indica con una excepción) el bloque catch correspondiente nos lo informa que ocurrió algo y previene que se detenga el ciclo.

No solo eso, sino que como es en el run donde se efectúa todo el proceso si inicia de nuevo el servicio MySQL

Tras reiniciar MySQL
Tras reiniciar MySQL

El programa vuelve a funcionar sin problema.

Obviamente para sacarle ventaja a todo esto debe diseñar su programa para que una excepción de ese tipo no vaya a causar errores de calculo o duplicidad de datos, la solución mas adecuada dependerá del caso especifico que este manejando.


Espero que esta entrada les fuera de utilidad y si fue así y desean cooperar con la causa.

ko-fi

Ejecutar periódicamente una función en Java

Función periodica
Función periódica

Una de las situaciones con las que seguro tendrá que lidiar al realizar una aplicación es ejecutar un método en forma periódica cada vez que pase un intervalo de tiempo especificado, ya sea para verificar el estado de un sensor, consultar o actualizar una base de datos, generar un reporte o enviar datos a un servidor, pero no se preocupe, hacer esto en Java es muy sencillo gracias a las clases Timer y TimerTask.

Timer

La clase Timer nos permite ejecutar una función en forma periódica a un intervalo especificado, su uso es bastante sencillo basta con crear un objeto Timer y usar el método scheduleAtFixedRate el cual toma tres argumentos que son los siguientes:

  • task, un objeto TimerTask cuyo método run se ejecutara al intervalo indicado
  • delay, la cantidad de milisegundos que queremos esperar antes de comenzar
  • period, cada cuanto en milisegundo queremos ejecutar el método run del objeto TimerTask

Esto en código se ve de la siguiente manera:

temporizador.scheduleAtFixedRate(tarea, 0, 1000*segundos);

Como notara no es nada del otro mundo, basta con pasarle los parámetros indicados y una vez pasado el retraso indicado por delay la función se llamara cada tantos milisegundos hasta que termine el programa o cancele la ejecución del objeto Timer llamando al método cancel.

TimerTask

Ya definimos cuando y cada cuanto queremos que una función se ejecute, ahora llego el momento de definir dicha función, para hacer esto debemos crear una subclase de TimerTask y redefinir el método run de modo que ejecute el código que nosotros queramos, como se ve en el siguiente ejemplo

package mx.com.hash.tareaprogramada;

import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class Tarea extends TimerTask {
    static private final Logger LOGGER = Logger.getLogger("mx.com.hash.tareaprogramada.Tarea");
    private Integer contador;    

    public Tarea() {
        contador = 0;
    }

    @Override
    public void run() {
        LOGGER.log(Level.INFO, "Numero de ejecución {0}", contador);
        contador++;
    }

}

De nuevo dentro del método run puede poner el código que quiera, llamar a otras clases y demas, no sienta que debe limitarse a funciones de la subclase de TimerTask.

Otro detalle a recordar es que el Timer llama al método run del objeto que le pasamos, de modo que si almacena información en ese objeto esta estará disponible entre cada ejecución del Timer, esto quedara mas claro en el ejemplo.

Ejemplo

Para dejar mas en claro todo esto hagamos un pequeño ejemplo, llamando a una función cada 5 segundos que nos escriba en pantalla cuantas veces hemos llamado a la función, para esto usaremos el siguiente código.

package mx.com.hash.tareaprogramada;

import java.util.Timer;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class TareaProgramada {
    static private final Logger LOGGER = Logger.getLogger("mx.com.hash.tareaprogramada.TareaProgramada");

    static public void main(String[] args){
        Tarea tarea = new Tarea();
        Timer temporizador = new Timer();
        Integer segundos = 5;

        temporizador.scheduleAtFixedRate(tarea, 0, 1000*segundos);
    }
}
package mx.com.hash.tareaprogramada;

import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class Tarea extends TimerTask {
    static private final Logger LOGGER = Logger.getLogger("mx.com.hash.tareaprogramada.Tarea");
    private Integer contador;    

    public Tarea() {
        contador = 0;
    }

    @Override
    public void run() {
        LOGGER.log(Level.INFO, "Numero de ejecución {0}", contador);
        contador++;
    }

}

Y al ejecutarlo veremos la siguiente salida.

Ejemplo de función periodica
Ejemplo de función periódica

Como puede ver el objeto tarea no se destruye durante la ejecución del Timer, por lo que la información en el persiste e ejecución en ejecución.

¿Que pasa si la función tarda mucho en ejecutarse?

Un caso que puede presentarse es que la función tarde tanto en ejecutarse que llegue el momento de volverla a ejecutar y aun no halla acabado, cosa muy posible si depende de conexiones a base de datos, servidores externos o conexiones, ¿En ese caso que pasaría?

Bueno hagamos la prueba, modifiqué la clase Tarea para que quede así

package mx.com.hash.tareaprogramada;

import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author david
 */
public class Tarea extends TimerTask {
    static private final Logger LOGGER = Logger.getLogger("mx.com.hash.tareaprogramada.Tarea");
    private Integer contador;    

    public Tarea() {
        contador = 0;
    }

    @Override
    public void run() {
        LOGGER.log(Level.INFO, "Numero de ejecución {0}", contador);
        contador++;

        try {
            // Con esto hacemos que la funcion tarde *mas* en ejecutarse que
            // el periodo especificado
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
            LOGGER.log(Level.SEVERE, "Error de interrupcion");
        }
    }

}<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

Lo que hacemos aquí es agregar un retraso  a la función run de modo que tarde 10 segundos en ejecutarse pero no modificamos lo demas, de modo que el temporizador ejecutara cada 5 segundos una función que tarda 10 segundos en ejecutarse, el resultado se ve a continuación.

Una función que tarda mas en ejecutarse
Una función que tarda mas en ejecutarse

Como ve el retraso entre llamadas es el indicado por la función, el Timer no llamara al método run sino hasta que este halla acabado por lo que no debe preocuparse de que queden cosas incompletas, lo que si puede pasar es que si ya paso el periodo entre llamadas el método run se llame inmediatamente después de terminar la llamada que tardo demas.

El código de este ejemplo lo puede encontrar aquí: https://gitlab.com/ticomWebcomic/tareaprogramada


Espero que esta entrada fuera de utilidad y si lo fue y quiere cooperar con la causa tengo una pagina en Ko-fi para aceptar donativos

ko-fi

Habilidad Geriatrica

Habilidad Geriatrica
Habilidad Geriatrica

La sabiduría de los ancianos

Transcript

Mike: ¡ESA COSA ES DEL DIABLO!

Mike: ¡¡¡COMO EL POKE MONGO Y EL IMSS TANGRAM!!

Narrador: Los mayores no sabran de técnologia, pero son expertos en detectar que es del Diablo.


Y si también pueden visiten mi pagina en Ko-fi y cooperen con la causa 😀

ko-fi

Yokai Gameplay Volumen 1

Se me a olvidado ponerlo aquí, pero he estado haciendo un webcomic basado en un gameplay de Yokai Watch, aquí estan los comics cubriendo el primer capitulo del juego.

Si le interesa como va este proyecto aca es donde puede ver el comic 🙂

yokai_watch

Si puede dele una visita, se actualiza (en lo posible :P) cada Martes y Jueves


Y si también pueden visiten mi pagina en Ko-fi y cooperen con la causa 😀

ko-fi

 

Materiales de dibujo

tools

Y finalmente me doy cuenta por que se hicieron TAN populares las tabletas digitalizadoras, no solo dejan deshacer cada error y ahorran hacer el escaneo sino que además evita el circo que es tratar de conseguir los materiales usuales de dibujo.

Sonara como broma para literalmente fue comprar la tinta en un Office Max, buscar plumillas en una tienda de arte, solo para ver que costaban un ojo de la cara y luego buscar un estilografo en otro Office Depot, por que no tenian ni en el Office Max ni en la tienda de arte.

Pero bueno, ya conseguí los materiales que necesitaba, a dibujar 😛