Deployment of a Spring Boot App with Jenkins in a Unix System using Gradle

One thing that I found very hard to do was to integrate a spring boot project into a CI environment using jenkins. As a default behavior, the Jenkins process tree killer always kills the process started by a job which stops the execution of a Spring Boot App after the jenkins job finishes. In addition of that, I wanted to see the server log on the jenkyns windows until it finishes loading. This article will try to help us solving this problems.

But first I would like to discuss what I consider a good practice to a Spring Boot App CI environment. I find very useful to first copy the artifacts to a specified area on the server to keep track of the artifacts deployed and deploy the artifact from that location. Also, I create a server log file there and start to listening on the jenkins window until the server started.

So the script below does that. With some minor improvements self explained on the comments, but in summary it does this:

  • stop whatever process running on the deployed port.
  • delete the files of the previous deploy
  • copy the files to deploy location
  • start application with nohup command, java – jar
  • start listening to the server log until it reaches an specific instruction.

Finally you have to do some adjustments to your job on Jenkins to avoid the default tree killing process. Just add this instruction before calling the sh: BUILD_ID=dontKillMe /path/to/my/script.sh (FIGURE 3)

You can see the jenkins job configuration window on FIGURES 1, 2, and 3 and the log result window on FIGURES 4 and 5.

Go to my github repo to check the project, but it recommend to extract the shell script to another repo to keep it lifecycle independent of your app.

https://github.com/rcoli/spring-boot-jenkins

Compila√ß√£o de m√ļltiplos projetos Maven

Em projetos de desenvolvimento de software mais complexos n√£o √© muito incomum a necessidade de quebrarmos uma aplica√ß√£o em peda√ßos menores que poder√£o ser reutilizados por outros projetos. E assim, acabamos criando a necessidade da compila√ß√£o de m√ļltiplos projetos de uma vez e em uma determinada ordem.

O Maven nos ajuda muito na tarefa de gest√£o de depend√™ncias e para o build de m√ļltiplos projetos ao mesmo tempo eles devem ter uma rela√ß√£o modular ou uma rela√ß√£o de pai para filho, saiba mais aqui e isto nem sempre √© desejado num ambiente de integra√ß√£o cont√≠nua.

O generic-maven-build nada mais √© do que um script preparado para compila√ß√£o de m√ļltiplos projetos de uma s√≥ vez, validando se compilaram corretamente e exibindo o tempo decorrido ao final.

A instrução executada partiu de uma necessidade de um projeto atual,  mvn clean install -U, no entanto nada impede que você faça a alteração no arquivo de acordo com a sua necessidade.

Explicando um pouco melhor as intru√ß√Ķes contidas no arquivo:

  • clean: ¬†attempts to clean a project’s working directory of the files that we’re generated at build-time. By default, it discovers and deletes the directories configured in project.build.directory, project.build.outputDirectory, project.build.testOutputDirectory, and project.reporting.outputDirectory.

  • install: install the package into the local repository, for use as a dependency in other projects locally

  • -U: Force Update, atualiza todas as depend√™ncias a partir dos reposit√≥rios configurados no pom.xml ou settings.xml

Instru√ß√Ķes de uso

Baixe o arquivo no meu repositório do bitbuket em uma pasta local do seu computador: https://rcoli@bitbucket.org/rcoli/generic-maven-build.git

Ali existem as vers√Ķes para Windows (pouco evolu√≠da, fique a vontade para melhor√°-la) e linux.

Para execut√°-lo, acesso o terminal ou prompt de comando e digite da seguinte forma:

Executando sem testes: generic-maven-build.sh /home/user/repository/project1/pom.xml /home/user/repository/project1/pom.xml semTestes

Executando com testes: generic-maven-build.sh /home/user/repository/project1/pom.xml /home/user/repository/project1/pom.xml

No Eclipse:

Clique no ícone External Tools na barra de tarefas do eclipse, escolha External Tools Configurations. Clique com o botão direito em Program e escolha new. Configure conforme as imagens abaixo:

Screenshot from 2015-07-08 10:26:07

Screenshot from 2015-07-08 10:26:28

Screenshot from 2015-07-08 10:28:35

Screenshot from 2015-07-08 10:28:48

Screenshot from 2015-07-08 10:37:19

Pré-requisitos:

Maven instalado e configurado, arquivo .sh ou .bat baixado em seu computador.

Referências:

https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

http://maven.apache.org/plugins/maven-clean-plugin/

http://books.sonatype.com/mvnex-book/reference/multimodule-web-spring-sect-intro.html

C√°lculo Simples de Data sem o uso de Date ou Calendar

Uma das grandes dificuldades do Java √© trabalhar com datas. Existem diversas APIs que resolvem esse problema de forma completa. No entanto atrav√©s de um simples c√°lculo utilizando os operadores “/” (divis√£o) e “%” (resto), somos capazes de obter o resultado sem a utiliza√ß√£o de nenhuma API espec√≠fica. Obviamente trabalhando com String.

Saída:
Hoje é: dia 3, mês 4, ano 14.

Hoje é: dia 23, mês 4, ano 2014.

public class Main {

