sábado, 28 de janeiro de 2023

Como criar uma aplicação em Python que escreva e consulte um banco Redis.

No mundo da programação web, é muito comum observar aplicações que fazem leitura e escrita no Redis. O Redis é um banco de dados, do tipo chave/valor, com armazenamento em memória volatil(ram), ou seja, não faz escrita no disco. Portanto é uma excelente opção para escritas que precisam de velocidade, tanto de escrita quanto de consulta.

Para o teste, criei o seguinte arquivo docker-compose, com um container em redis e um container para rodar um worker em python.

para isso, precisamos instalar o modulo redis, no python.

Nota: Crie um virtual env, e dentro dele instale os modulos do redis. Dai crie um arquivo, to tipo freeze, para instala-lo em seu container sempre que for buildar.

$pip install redis
Para que isso seja impl

$pip freeze > requiriments.txt

Abaixo minha arvore de diretórios, para fins didaticos:
├── Dockerfile
├── app
│ ├── requirements.txt
│ └── worker.py
├── config
├── docker-compose.yaml
├── requirements.txt

Segue o código para o worker:

import time
from datetime import datetime
import redis
import os



def start():
ctime = datetime.now()
ts = int(round(ctime.timestamp()))
# Criando uma conexão com o banco Redis
print('Iniciando inserção de dados no redis')
REDIS_MASTER_NAME = os.environ.get('REDIS_MASTER_NAME')
REDIS_PASSWORD = os.environ.get('REDIS_PASSWORD')
REDIS_ENDPOINTS = os.environ.get('REDIS_ENDPOINTS')

print(type(ts))
r = redis.Redis(host=REDIS_ENDPOINTS, port=6379, db=0)
r.set(ts,'Rodrigo,{}'.format(ts))

if __name__ == "__main__":
while True:
start()
time.sleep(1)

arquivo .env

REDIS_MASTER_NAME=redis
REDIS_PASSWORD=mypass
REDIS_ENDPOINTS=redis

Segue o docker-file:

version: '3'
services:
worker:
image: worker:1
command: ["python", "/opt/app/worker.py"]
env_file:
- config/.env
links:
- redis
redis:
image: redis
ports:
- "26379:26379"
environment:
- MASTER_NAME=mymaster
- MASTER_PASSWORD=mypass
- REQUIRE_PASS=mypass

$docker build . -t worker:1
$docker-compose up
Entre no redis, para verificar a inserção das chaves, la dentro use o comando keys *:
$docker exec -it poc-redis_redis_1 redis-cli

127.0.0.1:6379> keys *
4182) "1674941584"
4183) "1674940348"
127.0.0.1:6379> get 1674940348
"Rodrigo,1674940348"
127.0.0.1:6379>

Prontinho, seu redis está pronto para uso. Lembre-se que eleprecisa de uma função para deletar as chaves, ou então todos os dados ficarão permanentes na memória até o pod ser desligado.

Para isso(limpar tudo) use o comando Flushall:

127.0.0.1:6379> FLUSHALL

Geralmente, em uso pratico, deve-se limpar o redis depois que se remove o dado para um local em armazenamento fixo, como um mysql. Ou seja, coletou uma chave e enviou para o mysql, deleta a chave. Isso vai garantir um que seu sistema tenha um uso pratico com custos menores. Posteriormente, criarei um container de consumo, um mysql-consumer com essa função.


Como ler arquivos de configuração no python.

Neste texto irei demonstrar como se faz a leitura de arquivos de configuração(arquivos INI) no python.

É muito comum nos depararmos com arquivos de configuração, eles facilitam o gerenciamento de rollouts. São arquivos do tipo 'chave x valor' separados em sessões, que servem em muitas vezes para a configuração de aplicativos. 

No exemplo abaixo temos o arquivo de configuração com a extenção python.conf.

[client]
port = 8080
pass = clientpass
key = true
[admin]
port = 8090
pass = adminpass
key = false

[system]
defaut = 0
security = 1

Para fazermos a leitura deste documento temos o módulo configparser.

Abaixo um exemplo de como ler a variavel porta, da seção(cabeçalho) "client":

import configparser

# Cria um objeto de configuração
config = configparser.ConfigParser()

# Lê o arquivo my.cnf
config.read('python.conf')

# Extrai o valor da porta do cabeçalho client
port = config.get('client', 'port')
print(port)

O resultado é 8080, caso queira extrair do cabeçalho admin basta substituir client por admin e tera a porta 8090.

Abaixo uma opção para validarmos todas as sessões lidas no arquivo de configuração, bem como validarmos se uma sessão existe dentro do arquivo de configuração.

import configparser

# Cria um objeto de configuração
config = configparser.ConfigParser()

# Lê o arquivo my.cnf
config.read('python.conf')

#Ler todas as sessões(cabeçalhos) do arquivo.
debug_sectopn = config.sections()
print(debug_sectopn)
#Validar se uma sessão existe dentro do arquivo.
debug_validar = 'client' in config
print(debug_validar)

O resultado esperado são todos os cabeçalhos da seção bem como um valor boleano(true) para a sessão client.

Também é possivel utilizar array, formatando o arquivo ini.
Segue abaixo a seção [system], do arquivo python.conf.:
[system]
defaut = false
security = true
array = [1,2,3]

Para chamar a seção system.array, iremos utilizar o método get do configparser.

import configparser
import json
# Cria um objeto de configuração
config = configparser.ConfigParser()

# Lê o arquivo my.cnf
config.read('conf/python.conf')

#debug
valor = config.get('system','array')
valor = json.loads(valor)
print(valor)
print(type(valor))

output:

user@workstation poc-python %python ex3.py
[1, 2, 3]
<class 'list'>
user@workstation poc-python %