Tag desenvolvimento de sistemas

Celery e Tarefas assícronas com Python

O Celery é um aplicação, escrita em Python, que permite que você delegue tarefas a diversos workers, localizados em outros servidores.

O Celery é uma forma bastante de realizar estes jobs ou tarefas de forma assíncrona, sem ter de quebrar muito a cabeça com conceitos complicados e difíceis de serem acertados.

Primeiramente, vou explicar como o Celery funciona, em termos de arquitetura.

Temos alguns componentes principais envolvidos:

  1. Aplicação – este carinha aqui é a sua aplicação normal, a qual o usuário ou outra máquina interage;
  2. Broker – este componente é uma fila de mensagens, utilizada para transportar mensagens entre os processos que estamos descrevendo aqui. O Celery permite o uso de diversos brokers, como redis e RabbitMQ. Usamos o redis por aqui, mas é uma preferência;
  3. Worker – este é o componente que trabalha de verdade. Qualquer tarefa agendada pela aplicação no broker, será executada pelo worker;
  4. Beat – é um componente opcional, mas funciona como um agendador de tarefas, que dispara de tempos em tempos as tarefas para o broker, como uma aplicação;

Com esta arquitetura, é bastante fácil escalar a coisa toda para funcionar em várias máquinas, bastando adicionar mais workers conforme a frequência das tarefas aumentam. O Celery é muito customizável e tem opções importantes, como controle de filas (algumas tarefas só podem ser processadas uma a uma, em uma única fila, sem concorrência alguma, enquanto outras podem ser paralelizadas), aplicaçoes de monitoramento (como o Flower) e extensões de biblioteca para os desenvolvedores (como o Jobtastic).

Vamos hoje dar um exemplo bastante simples, integrado a um projeto Django. Não vamos entrar em muitos detalhes de como subir os workers ou o broker, pois vai depender muito do seu ambiente.

Imagine que sua aplicação manda emails. Quase todas as aplicações (web) mandam emails, mas algumas mandam mais emails que outras e com maior frequência. Entre o ponto em que uma requisição feita pelo usuário é processada e uma resposta é retorna, vários segundos podem se passar e não queremos deixar o usuário esperando. Então decidimos delegar o envio do email, que é mais demorado, para uma tarefa assícrona no Celery.

Como fazer isto?

Bem, primeiramente é necessário configurar sua aplicação Celery. Fazemos (aqui na SIGMA) por meio de um arquivo celery.py, localizado junto wsgi.py do projeto. Ele é mais ou menos assim:

# coding: utf-8
"""Configuração inicial do Celery"""
from __future__ import absolute_import
import os
from django.conf import settings

if not "DJANGO_SETTINGS_MODULE" in os.environ:
    os.environ["DJANGO_SETTINGS_MODULE"] = "settings.local"  # aqui na SIGMA usamos settings separados para cada ambiente

from celery import Celery
app = Celery('nome-da-app')

app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

Com esta configuração batuta, podemos iniciar um worker, por exemplo. Além disso, usamos o autodiscover do Celery, que percorrerá todas as INSTALLED_APPS e cadastrará todas as tarefas dentro dos módulos tasks.py.

Ok, com o Celery configurado, podemos startar um worker.

celery -A projeto worker -l info

Agora, vamos criar nossa task e chamar ela de dentro de uma view qualquer. Crie um arquivo chamado tasks.pyem uma de suas apps, por exemplo, sistema.

Para definir a task, utilizaremos um decorador:

from projeto.celery import app  # lembre do nosso arquivo celery.py?


@app.task()
 def email_async(email, assunto, template, contexto):
    template_html = get_template(template)
    template_txt = get_template(template.replace('.html', '.txt'))
    if isinstance(contexto, dict):
        contexto = Context(contexto)

    contexto['email_header_image'] = get_random_image()
    html = template_html.render(contexto)
    txt = template_txt.render(contexto)
    if isinstance(email, basestring):
        email =[email]

    send_mail(assunto,
              txt,
              'remetente',
              recipient_list=email,
              html_message=html)

