> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Tempo real

> Transmita os logs, o status e os eventos de sistema de uma aplicação ao vivo com client.apps.realtime(), um iterador (iterador assíncrono com o AsyncSquareCloud) que mescla os frames de status e se reconecta sozinho.

`client.apps.realtime(app_id)` abre um stream ao vivo dos logs, do status e dos eventos de sistema de uma aplicação. Com o `SquareCloud` ele é um **iterador** consumido com `for`; com o `AsyncSquareCloud` ele é um **iterador assíncrono** consumido com `async for`. Use-o em um bloco `with` / `async with` para que sair do bloco feche a conexão.

<Tabs>
  <Tab title="Síncrono">
    ```python theme={"system"}
    with client.apps.realtime(app_id) as stream:
        for event in stream:
            if event["event"] == "logs":
                print(event["stream"], event["line"])  # "stdout" | "stderr"
            elif event["event"] == "status":
                print(event["status"].get("cpu"), event["status"].get("ram"))  # always the full, merged state
            else:
                print(event["event"], event["data"])  # "system" or "error"
    ```
  </Tab>

  <Tab title="Assíncrono">
    ```python theme={"system"}
    async with client.apps.realtime(app_id) as stream:  # no await: realtime() is not a coroutine
        async for event in stream:
            if event["event"] == "logs":
                print(event["stream"], event["line"])  # "stdout" | "stderr"
            elif event["event"] == "status":
                print(event["status"].get("cpu"), event["status"].get("ram"))  # always the full, merged state
            else:
                print(event["event"], event["data"])  # "system" or "error"
    ```
  </Tab>
</Tabs>

Com o `AsyncSquareCloud`, `apps.realtime(app_id)` retorna um `AsyncRealtime` diretamente: **não** use `await` nele. Uma thread de leitura em segundo plano entrega os eventos ao seu event loop, então nenhuma thread do executor fica ocupada enquanto você espera.

## Eventos

Todo evento é um dict com `event`, `data` (o texto bruto do frame) e `id` (`None` quando o frame não tem um).

| `event`   | Campos extras    | Descrição                                                                                                                                                                     |
| --------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `logs`    | `stream`, `line` | Uma linha de log. O primeiro caractere de `data` indica o stream (`\u0001` stdout, `\u0002` stderr); o SDK o remove em `line` e define `stream` como `"stdout"` ou `"stderr"` |
| `status`  | `status`         | Métricas do container ao vivo. O primeiro frame é completo e os seguintes trazem apenas o que mudou: o SDK os mescla, então `status` é sempre o estado completo               |
| `system`  |                  | Eventos de conexão como `REALTIME_CONNECTING \| <id>`, `REALTIME_TIMEOUT` ou `REALTIME_DISCONNECTED`                                                                          |
| `error`   |                  | Um código de erro como `CONTAINER_NOT_FOUND`                                                                                                                                  |
| `message` |                  | Um frame sem nome de `event`                                                                                                                                                  |

### O objeto `status`

| Campo      | Descrição                                                          |
| ---------- | ------------------------------------------------------------------ |
| `cpu`      | Uso de CPU (%)                                                     |
| `cpuLimit` | Número de núcleos de CPU alocados                                  |
| `ram`      | `[usedMB, limitMB]`                                                |
| `status`   | Estado do container, por exemplo `running`                         |
| `netIO`    | Totais de rede `{ i, o }`, com `new` para o intervalo mais recente |
| `bIO`      | Totais de disco `{ i, o }`                                         |
| `uptime`   | Unix ms do início do container                                     |

## Encerrando o stream

O loop termina sozinho quando:

* o servidor fecha a conexão de forma limpa (cada conexão dura até **10 minutos**);
* o servidor envia `REALTIME_DISCONNECTED`;
* você sai do loop com `break` (e então deixa o bloco `with`, que fecha a conexão);
* você chama `stream.close()`, a partir de qualquer thread, mesmo enquanto o loop espera por dados ou por uma reconexão (o loop simplesmente termina, sem lançar erro).

`close()` é síncrono tanto em `Realtime` quanto em `AsyncRealtime`. Para continuar acompanhando além de 10 minutos, abra um novo stream quando o loop terminar.

```python theme={"system"}
import threading

stream = client.apps.realtime(app_id)
threading.Timer(60, stream.close).start()  # stop after one minute

for event in stream:
    print(event["event"], event["data"])
```

## Reconexão

Uma conexão perdida, ou o servidor delegando a reconexão ao cliente (`REALTIME_RECONNECT`), reabre o stream sozinho:

* até **3 vezes seguidas**; qualquer evento `logs` ou `status` zera a contagem;
* cada reabertura ocorre pelo menos **5,5 s** após a abertura anterior, para respeitar o ritmo da API de uma abertura a cada 5 segundos por aplicação.

Após 3 reconexões falhas, o loop lança um `SquareCloudAPIError` com `NETWORK_ERROR`. Cada abertura é um `GET`, então um erro de rede durante a abertura também é [tentado novamente](/pt-br/sdks/py/errors#novas-tentativas) até `max_retries` vezes; uma abertura que ainda falhe lança o erro.

## Limites e erros

* **5** conexões simultâneas por conta e **30** por aplicação, somando todos os usuários. Ultrapassar resulta em 429 `REALTIME_MAX_CONNECTIONS` ou `REALTIME_MAX_CONNECTIONS_APP`.
* O status HTTP é verificado antes do streaming, então esses erros (e o 404 para uma aplicação desconhecida) são lançados na primeira iteração.
* O timeout cobre apenas a abertura, até os headers da resposta chegarem. O stream em si não tem timeout: uma conexão meio aberta (um notebook saindo do modo de suspensão) espera até você chamar `close()`.
