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

# Temps réel

> Diffusez en direct les logs, le statut et les événements système d'une application avec client.apps.realtime(), un itérateur (itérateur asynchrone avec AsyncSquareCloud) qui fusionne les trames de statut et se reconnecte tout seul.

`client.apps.realtime(app_id)` ouvre un flux en direct des logs, du statut et des événements système d'une application. Avec `SquareCloud`, c'est un **itérateur** consommé avec `for` ; avec `AsyncSquareCloud`, c'est un **itérateur asynchrone** consommé avec `async for`. Utilisez-le dans un bloc `with` / `async with` afin que la sortie du bloc ferme la connexion.

<Tabs>
  <Tab title="Synchrone">
    ```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="Asynchrone">
    ```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>

Avec `AsyncSquareCloud`, `apps.realtime(app_id)` renvoie directement un `AsyncRealtime` : ne l'utilisez **pas** avec `await`. Un thread de lecture en arrière-plan transmet les événements à votre boucle d'événements, de sorte qu'aucun thread d'exécution n'est occupé pendant l'attente.

## Événements

Chaque événement est un dict avec `event`, `data` (le texte brut de la trame) et `id` (`None` lorsque la trame n'en a pas).

| `event`   | Champs supplémentaires | Description                                                                                                                                                                                |
| --------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `logs`    | `stream`, `line`       | Une ligne de log. Le premier caractère de `data` indique le flux (`\u0001` stdout, `\u0002` stderr) ; le SDK le retire pour produire `line` et définit `stream` à `"stdout"` ou `"stderr"` |
| `status`  | `status`               | Métriques du conteneur en direct. La première trame est complète et les suivantes ne portent que ce qui a changé : le SDK les fusionne, de sorte que `status` est toujours l'état complet  |
| `system`  |                        | Événements de connexion tels que `REALTIME_CONNECTING \| <id>`, `REALTIME_TIMEOUT` ou `REALTIME_DISCONNECTED`                                                                              |
| `error`   |                        | Un code d'erreur tel que `CONTAINER_NOT_FOUND`                                                                                                                                             |
| `message` |                        | Une trame sans nom d'`event`                                                                                                                                                               |

### L'objet `status`

| Champ      | Description                                                     |
| ---------- | --------------------------------------------------------------- |
| `cpu`      | Utilisation du CPU (%)                                          |
| `cpuLimit` | Nombre de cœurs CPU alloués                                     |
| `ram`      | `[usedMB, limitMB]`                                             |
| `status`   | État du conteneur, par ex. `running`                            |
| `netIO`    | Totaux réseau `{ i, o }`, avec `new` pour le dernier intervalle |
| `bIO`      | Totaux disque `{ i, o }`                                        |
| `uptime`   | Ms Unix du démarrage du conteneur                               |

## Fin du flux

La boucle se termine d'elle-même lorsque :

* le serveur ferme proprement la connexion (chaque connexion dure jusqu'à **10 minutes**) ;
* le serveur envoie `REALTIME_DISCONNECTED` ;
* vous sortez de la boucle avec `break` (puis quittez le bloc `with`, ce qui ferme la connexion) ;
* vous appelez `stream.close()`, depuis n'importe quel thread, même pendant que la boucle attend des données ou une reconnexion (la boucle se termine simplement, elle ne lève pas d'erreur).

`close()` est synchrone sur `Realtime` comme sur `AsyncRealtime`. Pour continuer à observer au-delà de 10 minutes, ouvrez un nouveau flux lorsque la boucle se termine.

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

## Reconnexion

Une connexion interrompue, ou le serveur qui confie la reconnexion au client (`REALTIME_RECONNECT`), rouvre le flux automatiquement :

* jusqu'à **3 fois d'affilée** ; tout événement `logs` ou `status` remet le compteur à zéro ;
* chaque réouverture au moins **5,5 s** après l'ouverture précédente, pour rester sous le rythme de l'API d'une ouverture toutes les 5 secondes par application.

Au-delà de 3 reconnexions échouées, la boucle lève une `SquareCloudAPIError` avec `NETWORK_ERROR`. Chaque ouverture est un `GET` : une erreur réseau pendant l'ouverture fait donc aussi l'objet de [nouvelles tentatives](/fr/sdks/py/errors#nouvelles-tentatives), jusqu'à `max_retries` fois ; une ouverture qui échoue encore lève une erreur.

## Limites et erreurs

* **5** connexions simultanées par compte et **30** par application, tous utilisateurs confondus. Les dépasser donne 429 `REALTIME_MAX_CONNECTIONS` ou `REALTIME_MAX_CONNECTIONS_APP`.
* Le statut HTTP est vérifié avant la diffusion, de sorte que ces erreurs (et 404 pour une application inconnue) sont levées à la première itération.
* Le timeout ne couvre que l'ouverture, jusqu'à l'arrivée des en-têtes de réponse. Le flux lui-même n'a pas de timeout : une connexion à moitié ouverte (un ordinateur portable qui sort de veille) attend jusqu'à ce que vous appeliez `close()`.
