Heartbeat

Nota: Le applicazioni a connessione lunga devono implementare il heartbeat, altrimenti la connessione potrebbe essere forzatamente chiusa dai nodi di routing a causa della lunga inattività.

Le funzioni principali del heartbeat sono due:

  1. Il client invia periodicamente dati al server per evitare che la connessione venga chiusa da firewall di alcuni nodi a causa della lunga inattività.

  2. Il server può utilizzare il heartbeat per determinare se il client è online; se il client non invia alcun dato entro un tempo prestabilito, si presume che il client sia offline. In questo modo è possibile rilevare eventi in cui il client va offline a causa di situazioni estreme (interruzione di corrente, perdita di rete, ecc.).

Intervallo di heartbeat consigliato:

Si consiglia che il client invii heartbeat con un intervallo inferiore a 60 secondi, ad esempio 55 secondi.

Il formato dei dati del heartbeat non ha requisiti specifici, purché il server riesca a riconoscerli.

Esempio di heartbeat

<?php
use Workerman\Worker;
use Workerman\Timer;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';

// Intervallo di heartbeat di 55 secondi
define('HEARTBEAT_TIME', 55);

$worker = new Worker('text://0.0.0.0:1234');

$worker->onMessage = function(TcpConnection $connection, $msg) {
    // Imposta temporaneamente un attributo lastMessageTime su connection per registrare l'ora dell'ultimo messaggio ricevuto
    $connection->lastMessageTime = time();
    // Altra logica di business...
};

// Dopo l'avvio del processo, imposta un timer che viene eseguito ogni 10 secondi
$worker->onWorkerStart = function($worker) {
    Timer::add(10, function()use($worker){
        $time_now = time();
        foreach($worker->connections as $connection) {
            // È possibile che questa connection non abbia ancora ricevuto messaggi, quindi lastMessageTime viene impostato all'ora attuale
            if (empty($connection->lastMessageTime)) {
                $connection->lastMessageTime = $time_now;
                continue;
            }
            // Se l'intervallo dall'ultimo comunicato è maggiore dell'intervallo di heartbeat, si presume che il client sia offline e si chiude la connessione
            if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {
                $connection->close();
            }
        }
    });
};

Worker::runAll();

La configurazione sopra stabilisce che se il client non invia dati al server per oltre 55 secondi, il server presume che il client sia offline, chiude la connessione e attiva onClose.

Riconnessione (Importante)

Indipendentemente dal fatto che sia il client a inviare il heartbeat o il server, la connessione può essere interrotta. Ad esempio, il JavaScript del browser può essere messo in pausa quando il browser è minimizzato, se si passa a un'altra scheda, quando il computer entra in modalità di sospensione, sul mobile durante un cambio di rete, segnale debole, schermo del telefono spento, applicazione mobile in background, guasto del router, disconnessione volontaria dell'operazione, ecc. Soprattutto in ambienti di rete esterni complessi, molti nodi di routing possono eliminare connessioni inattive da più di un minuto, il che spiega perché si raccomanda un intervallo di heartbeat inferiore a un minuto.

Le connessioni in ambienti esterni possono essere facilmente interrotte, quindi la riconnessione è una funzione necessaria per le applicazioni a connessione lunga (la riconnessione può essere eseguita solo dal client, il server non può implementarla). Ad esempio, nel WebSocket del browser, è necessario ascoltare l'evento onclose; quando si verifica onclose, si deve stabilire una nuova connessione (per evitare crash, la connessione deve essere stabilita in modo ritardato). Ancora più rigorosamente, il server dovrebbe anche inviare periodicamente dati di heartbeat, e il client deve monitorare regolarmente se i dati di heartbeat del server hanno superato il timeout; se non si ricevono dati di heartbeat dal server entro il tempo prestabilito, si dovrebbe ritenere che la connessione sia interrotta, e si deve eseguire close per chiudere la connessione e stabilire una nuova connessione.