Este projeto implementa um motor de decisões baseado em JsonLogic com funcionalidades estendidas, incluindo suporte completo para funções assíncronas.
Nova funcionalidade implementada! O projeto agora suporta execução assíncrona de regras com funções que fazem I/O, consultas de banco de dados, chamadas de API, etc.
📖 Documentação Completa do Suporte Assíncrono
- ✅ Implementação completa do JsonLogic padrão
- ✅ Operações matemáticas, lógicas e de comparação
- ✅ Manipulação de arrays e strings
- ✅ Suporte a funções personalizadas síncronas
- ✅ Acesso a dados aninhados
- ✅ Execução assíncrona de regras (
jsonLogicAsync) - ✅ Suporte a funções síncronas e assíncronas na mesma regra
- ✅ Detecção automática de execução sync/async (
jsonLogicAuto) - ✅ Operações paralelas otimizadas para melhor performance
- ✅ Backward compatibility total com JsonLogic original
- ✅ Chamadas de API, I/O, banco de dados sem bloquear execução
- ✅ Melhor performance para operações I/O-bound
# Clone o repositório
git clone <repo-url>
cd poc-jsonlogic
# Instale as dependências
poetry install
# Ou usando pip
pip install -e .from src.lib.json_logic import jsonLogic
# Dados
dados = {
"usuario": {"nome": "João", "idade": 25},
"produto": {"preco": 100}
}
# Regra
regra = {
"and": [
{">": [{"var": "usuario.idade"}, 18]},
{"<": [{"var": "produto.preco"}, 200]}
]
}
# Execução
resultado = jsonLogic(regra, dados)
print(resultado) # Trueimport asyncio
from src.lib.json_logic import jsonLogicAsync
# Função assíncrona personalizada
async def consultar_score_credito(cpf):
# Simula consulta a API externa
await asyncio.sleep(0.2)
return 750
# Função síncrona
def calcular_limite(score):
return score * 10
# Registro de funções
funcoes = {
"get_score": consultar_score_credito,
"calc_limite": calcular_limite,
}
# Dados
dados = {"cpf": "12345678901", "valor_solicitado": 5000}
# Regra que combina sync e async
regra = {
">=": [
{"apply": [
"calc_limite",
{"apply": ["get_score", {"var": "cpf"}]}
]},
{"var": "valor_solicitado"}
]
}
# Execução assíncrona
async def main():
resultado = await jsonLogicAsync(regra, dados, funcoes)
print(f"Crédito aprovado: {resultado}")
asyncio.run(main())from src.lib.json_logic import jsonLogicAuto
# Detecta automaticamente se deve usar sync ou async
resultado = jsonLogicAuto(regra, dados, funcoes)
if asyncio.iscoroutine(resultado):
# Tem funções async - execute com await
final_result = await resultado
else:
# Apenas funções sync - resultado direto
final_result = resultadoimport asyncio
from src.lib.json_logic import jsonLogic_async
# Funções de negócio assíncronas
async def consultar_serasa(cpf):
await asyncio.sleep(0.3) # Simula latência
return {"score": 720, "restricoes": False}
async def verificar_renda(user_id):
await asyncio.sleep(0.2)
return {"valor": 5000, "comprovada": True}
# Função síncrona
def calcular_limite_credito(renda, score):
if score > 700:
return renda * 3
elif score > 600:
return renda * 2
return renda * 0.5
# Registro de funções
funcoes = {
"get_serasa": consultar_serasa,
"get_renda": verificar_renda,
"calc_limite": calcular_limite_credito,
}
# Dados da solicitação
dados = {
"cpf": "12345678901",
"user_id": 123,
"valor_solicitado": 10000
}
# Regra complexa de aprovação
regra_aprovacao = {
"and": [
# Score > 600 e sem restrições
{">": [
{"apply_async": ["get_serasa", {"var": "cpf"}]},
{"score": 600}
]},
{"==": [
{"apply_async": ["get_serasa", {"var": "cpf"}]},
{"restricoes": False}
]},
# Renda comprovada
{"==": [
{"apply_async": ["get_renda", {"var": "user_id"}]},
{"comprovada": True}
]},
# Valor <= limite calculado
{"<=": [
{"var": "valor_solicitado"},
{"apply": [
"calc_limite",
{"apply_async": ["get_renda", {"var": "user_id"}]},
{"apply_async": ["get_serasa", {"var": "cpf"}]}
]}
]}
]
}
async def processar_credito():
inicio = time.time()
aprovado = await jsonLogic_async(regra_aprovacao, dados, funcoes)
fim = time.time()
print(f"Crédito {'APROVADO' if aprovado else 'NEGADO'}")
print(f"Processamento: {fim - inicio:.2f}s")
asyncio.run(processar_credito())# Testes do JsonLogic original
python -m pytest src/tests/test_json_logic.py -v
# Testes de suporte assíncrono
python -m pytest src/tests/test_async_support.py -v
# Todos os testes
python -m pytest src/tests/ -v# Teste de carga rápido - Comparação Sync vs Async
python src/tests/test_quick_load_performance.py
# Teste de carga completo com múltiplos cenários
python src/tests/test_load_performance_comparison.py
# Benchmark detalhado de performance
python src/tests/test_benchmark_complete.py
# Teste de melhores práticas
python src/tests/test_best_practices.py
# Teste de carga original
python src/tests/test_load_test.py# Exemplo assíncrono
python exemplo_async.pyCenário 1: Operações Matemáticas Simples (200 iterações)
- 🔄 Sync: 14.532,7 ops/s (⌀ 0.07ms) - ✅ Mais eficiente
- ⚡ Async: 554,2 ops/s (⌀ 1.80ms) - 96.2% mais lento
- 🚀 Concurrent: 2.030,1 ops/s (⌀ 2.45ms) - 86.0% mais lento
Cenário 2: Operações Computacionais Pesadas (100 iterações)
- 🔄 Sync: 52.217,1 ops/s (⌀ 0.02ms) - ✅ Mais eficiente
- ⚡ Async: 169,3 ops/s (⌀ 5.90ms) - 99.7% mais lento
- 🚀 Concurrent: 842,2 ops/s (⌀ 5.93ms) - 98.4% mais lento
| Tipo de Operação | Melhor Escolha | Motivo |
|---|---|---|
| CPU-bound (matemática, lógica) | Sync | Sem overhead de async |
| I/O-bound (API, DB, rede) | Async | Paralelização de I/O |
| Misto | Auto | Detecção automática |
| Cenário | JsonLogic Sync | JsonLogic Async | Melhoria |
|---|---|---|---|
| 3 consultas sequenciais | ~0.9s | ~0.4s | 55% mais rápido |
| 5 validações paralelas | ~1.5s | ~0.6s | 60% mais rápido |
| Regras complexas | ~2.1s | ~0.8s | 62% mais rápido |
Dados baseados em simulações com latência de rede de 200ms
# ✅ Use SYNC para operações CPU-bound
regra_matematica = {"+": [{"var": "a"}, {"var": "b"}]}
resultado = jsonLogic(regra_matematica, dados)
# ✅ Use ASYNC para operações I/O-bound
regra_com_api = {"apply": ["consultar_api", {"var": "id"}]}
resultado = await jsonLogicAsync(regra_com_api, dados, funcoes_async)
# ✅ Use AUTO para detecção automática
resultado = jsonLogicAuto(regra, dados, funcoes_mistas)
if asyncio.iscoroutine(resultado):
resultado = await resultado-
Overhead Async é Significativo para CPU-bound
- Async pode ser 96-99% mais lento para operações puras de CPU
- Event loop e context switching adicionam latência considerável
- Para matemática/lógica pura, prefira sempre sync
-
Concorrência Melhora Async mas Não Vence Sync
- Concurrent async é 60-80% mais lento que sync puro
- Benefício real apenas com I/O blocking genuíno
- Use concurrent para operações independentes com I/O
-
Detecção Automática (
jsonLogicAuto) é Inteligente- Detecta presença de funções async automaticamente
- Escolhe a melhor estratégia sem intervenção manual
- Recomendado para aplicações mistas
-
Throughput Varia Drasticamente por Cenário
- Sync: 14.000-52.000 ops/s (operações simples)
- Async: 169-554 ops/s (com sleep simulado)
- Concurrent: 842-2.030 ops/s (melhor que async sequencial)
| Se sua aplicação tem... | Use... | Motivo |
|---|---|---|
| Apenas regras matemáticas | jsonLogic() |
Máxima performance |
| APIs/DB externos | jsonLogicAsync() |
Paralelização de I/O |
| Mistura de ambos | jsonLogicAuto() |
Detecção automática |
| Milhares de regras/seg | jsonLogic() |
Throughput superior |
1. Substituir chamada de função:
# Antes
resultado = jsonLogic(regra, dados, funcoes)
# Depois
resultado = await jsonLogic_async(regra, dados, funcoes)2. Adicionar funções assíncronas:
# Mantenha funções existentes
funcoes_sync = {"calc": lambda x, y: x + y}
# Adicione novas funções async
async def fetch_data(id):
return await api_call(id)
# Combine ambas
funcoes_completas = {
**funcoes_sync,
"fetch": fetch_data,
}
# Use operações específicas
regra = {
"apply": ["calc", 10, 20], # Síncrona
"apply_async": ["fetch", "123"] # Assíncrona
}src/
├── lib/
│ └── json_logic.py # Core: JsonLogic + JsonLogic Async
├── tests/
│ ├── test_async_support.py # Testes para o suporte a funções assíncronas
│ ├── test_best_practices.py # Demonstração de melhores práticas
│ ├── test_benchmark_complete.py # Benchmark completo de performance
│ ├── test_json_logic.py # Testes originais do JsonLogic
│ ├── test_load_performance_comparison.py # Teste de carga: Sync vs Async
│ ├── test_load_test.py # Testes de carga originais
│ ├── test_performance_quick.py # Teste de performance rápido
│ ├── test_performance_sync_async.py # Comparação detalhada sync/async
│ └── test_quick_load_performance.py # Teste de carga rápido
├── motor_regras.py # Motor de regras
├── regras.py # Definições de regras
└── acoes.py # Ações do sistema
- Lógicas:
and,or,!,?: - Comparação:
==,!=,>,>=,<,<= - Matemáticas:
+,-,*,/,%,min,max - Dados:
var,in,count - Arrays:
some,every,map,filter,merge - Strings:
cat - Sistema:
log
apply_async: Executa função assíncronaapply: Executa função síncrona (com validação de tipo)- Operações lógicas assíncronas:
and,orcom suporte a async - Operações de array assíncronas:
map,filter,some,every
- 🌐 Regras que fazem consultas HTTP/API
- 🗄️ Validações que acessam banco de dados
- 📊 Cálculos que dependem de múltiplas fontes externas
- ⚡ Cenários que se beneficiam de paralelismo
- 🔄 Sistemas que processam muitas regras simultaneamente
- 🧮 Regras puramente matemáticas/lógicas
- 💾 Operações apenas com dados em memória
- 🏃 Cenários onde latência mínima é crítica
- 🔒 Ambientes que não suportam async/await
- ⚡ High-throughput CPU-bound operations (conforme testes de carga)
- Fork o projeto
- Crie uma branch para sua feature (
git checkout -b feature/nova-funcionalidade) - Commit suas mudanças (
git commit -am 'Adiciona nova funcionalidade') - Push para a branch (
git push origin feature/nova-funcionalidade) - Abra um Pull Request
Este projeto está licenciado sob a licença MIT - veja o arquivo LICENSE para detalhes.
jsonlogic async motor-decisoes regras-negocio python asyncio performance poc
- Propósito: Comparação rápida entre sync, async e concurrent
- Cenários: Operações matemáticas simples e computação pesada
- Métricas: Throughput, latência média, taxa de sucesso
- Propósito: Análise detalhada sob diferentes cargas de trabalho
- Cenários: Light Load, Medium Load, Heavy Load
- Métricas: Performance completa com estatísticas detalhadas
- Propósito: Benchmark em diferentes tipos de operação
- Cenários: CPU-bound, I/O simulation, lógica complexa
- Métricas: Análise comparativa profunda
- Propósito: Demonstra padrões corretos vs anti-patterns
- Foco: Evitar objetos literais, usar operações lógicas puras
- Objetivo: Educacional e validação de qualidade
# Teste rápido (2-3 segundos)
python src/tests/test_quick_load_performance.py
# Teste completo (1-2 minutos)
python src/tests/test_load_performance_comparison.py
# Benchmark profundo (3-5 minutos)
python src/tests/test_benchmark_complete.py
# Validação de práticas
python src/tests/test_best_practices.py