> ## 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.

# Realtime

> Ricevi in streaming i log, lo stato e gli eventi di sistema di un'applicazione con client.apps.realtime(), un iteratore (iteratore asincrono con AsyncSquareCloud) che unisce i frame di stato e si riconnette da solo.

`client.apps.realtime(app_id)` apre un flusso in tempo reale dei log, dello stato e degli eventi di sistema di un'app. Con `SquareCloud` è un **iteratore** da consumare con `for`; con `AsyncSquareCloud` è un **iteratore asincrono** da consumare con `async for`. Usalo in un blocco `with` / `async with`, così uscire dal blocco chiude la connessione.

<Tabs>
  <Tab title="Sincrono">
    ```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="Asincrono">
    ```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>

Con `AsyncSquareCloud`, `apps.realtime(app_id)` restituisce direttamente un `AsyncRealtime`: **non** usare `await`. Un thread lettore in background passa gli eventi al tuo event loop, quindi nessun thread dell'executor resta occupato mentre attendi.

## Eventi

Ogni evento è un dict con `event`, `data` (il testo grezzo del frame) e `id` (`None` quando il frame non ne ha).

| `event`   | Campi aggiuntivi | Descrizione                                                                                                                                                                       |
| --------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `logs`    | `stream`, `line` | Una riga di log. Il primo carattere di `data` indica lo stream (`\u0001` stdout, `\u0002` stderr); l'SDK lo rimuove ottenendo `line` e imposta `stream` a `"stdout"` o `"stderr"` |
| `status`  | `status`         | Metriche del container in tempo reale. Il primo frame è completo e i successivi contengono solo ciò che è cambiato: l'SDK li unisce, quindi `status` è sempre lo stato completo   |
| `system`  |                  | Eventi di connessione come `REALTIME_CONNECTING \| <id>`, `REALTIME_TIMEOUT` o `REALTIME_DISCONNECTED`                                                                            |
| `error`   |                  | Un codice di errore come `CONTAINER_NOT_FOUND`                                                                                                                                    |
| `message` |                  | Un frame senza nome di `event`                                                                                                                                                    |

### L'oggetto `status`

| Campo      | Descrizione                                                       |
| ---------- | ----------------------------------------------------------------- |
| `cpu`      | Utilizzo della CPU (%)                                            |
| `cpuLimit` | Numero di core CPU allocati                                       |
| `ram`      | `[usedMB, limitMB]`                                               |
| `status`   | Stato del container, ad es. `running`                             |
| `netIO`    | Totali di rete `{ i, o }`, con `new` per l'intervallo più recente |
| `bIO`      | Totali del disco `{ i, o }`                                       |
| `uptime`   | ms Unix dell'avvio del container                                  |

## Terminare il flusso

Il ciclo termina da solo quando:

* il server chiude la connessione in modo pulito (ogni connessione dura fino a **10 minuti**);
* il server invia `REALTIME_DISCONNECTED`;
* esci dal ciclo con `break` (poi esci dal blocco `with`, che chiude la connessione);
* chiami `stream.close()`, da qualsiasi thread, anche mentre il ciclo attende dati o una riconnessione (il ciclo semplicemente termina, non solleva eccezioni).

`close()` è sincrono sia su `Realtime` sia su `AsyncRealtime`. Per continuare a osservare oltre i 10 minuti, apri un nuovo flusso quando il ciclo termina.

```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"])
```

## Riconnessione

Una connessione interrotta, o il server che delega la riconnessione al client (`REALTIME_RECONNECT`), riapre il flusso da sola:

* fino a **3 volte di fila**; qualsiasi evento `logs` o `status` azzera il conteggio;
* ogni riapertura avviene almeno **5,5 s** dopo l'apertura precedente, per restare sotto il ritmo dell'API di un'apertura ogni 5 secondi per app.

Oltre 3 riconnessioni fallite, il ciclo solleva un `SquareCloudAPIError` con `NETWORK_ERROR`. Ogni apertura è un `GET`, quindi anche un errore di rete durante l'apertura viene [ripetuto](/it/sdks/py/errors#retry) fino a `max_retries` volte; un'apertura che continua a fallire solleva un'eccezione.

## Limiti ed errori

* **5** connessioni simultanee per account e **30** per app, considerando tutti gli utenti. Superarle produce 429 `REALTIME_MAX_CONNECTIONS` o `REALTIME_MAX_CONNECTIONS_APP`.
* Lo status HTTP viene controllato prima dello streaming, quindi questi errori (e il 404 per un'app sconosciuta) vengono sollevati alla prima iterazione.
* Il timeout copre solo l'apertura, fino all'arrivo degli header della risposta. Il flusso in sé non ha timeout: una connessione semiaperta (un portatile che si riattiva dalla sospensione) resta in attesa finché non chiami `close()`.