    public static void main(String[] args) {

        String hojeComAnoEmDoisDigitos = "030414";
        System.out.println(escreverDataPorExtensoComAnoEmDoisDigitos(hojeComAnoEmDoisDigitos));

        String hojeComAnoEmQuatroDigitos = "23042014";
        System.out.println(escreverDataPorExtensoComAnoEmQuatroDigitos(hojeComAnoEmQuatroDigitos));
    }

    public static String escreverDataPorExtensoComAnoEmDoisDigitos(String hojeComAnoEmDoisDigitos) {
        try {

            if(!isDataValida(hojeComAnoEmDoisDigitos, 6))
                return ("Data Inválida, Verifique se o dia, o mês e ano possuem 2 dígitos.");

            Integer divisorDiaDoisDigitos = 10_000;
            Integer divisorAnoDoisDigitos = 100;

            Integer hoje = Integer.parseInt(hojeComAnoEmDoisDigitos);

            Integer dia;
            Integer mes;
            Integer ano;

            dia = (hoje / divisorDiaDoisDigitos);
            mes = (hoje / divisorAnoDoisDigitos) % 100;
            ano = hoje % divisorAnoDoisDigitos;

            return String.format("Hoje é: dia %d, mês %d, ano %d. \n", dia, mes, ano);

        } catch (NumberFormatException e) {
            return "Erro ao formatar valor para n√ļmero.";
        }
    }

    public static String escreverDataPorExtensoComAnoEmQuatroDigitos(String hojeComAnoEmQuatroDigitos) {
        try {

            if(!isDataValida(hojeComAnoEmQuatroDigitos, 8))
                return ("Data Inválida, Verifique se o dia, o mês possuem 2 dígitos e o ano quatro.");

            Integer hoje = Integer.parseInt(hojeComAnoEmQuatroDigitos);

            Integer divisorDiaQuatroDigitos = 1_000_000;
            Integer divisorAnoQuatroDigitos = 10_000;

            Integer dia;
            Integer mes;
            Integer ano;

            dia = (hoje / divisorDiaQuatroDigitos);
            mes = (hoje / divisorAnoQuatroDigitos) % 100;
            ano = hoje % divisorAnoQuatroDigitos;

            return String.format("Hoje é: dia %d, mês %d, ano %d. \n", dia, mes, ano);

        } catch (NumberFormatException e) {
            return "Erro ao formatar valor para n√ļmero.";
        }
    }

    private static boolean isDataValida(String hoje, int i) {
        return hoje.length() == i;
    }

}

Back-up r√°pido de tabelas MySQL

Uma boa prática  antes de atualizar a sua base é sempre fazer um back-up das tabelas que pode ser feito de forma rápida com o seguinte comando:

// criando a nova tabela
CREATE TABLE nova_tabela LIKE minha_base.tabela; 
// copiando os dados

INSERT nova_tabela SELECT * FROM minha_base.tabela;

CHAR ou VARCHAR? Que tipo de campo escolher no MySQL?

Ambos os tipos de campo “texto” podem ser definidos com um comprimento m√°ximo no MySQL. A principal diferen√ßa entre os dois tipos de campos √© que o CHAR sempre armazenar√° o texto com o tamanho fixo, mesmo que o “texto” seja menor do que o tamanho m√°ximo especificado na cria√ß√£o do campo. Neste caso, o pr√≥prio SGBD do MySQL ir√° usar espa√ßos a direita do “texto” preenchendo o campo at√© a quantidade m√°xima especificada em sua cria√ß√£o. Note, que esses espa√ßos ser√£o removidos quando voc√™ recuperar os dados a armazenados.

Por outro lado, “textos” armazenadas em uma coluna VARCHAR exigem apenas o tamanho do “texto” armazenado. Portanto, a palavra “ivo” em uma coluna VARCHAR(10) ir√° requerer quatro bytes de espa√ßo (o comprimento do “texto” mais 1), enquanto em uma coluna CHAR(10), a mesma palavra exigir√° 10 bytes de espa√ßo.

Assim, de modo geral, as colunas VARCHAR tendem a consumir menos espa√ßo em disco do que colunas CHAR. Contudo, as bases de dados s√£o normalmente mais r√°pidas quando se trabalha com colunas de tamanho fixo, o que √© um argumento a favor de CHAR. E essa mesma palavra de tr√™s letras, “ivo”, em um CHAR(3) utiliza apenas 3 bytes, enquanto em um VARCHAR(10) requer 4. Desta forma, como decidir qual usar?

Se o “texto” for sempre de um tamanho determinado¬†(por exemplo, uma abreviatura do estado), use CHAR, caso contr√°rio,¬†use VARCHAR. Voc√™ pode notar, por√©m, que, em alguns casos, o MySQL define uma coluna de um tipo (como CHAR) embora voc√™ a tenha criado como outro tipo (VARCHAR). Isto √© perfeitamente normal e √© a maneira que o MySQL possui para melhorar o desempenho.

OBS: Note que a palavra texto encontra-se marcada aqui no sentido de ressaltar que o campo “string” pode, al√©m de conter caracteres, conter tamb√©m n√ļmeros, datas ou listas armazenadas como texto (string). Neste caso, n√£o poder√£o ser usadas as fun√ß√Ķes SQL de c√°lculo espec√≠ficas de outros tipos. A n√£o ser que sejam convertidas antes.

Fonte: PHP 6 and MySQL 5 for Dynamic Web Sites. ULLMAN, Larry, 2007.

Assine o RSS de meus Artigos e Comentários.