Com a tarefa definida, podemos invocá-la de forma assícrona. O Celery tem muitas formas de se invocar uma tarefa. Existe um negócio chamado canvas que permite você combinar as tarefas de forma assícrona, paralelas, etc. Confira a documentação do canvas.

Vá em uma de suas views que enviam emails:

from .tasks import email_async

def view_qualquer(request):

    # faça alguma coisa útil

    email_async.delay('novo email', 'sistema/email.html', {'variavel_contexo_a': 'foo', 'b': 'novo email maroto'})

O segredo da chamada assícrona está no método delay, que irá usar o broker para agendar a tarefa e futuramente será executada por um worker.

É um resumo muito curto para mostrar todas as capacidades do Celery, mas é um projeto muito bem mantido, utilizado por muita gente.

O exemplo que demos, apesar de parecer bobo, é bastante significativo quando estamos falando de uma aplicação que envia centenas ou milhares de emails por dia, diminuindo muito o impacto nos servidores de aplicação e permitindo que você lide com uma carga bem mais alta.

Iremos fazer uma pequena série sobre o Celery. Tem jeito de consultar o status da tarefa, agendar tarefas periódicas, controlar exceções e um monte de coisa legal.

Fique ligado e obrigado!

Automação de Infraestrutura com Puppet

Let the computer do the repetitious, the mundane – it will do a better job of it than we would. We’ve got more important and more dificult things to do.
Trecho retirado do livro Programador Pragmatico.

O profissional de desenvolvimento de software conta com um grande trunfo em sua manga que é frequentemente negligenciado, um trunfo que vem sendo utilizado vastamente por outras áreas em que sua complexidade é maior do que a encontrada na área de software. Com a automação pode ser alcançado o que economia chama de lucro, pois um profissional aumenta sua produtividade e a qualidade do que é produzido. Estes dois parametros trarão uma enorme mudança em sua carreira, então a partir deste momento se torne um profissional que se vale deste trunfo e se destaca dos demais, simplesmente aplicando em seu trabalho o que de melhor fazemos: automatizar tarefas.

Durante os ultimos anos vemos as práticas DevOps se tornando cada vez mais a cultura dos desenvolvedores e administradores. Neste artigo faremos uma comparação da utilização de uma das tecnologias de escrita de infraestrutura como código criada pela empresa Puppet, o produto escolhido se chama puppet-agent e vamos escrever em uma dsl de mesmo nome, que tenta tornar este processo tão simples como listar quais software serão utilizados.

#####Aplicamos esta prática em dois cenários:

#####Windows:

Neste cenário o cliente utiliza Windows, embora esta arquitetura seja compatível com ambientes linux o cliente tinha mais experiência com Windows e o utilizava em todos ambientes do desenvolvimento à produção. Para prover serviços de mapa e hospedar a aplicação web map é utilizado IIS 7.5, Geoserver, Postgresql e Postgis. Nós escolhemos o puppet-agent e o script será aplicado em uma maquina existente preparada para receber as instalações oriundas do script puppet.

O primeiro passo é instalar o puppet para poder executar o script, que como dito é uma dsl simples

A script que criamos é composta por resources, cada resource tem funções como: instalação de pacote, execução de comandos shell, agendamento de tarefas, administração de serviços, criação de usuários, operações no sistema de arquivos e etc.

Os resources podem ser combinados de forma a determinar qual é o resource requerido para que um outro seja executado, ou assim que determinado resource for executado ele pode notificar outro para que este seja executado.

Uma dificuldade ao utilizar o puppet para instalação de sistemas é que o windows não possui um gestor de pacotes, os instaladores são individuais e distribuídos individualmente por cada fornecedor. Desta forma o processo de instalação exige que em alguns casos seja utilizado o processo de instalação headless que é disponibilizado pela ferramenta de empacotamento utilizada pela empresa que provê o instalador do software. Infelizmente por não haver uma padrão isto é o que mais dá trabalho durante a redação do script.

Após as instalações é necessário configurar as aplicações instaladas, iniciar serviços ou agendar tarefas.

Basicamente utilizamos o resources exec, que permite executar comandos shell, o file, que permite copiar arquivos e o scheduled_task para agendar tarefas.

