Arquitetura orientada a eventos com lambda functions no Python
Tags: architecture, eventdriven, programming, beginners
Published: 2021-11-29 13:09:15

**Orientação a eventos** é um assunto em evidencia ultimamente, porém não é algo novo, mas ainda gera algumas duvidas, vou tentar sanar algumas.

1. Eventos não devem ser confundidos com comandos, intenções, expectativas ou transferência de dados.
2. Change Data Capture(CDC) é ferramenta para transito de dados, dificilmente teremos um evento neste cenário.
3. Eventos são específicos, e representam algo relevante que ocorre do ponto de vista de negócio.
4. Eventos devem conter apenas dados relevantes para o próprio evento
5. Evento não é alteração de tabela em banco de dados.

**Eventos são sempre descritos no passado:**

- Pedido Efetuado com Sucesso
- Aplicação Realizada
- Ordem de Compra Rejeitada

Frequentemente, principalmente quando queremos propagar os eventos para múltiplos domínios distintos, usamos mecanismos de mensageria (Brokers) para realizar esta propagação.

Desta forma, serviços interessados nesses eventos, assinam (subscription /consumer group / etc) este evento. Exemplo: consomem o tópico que o evento está sendo publicado.

Dica de leitura super legal e free sobre o tema **[aqui](https://www.confluent.io/designing-event-driven-systems/)**!

### Padrões de eventos

**Event Notification**

Esse padrão é usado quando um sistema envia mensagens de eventos para notificar outros sistemas sobre uma alteração em seu domínio. Neste padrão não temos detalhes (muitos atributos) sobre o evento na mensagem

**Event Carried State Transfer**

Neste padrão, o evento contém todas as informações sobre o comando executado (todos atributos relevantes para o evento) , é usado para evitar o contato com o aplicativo de origem para realizar processamento adicional pelos sistemas dependentes

Esse padrão traz os seguintes benefícios para a mesa:

- Melhora o desempenho do aplicativo
- Reduz a carga no aplicativo de origem
- Aumenta a disponibilidade do sistema

{% youtube STKCRSUsyP0 %}

**Manifesto Reativo**

Organizações que trabalham em diferentes ramos, estão independentemente descobrindo padrões aleatórios para criarem sistemas semelhantes. Esses sistemas são mais robustos, mais resistentes, mais flexíveis e melhor posicionados para sustentar as demandas modernas.

Essas transformações estão acontecendo por causa dos requisitos que mudaram drasticamente nos últimos anos. Apenas alguns anos atrás, grandes aplicações tinham dezenas de servidores, demoravam segundos para responder, tinham manutenções que demoravam horas e lidavam apenas com gigabytes de dados. Hoje há aplicações em produção em todos os lugares, desde aplicativos móveis até aplicações na nuvem com clusters rodando milhares processadores multi-core. Geralmente os usuários esperam respostas em milisegundos e 100% de disponibilidade. Dados são mensurados em Petabytes. As demandas de hoje simplesmente não são mais atendidas pelas arquiteturas de ontem.

Nós acreditamos que é necessária uma abordagem coerente para arquitetura de sistemas, e acreditamos que todos os aspectos necessários já são reconhecidos individualmente: nós queremos sistemas Responsivos, Resilientes, Elásticos e Orientados a Mensagens. Nós chamamos isso de Sistemas Reativos.

Sistemas criados como Reativos são muito mais flexíveis, desacoplados e escaláveis. Isso os torna mais fáceis de desenvolver e manter. São mais tolerantes a falhas e quando elas ocorrem são tratadas com elegância ao invés de desastre. Sistemas Reativos são responsivos, dando aos usuários feedbacks mais interativos.

### Diferenças entre programação reativa e orientada a eventos

Deve-se notar que existem algumas diferenças sutis entre a programação orientada a eventos e a programação reativa. A programação orientada a eventos concentra-se no tratamento de eventos como, por exemplo, um clique de botão e é o paradigma no qual a maioria dos sistemas operacionais se baseia. Se você executar uma ação em um sistema operacional, o ostratará isso como um evento e acionará a função correspondente para aquela ação.

A programação reativa, por outro lado, trata os dados passados ​​para os sistemas reativos como eventos. Você poderia ter um sistema reativo para ouvir as mudanças no preço das ações e apenas acionar uma ação quando uma ação atingir um determinado preço.

### Trabalhando com RxPY

Neste tutorial, exploraremos a biblioteca [RxPY](https://github.com/ReactiveX/RxPY), que é a biblioteca mais popular atualmente disponível para escrever sistemas reativos.

Para começar, vamos querer definir um fluxo de entrada que posteriormente observaremos e, em seguida, acionaremos ações caso um desses bits de dados atenda a determinados critérios.

Vamos imaginar que estejamos criando um sistema de negociação de ações que comprará e venderá ações dependendo de seu preço. Poderíamos ter uma série de ações como esta:

```python
stocks = [
  { 'TCKR' : 'APPL', 'PRICE': 200},
  { 'TCKR' : 'GOOG', 'PRICE': 90},
  { 'TCKR' : 'TSLA', 'PRICE': 120},
  { 'TCKR' : 'MSFT', 'PRICE': 150},
  { 'TCKR' : 'INTL', 'PRICE': 70},
]
```

Queremos então criar um Observableobjeto que irá emitir eventos com base no valor dos estoques. Neste exemplo, definiremos uma buy_stock_events(observer)função que iterará em nosso stocksarray e chamará a on_next()função sempre que o preço da ação for maior que 100.

```python
from rx import Observable

stocks = [
  { 'TCKR' : 'APPL', 'PRICE': 200},
  { 'TCKR' : 'GOOG', 'PRICE': 90},
  { 'TCKR' : 'TSLA', 'PRICE': 120},
  { 'TCKR' : 'MSFT', 'PRICE': 150},
  { 'TCKR' : 'INTL', 'PRICE': 70},
  { 'TCKR' : 'ELLT', 'PRICE': 0}
]

def buy_stock_events(observer):
  for stock in stocks:
    if(stock['PRICE'] > 100):
      observer.on_next(stock['TCKR'])
    elif(stock['PRICE'] <= 0):
      observer.on_error(stock['TCKR'])
  observer.on_completed()

source = Observable.create(buy_stock_events)
```

Depois de fazer isso, podemos nos inscrever em nosso sourceobjeto Observable da seguinte forma:

```python
source.subscribe(on_next=lambda value: print("Received Instruction to buy {0}".format(value)),
                on_completed=lambda: print("Completed trades"),
                on_error=lambda e: print(e))
```

Você notará que estamos passando 3 lambdafunções distintas para nossa chamada para subscribe(). Essas 3 lambdafunções são on_next()chamadas sempre que nosso Observável emite algo, on_completed()que é chamado quando nosso Observável não tem mais nada a nos dar e on_error()que é chamado sempre que há um erro emitido por nosso Observável.

Quando você executa isso, você deve ver isso APPL, TSLAe MSFTtodos acionam a on_next()função de nosso observador e uma ordem de compra é colocada. No entanto, quando nosso Observable tenta processá- ELLTlo , ele chama on_error()quando o preço da ação está definido como 0.

```python
$ python3.6 allLambda.py
Received Instruction to buy APPL
Received Instruction to buy TSLA
Received Instruction to buy MSFT
Stock has an invalid price: ELLT
```

Este é apenas um exemplo muito simples do que pode ser feito RxPY, há uma quantidade quase infinita de coisas diferentes que você pode fazer com esta biblioteca. Você pode, por exemplo, fazer com que um bot do Twitter procure tweets com base em uma determinada palavra-chave e sempre que um novo tweet aparecer, ele pode acionar um evento.