Integração que lê itens de exames de um banco SQL Server, agrupa por solicitação e envia pedidos para a API da Bemsoft (POST /requests). Roda em loop (daemon/worker), com checkpoint incremental, retries, idempotência e persistência de falhas para reprocessamento.
Documentação BemSoft: https://bemsoft.ws.wiselab.com.br/swagger
- Lê novos registros da tabela
ItemSol(join comsolicitacaoepaciente) filtrando porNomeTerceirizado. - Usa um checkpoint persistente (
dbo._MonitorState.LastItemId) para processar somente itens novos. - Debounce opcional para aguardar a solicitação “assentar” antes de enviar.
- Agrupa linhas por
CodSolicitacaoe monta 1 payload por solicitação. - Resolve
supportSpecimenIdconsultando e cacheando o catálogoGET /testsda Bemsoft. - Suporta mapeamento local de códigos de exame →
supportTestIdvia arquivo JSON. - Envia
POST /requestscomIdempotency-Keybaseada emCodSolicitacaoe com retries/backoff. - Salva falhas em disco (
FAILED_DIR) para reenvio manual. - Modo
DRY_RUNpara validar transformação e payload sem fazer chamadas HTTP.
Fluxo resumido: SQL Server → transformar → (cache /tests) → POST /requests → checkpoint atualizado → falhas em completo/failed_events/ (se houver).
- Python 3.10+
- Pacotes Python:
requests,urllib3,sqlalchemy,pyodbc,python-dotenv - SQL Server acessível e driver ODBC instalado (recomendado: “ODBC Driver 18 for SQL Server”).
Observação (Windows): instale o driver ODBC 18 e o pacote pyodbc. No Linux, garanta unixODBC e o driver MS ODBC correspondentes.
Todas as variáveis são lidas de um arquivo .env na raiz. Principais chaves:
-
Banco de dados
DB_SERVER: ex.localhost\SQLEXPRESSou10.0.0.5\SQLEXPRESSDB_NAME,DB_USER,DB_PASSODBC_DRIVER: ex.ODBC Driver 18 for SQL Server
-
Leitura/execução
POLL_SECONDS: intervalo de polling (segundos)DEBOUNCE_SECONDS: atraso (em segundos) antes do envio; ex.:300= espera 5 minutos (0 desliga)TERCEIROS: lista separada por vírgula com os nomes emItemSol.NomeTerceirizado(ex.:DIAGNÓSTICO DO BRASIL - DB,AME-SE - PARDINI)TERCEIRO: opção legada (um único nome); se definido, será usado como fallbackFAILED_DIR: pasta onde salvar falhas (padrãocompleto/failed_events)
-
Bemsoft
BEMSOFT_BASE_URL: ex.https://bemsoft.ws.wiselab.com.brBEMSOFT_ENDPOINT: ex./requestsBEMSOFT_TOKEN: token Bearer de produção (obrigatório seDRY_RUN=0)BEMSOFT_TIMEOUT,BEMSOFT_RETRIES,BEMSOFT_BACKOFF,BEMSOFT_VERIFYBEMSOFT_DRY_RUN:1para não enviar (somente gerar payload),0para enviar
-
Defaults de dados (usados quando o legado não fornece)
DEFAULT_GENDER:MouF(obrigatório se não vier do paciente)DEFAULT_BIRTHDATE:YYYY-MM-DD(obrigatório se não vier do paciente)
-
Médico (opcional – envia somente se todos estiverem preenchidos)
PHYSICIAN_NAME,PHYSICIAN_COUNCIL,PHYSICIAN_NUMBER,PHYSICIAN_UF
-
Mapeamento de exames (opcional)
BEMSOFT_TEST_MAP_PATH: caminho para um JSON com{ "<codigo_local>": "<supportTestId>" }
Você pode começar copiando o arquivo de exemplo e ajustando:
cp .env.example .env # Linux/macOS
REM copy .env.example .env # Windows (cmd)
Exemplo mínimo de .env (sanitizado):
DB_SERVER=localhost\SQLEXPRESS
DB_NAME=MinhaBase
DB_USER=usuario
DB_PASS=senha
ODBC_DRIVER=ODBC Driver 18 for SQL Server
POLL_SECONDS=5
DEBOUNCE_SECONDS=300
TERCEIROS=DIAGNÓSTICO DO BRASIL - DB,AME-SE - PARDINI,AME-SE LABORATORIO
BEMSOFT_BASE_URL=https://bemsoft.ws.wiselab.com.br
BEMSOFT_ENDPOINT=/requests
BEMSOFT_TOKEN=coloque_seu_token_aqui
BEMSOFT_DRY_RUN=1
DEFAULT_GENDER=M
DEFAULT_BIRTHDATE=1970-01-01
Exemplo de arquivo de mapeamento (tests_map.json):
{
"HEMOGRAMA": "HB-001",
"GLICOSE": "GLU-FAST",
"12345": "TEST-12345"
}
Depois, aponte BEMSOFT_TEST_MAP_PATH=./tests_map.json no .env.
- Crie e ative um ambiente virtual (opcional):
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
- Instale as dependências:
pip install -r requirements.txt
-
Configure o
.envconforme sua infraestrutura. -
Execute o monitor:
python main.py
Mensagens de log no console mostram o evento agrupado por solicitação e o resultado do envio. Com BEMSOFT_DRY_RUN=1, apenas imprime o payload gerado (sem enviar).
Atalhos (scripts prontos em scripts/):
- Linux/macOS:
bash scripts/start_monitor.shebash scripts/stop_monitor.sh - Windows:
scripts\start_monitor.batescripts\stop_monitor.bat
Para rodar automaticamente no servidor de produção, você pode gerar um executável standalone e instalá-lo como serviço Windows.
Na máquina de desenvolvimento (com o código-fonte):
build.batEste script vai:
- Instalar o PyInstaller automaticamente
- Gerar o arquivo
dist\BemsoftMonitor.exe(executável único) - Incluir todas as dependências necessárias
Copie os seguintes arquivos para o servidor:
BemsoftMonitor.exe (do diretório dist/)
.env (configurado com as credenciais do servidor)
install_service.bat
uninstall_service.bat
Opcionalmente, copie também o nssm.exe (baixe de nssm.cc) para a mesma pasta.
No servidor, execute como Administrador:
install_service.batIsso vai:
- Verificar se o NSSM está instalado (necessário para gerenciar serviços)
- Criar o serviço "BemsoftMonitor"
- Configurar para iniciar automaticamente com o Windows
- Criar logs em
logs\service_output.logelogs\service_error.log - Iniciar o serviço imediatamente
Comandos úteis (executar como Administrador):
# Ver status
sc query BemsoftMonitor
# Parar
sc stop BemsoftMonitor
# Iniciar
sc start BemsoftMonitor
# Ver logs em tempo real
type logs\service_output.logOu use o gerenciador de serviços do Windows (services.msc).
Para remover o serviço, execute como Administrador:
uninstall_service.batO servidor Windows precisa ter instalado:
- ODBC Driver 18 for SQL Server (ou outra versão configurada no
.env) - Visual C++ Redistributable (geralmente já instalado)
- O executável já inclui Python e todas as bibliotecas
- Erro de permissão: Execute os scripts como Administrador
- NSSM não encontrado: Baixe de nssm.cc e coloque
nssm.exena mesma pasta - Serviço não inicia: Verifique os logs em
logs\service_error.log - Erro de conexão SQL: Verifique o
.enve se o ODBC Driver está instalado - Arquivo .env não encontrado: O
.envdeve estar na mesma pasta do executável
Use o script retry_failed.py para reenviar eventos salvos em FAILED_DIR.
- Dry-run (padrão, não envia):
python retry_failed.py --dir completo/failed_events
- Enviar de fato (override
BEMSOFT_DRY_RUN=0neste processo):
python retry_failed.py --dir completo/failed_events --send
- Processar um arquivo específico e mover os enviados com sucesso:
python retry_failed.py --file completo/failed_events/20240101T120000Z_123.json --send --move-ok completo/sent
- Limitar a N arquivos e mostrar detalhes de resposta:
python retry_failed.py --limit 10 --send --verbose
Atalhos (scripts):
- Linux/macOS:
bash scripts/start_retry.sh [completo/failed_events]ebash scripts/stop_retry.sh - Windows:
scripts\start_retry.batescripts\stop_retry.bat
- Checkpoint incremental: tabela
dbo._MonitorStateé criada automaticamente (se não existir) e armazenaLastItemId. O monitor lê sempre itens comCodItemSol > LastItemId. - Agrupamento por solicitação: todas as linhas com o mesmo
CodSolicitacaosão agregadas em um único payload de pedido. - Janela de debounce: cada solicitação detectada entra em uma fila in-memory e só é enviada após
DEBOUNCE_SECONDSsegundos (logs[debounce]indicam o tempo restante e a quantidade na fila). - Datas/horários: prioriza
solicitacao.dtaentrada+Hora; se não disponíveis, tentaItemSol.DataEntrada; por fim usa o horário atual (fuso −03:00). - Paciente: gera
externalIdestável com base emcodpacienteou CPF; exigebirthDateegender(ou usa os defaults do.env). - Exames (tests):
supportTestIdvem do código local mapeado (arquivo JSON) ou do próprioCodConvExames.supportSpecimenIdé resolvido pelo catálogoGET /tests(cacheado em memória). NoDRY_RUN, é usado um valor dummy (SPECIMEN-TEST).
- Envio para Bemsoft:
- Cabeçalhos:
Authorization: Bearer <TOKEN>eIdempotency-Key: sol-<CodSolicitacao>. - Retry e backoff automáticos para 502/503/504.
- Respeita
BEMSOFT_VERIFYpara verificação TLS.
- Cabeçalhos:
- Falhas: qualquer erro de transformação/envio gera um arquivo JSON em
FAILED_DIRcom o motivo e o evento completo para posterior reenvio.
Para reenviar um evento salvo em FAILED_DIR, você pode usar um REPL Python:
python
>>> import json
>>> from bemsoft_api import send_to_bemsoft
>>> data = json.load(open('completo/failed_events/20240101T120000Z_123.json', encoding='utf-8'))
>>> send_to_bemsoft(data['event'])
Garanta BEMSOFT_DRY_RUN=0 e BEMSOFT_TOKEN válidos para que o envio ocorra.
- Conexão ODBC: confirme o driver (
ODBC Driver 18 for SQL Server) instalado e credenciais válidas. - Certificado/TLS: ajuste
BEMSOFT_VERIFY=0apenas para teste (não recomendado em produção). - Catálogo
/tests: é necessárioBEMSOFT_TOKENpara carregar; sem ele e fora doDRY_RUN, a resolução desupportSpecimenIdfalhará. supportSpecimenId ausente: ajuste seu mapeamento (BEMSOFT_TEST_MAP_PATH) ou valide o catálogo da Bemsoft.
main.py: script principal (poll, transformação, envio, retries, falhas).retry_failed.py: utilitário CLI para reprocessar eventos com falha..env: configurações locais (não commitar segredos reais em repositórios públicos).completo/failed_events/: diretório (criado automaticamente) para eventos que falharam.
- Baixe e instale o NSSM (Non-Sucking Service Manager).
- Execute:
nssm install BemsoftMonitor "C:\\Path\\to\\python.exe" "C:\\Path\\to\\project\\main.py"
- Em “Startup directory”, aponte para a pasta do projeto. Garanta que o
.envesteja na raiz do projeto e acessível pelo serviço. - Inicie o serviço pelo Services.msc:
BemsoftMonitor.
Para o reprocessador de falhas, você pode criar outro serviço apontando para retry_failed.py --send se desejar reprocessamento contínuo (não recomendado em paralelo com o monitor sem coordenação).
Arquivo de unidade exemplo (/etc/systemd/system/bemsoft-monitor.service):
[Unit]
Description=Bemsoft Monitor (SQL -> Bemsoft)
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/bemsoft-monitor
ExecStart=/usr/bin/python3 /opt/bemsoft-monitor/main.py
Restart=on-failure
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
Comandos:
sudo systemctl daemon-reload
sudo systemctl enable bemsoft-monitor
sudo systemctl start bemsoft-monitor
sudo systemctl status bemsoft-monitor
Garanta que o .env exista em /opt/bemsoft-monitor/.env e o diretório tenha permissões corretas.