Com o exec nós configuramos o postgres, executamos os scripts sql de criação das feições espaciais, com o file copiamos arquivos, como por exemplo o diretório data_dir do geoserver e com o scheduled_task configuramos a tarefa de execução do geoserver.

Utilizamos também o Hiera para criar um arquivo de configuração externo e permitir que o script fosse executado independente dos diretórios em que os arquivos existiriam ou do local em que desejamos instalar.

A grande desvantagem foi o tempo que levamos para montar este script. É bastante trabalhoso e em por utilizarmos o windows neste cenário, tivemos pouca documentação disponível principalmente para as instalações headless de cada instalador. Porém quando este desafio foi ultrapassado a grande vantagem foi conseguir instalar com pouquissima dificuldade quatro maquinas diferentes, uma maquina na cloud (Windows Server 2012 R2 ) e três estações de trabalho com Windows 7. O primeiro grande beneficio é que temos a certeza que todas as maquinas possuem a mesma versão e configuração e uma vantagem é que nossa equipe é distribuída e podemos contar com o apoio de outros desenvolvedores que não estejam geográficamente perto e eles conseguirão replicar o ambiente com rapidez e poderão efetivamente apoiar o desenvolvimento do software.

#####Linux:

Montar a maquina servidora de um web map escrito em python e javascript, que consulta um banco de dados geográfico.

De cara podemos dizer que só há vantagens ao utilizar vagrant e puppet para montar ambientes em Linux (dist Ubuntu) não tivemos um décimo das dificuldades apresentadas no Windows e o tempo transcorrido para redigir os scripts foi muito menor.

O maior desafio que encontramos é que algumas versões disponíveis por padrão nos repositórios do apt-get podem estar com uma grande defasagem, o que pode induzir ao erro ao usar uma versão antiga que contém bugs que já foram resolvidos, porém uma vez que você configura o repositório correto do pacote e instala as versões mais recentes o restante é muito prático.

Nós utilizamos postgres e postgis e é excelente ter um repositório de pacotes, fizemos todas as configurações, criação do database e configuração da extensão postgis.

Uma novidade foi utilizar um provider diferente ao utilizar o resource package, pois utilizamos o pip3 para instalação dos pacotes python, porém não tivemos problema algum.

Não identifiquei desvantagens ao escrever o script puppet para uma maquina linux, basta ter atenção às versões que são instaladas pelos repositórios default do apt-get e na dúvida utilize o repositório da fornecedora do software.

Para não dizer que a experiência foi livre de problemas, perdemos um tempo para instalar corretamente o puppet, pois às maquinas ubuntu disponíveis não trazem mais esta instalação por padrão.

A grande vantagem neste caso é que a replicação para outros provider do vagrant se torna fácil, permitindo que eu utilize o virtualbox, vmware, amazon aws ou digital ocean.

Template de história de Usuário

As histórias de usuários são ferramentas interessantes para se determinar quais são as funcionalidades reais de um sistema a ser construído.

Elas são breves, capturam as informações gerais e servem de documentação de alto nível para diversos outros produtos dentro da organização que constrói software.

Nós da SIGMA, construímos um pequeno template para ser impresso e que você pode levar com você para qualquer lugar. Este template será disponibilizado em nosso repositório, de forma gratuita.

O que são?

Histórias de Usuários são pequenos documentos que ajudam a descrever uma funcionalidade a ser implementada em determinado sistema.

Elas, através de uma única sentença, tentam capturar um requisito de negócio e seu valor para o negócio.

Estas histórias, geralmente são no seguinte formato:

  • Eu, como administrador do sistema, gostaria de delegar permissões a outros usuários, de forma que eles possam executar seu trabalho sem me incomodar;
  • Eu, como usuário, gostaria de abrir uma ocorrência, de forma que ela fique registrada e alguém possa resolver este problema;

As histórias, são geralmente escritas utilizando pequenos quadradinhos de papel com cola amarelos, ou os PostITs. No nosso caso, criamos um template para ser impresso e ser utilizado com papel e caneta.

Exemplo

Um exemplo prático completo, é o seguinte:

  • Título: Visualizar ocorrências em um mapa
  • Prioridade: A (na SIGMA usamos da letra A até a letra D para denotar prioridades, onde A é a prioridade mais alta e D a mais baixa);
  • Ação: Eu, como usuário do sistema, gostaria de visualizar as ocorrências em um mapa, de forma que eu possa otimizar a minha rota de atendimento;

Além desta seção básica, contendo estas informações, adicionamos uma área para você detalhar as tarefas necessárias para completar aquela história de usuário, bem como o número de pontos que cada tarefa e a história irão tomar.

Abraços!

Docgen

Olá pessoal, boa tarde!

Estamos prestando uma consultoria à um órgão governamental que possui um banco de dados em PostgreSQL bastante extenso. Uma de nossas tarefas era documentar o banco de dados todo, incluindo a criação de um dicionário de dados compreensivo, com informações sobre as tabelas, views, procedures, etc.

Como o banco é grande, possuindo muitos objetos, decidimos criar uma solução simples em Python que conecta-se ao banco de dados e utilizando um template, escreve o dicionário para nós, baseados nos comentários existentes para cada objeto.

No PostgreSQL, acredito que quase todos os objetos do banco possuem um campo de comentário, ou seja, ao invés da documentação ficar somente no papel, ela fica diretamente armazenada no campo de comentário de cada objeto, podendo ser consultada por quem já tem permissão aquele determinado objeto. É uma ideia simples, mas funcional.

Para inserir os comentários em lote, geramos um arquivo .yaml estruturado, onde as descrições podem ser preenchidas e posteriormente sincronizadas com o banco de dados. Outro utilitário, gera a documentação no formato de um template, podendo o mesmo ser customizado.

Ainda precisa de algumas mudanças e criação de testes para ficar um pouco mais modular, mas basicamente conseguimos ler todo o catálogo do PostgreSQL e gerar esta documentação em pouquíssimo tempo.

Outras funcionalidades veem a mente:

  • Geração de diagramas de forma automatizada;
  • Geração de relatórios de problemas comuns de banco de dados (ex: chave única em que é permitido valor nulo, etc);
  • Refatoração do código para funcionar com outros bancos de dados;

O docgen foi um projeto interessante de ser feito. Todo escrito em Python e agilizou bastante nossa vida. Fiquem a vontade para conhecê-lo no Github.

Traduzindo a documentação do PostGIS

Olá pessoal,

Existe um tremendo esforço atualmente para realizar a tradução da documentação do PostGIS. Anteriormente, este era um processo muito chato, que envolvia copiar arquivos, traduzir enormes parágrafos sem referências em um formato que não é muito familiar para muitas pessoas, o xml.

Em discussão com o time do PostGIS, conseguimos ajustar uma conta em um site especializado para isto, o Transifex. Dentro do Transifex, qualquer um pode criar uma conta pessoal ou de um projeto (nosso caso) e importar os arquivos brutos de documentação. O Transifex é inteligente, separando o que deve e o que não deve ser traduzido, permitindo a criação de múltiplas línguas “alvo” para a tradução.

Através dele, é possível administrar quais são os colaboradores, qual linguagem ele tem permissão para traduzir e estabelece processos formais de revisão, string por string.

Atualmente, temos as seguintes línguas e as porcentagens de tradução de cada uma:

  • Inglês – 100% (original);
  • Italiano – 36%;
  • Francês – 28%;
  • Espanhol – 26%;
  • Português Brasil – 17%;
  • Coreano – 6%;
  • Polonês – 8%;

Existem ainda mais umas dez línguas, mas sem nenhuma tradução.

Precisamos aumentar a margem de tradução para o Português. Embora nós, aqui na SIGMA, tenhamos traduzido um pouco por dia, o esforço é muito grande.

Ajude-nos! Crie uma conta no Transifex e solicite um login na página de tradução do PostGIS. Logo que possível, autorizo a tradução e basta mandar brasa.

Lembro ainda, que ajudar na tradução da documentação é uma boa fonte de aprendizado, já que você acaba se obrigando a ler toda a documentação que for traduzir. Existem coisas que eu mesmo nem sabia que existiam que aprendi através da tradução direta dos documentos.