Llamadas de aviso por interrupciones en el servicio

La plataforma Vonage Video supervisa continuamente todos los servicios en ejecución. Cuando un fallo interno afecta a un servicio —como un fallo del servidor multimedia, un fallo del archivador, la caída de un nodo de emisión, un problema con la pasarela SIP o un fallo del motor de subtítulos—, el sistema de supervisión de la plataforma detecta el fallo, actualiza el estado del servicio y envía inmediatamente una notificación de devolución de llamada a tu terminal registrado.

Esta guía explica qué funciones de devolución de llamada emite cada servicio en caso de interrupción, cómo son las cargas útiles y cómo recuperar cada servicio mediante programación.

Visión general

Las interrupciones del servicio pueden afectar a cualquiera de los siguientes servicios de Vonage Video:

Servicio ¿Qué se ve afectado? Mecanismo principal de devolución de llamada
Sesiones El Media Router se bloquea; se interrumpen las conexiones y las transmisiones de los participantes Webhook de supervisión de sesiones del lado del servidor + eventos del Client SDK
Archivos (Grabaciones) El proceso «Archiver» se bloquea; la grabación finaliza de forma anómala Webhook de estado del archivo ("status": "failed")
Emisiones Fallo del nodo de retransmisión; se interrumpe la transmisión HLS/RTMP Webhook de estado de la emisión ("status": "failed")
Llamadas SIP La pasarela SIP falla; se interrumpe la conexión de la llamada Webhook de supervisión de sesiones callDestroyed
Leyendas Fallo del motor de subtítulos; se interrumpe la transcripción en directo Webhook de estado de los subtítulos ("status": "failed")

En todos los casos, el reason El campo en la carga útil de la llamada de retorno es normalmente ajustado a "forceDisconnected". Pueden aparecer otros valores de motivo en función de la naturaleza del fallo, por lo que tu código de recuperación debería tratar cualquier interrupción inesperada (que no esté causada por tus propias llamadas a la API) como una posible interrupción del servicio.

Nota: La plataforma también envía avisos previos a una interrupción para las rotaciones de servidores (reason: "serverRotation") a través de la sessionNotification evento. Véase Rotación de servidores y migración de sesiones para obtener más información sobre ese caso concreto.

Requisitos previos

Para recibir notificaciones de interrupciones del lado del servidor, debes registrar un URL de devolución de llamada para la supervisión de sesiones para tu proyecto. Consulta Control de la sesión para obtener instrucciones de configuración.

Para las notificaciones de estado de archivos, emisiones y subtítulos, configura la URL de notificación de estado correspondiente en tu Panel de control del proyecto de la Video API de Vonage.


Interrupción de la sesión

Cuando el Media Router que aloja una sesión se bloquea, la sesión se interrumpe y la plataforma envía un sessionDestroyed evento al punto final de supervisión de tu sesión.

Cargas útiles de devolución de llamada

{
  "sessionId": "2_MX4xMzExMjU3MX5-MTQ3MDI1NzY3OTkxOH45QXRr",
  "projectId": "123456",
  "event": "sessionDestroyed",
  "reason": "forceDisconnected",
  "timestamp": 1718000050000
}

Eventos del Client SDK

Paralelamente a los webhooks del lado del servidor, los clientes reciben eventos del ciclo de vida a través del SDK:

session.on('sessionReconnecting', () => {
  // Platform is attempting automatic reconnection via session migration
  showReconnectingBanner();
});

session.on('sessionReconnected', () => {
  // Automatic recovery succeeded — no further action needed
  hideReconnectingBanner();
});

session.on('sessionDisconnected', (event) => {
  // Automatic recovery failed or is not enabled
  if (event.reason === 'networkDisconnected' || event.reason === 'networkTimedout') {
    promptUserToRejoin();
  }
});

publisher.on('streamDestroyed', (event) => {
  if (event.reason === 'networkDisconnected') {
    event.preventDefault(); // Keep the publisher element in the DOM
    retryPublish();
  }
});

Para los SDK nativos, utiliza los métodos delegados equivalentes:

  • iOS: OTSessionDelegate.sessionDidBeginReconnecting(_:) / sessionDidReconnect(_:) / sessionDidDisconnect(_:)
  • Android: Session.SessionListener.onReconnecting() / onReconnected() / onDisconnected()

Recuperación

En sessionDisconnected incendios con reason: "forceDisconnected" (o después de sessionReconnecting tiempo de espera):

  1. Crea una nueva sesión a través de la API REST o del SDK del servidor.
  2. Emitir tokens nuevos para todos los participantes.
  3. Avisa a los clientes de que deben volver a conectarse, ya sea a través de tu propio canal de notificación, mediante una notificación push o con un mensaje dentro de la aplicación.
// Server-side — handle sessionDestroyed with reason "forceDisconnected"
app.post('/callbacks/vonage/session', (req, res) => {
  const { event, reason, sessionId } = req.body;

  if (event === 'sessionDestroyed' && reason === 'forceDisconnected') {
    createNewSessionAndNotifyClients(sessionId);
  }

  res.sendStatus(200);
});

Consejo: Si Migración de sesiones Si está activada, la plataforma puede recuperar la sesión automáticamente. En ese caso sessionReconnected se inician en el cliente y no es necesario volver a conectarse manualmente.


Interrupción del archivo (grabación)

Cuando un proceso de archivado se bloquea en mitad de la grabación, el sistema de supervisión de la plataforma detecta el fallo y marca el archivo como "failed", y envía una notificación de estado a la URL de estado del archivo que hayas registrado.

Carga útil de la llamada de retorno

{
  "id": "b40ef09b-3811-4726-b508-e41a0f96c68f",
  "event": "archive",
  "status": "failed",
  "reason": "Internal server failure",
  "sessionId": "2_MX4xMzExMjU3MX5-MTQ3MDI1NzY3OTkxOH45QXRr",
  "projectId": "123456",
  "name": "My Recording",
  "createdAt": 1718000000000,
  "duration": 0,
  "outputMode": "composed",
  "hasVideo": true,
  "hasAudio": true
}

Campos clave:

Campo El valor de la disrupción
status "failed"
reason "Internal server failure"
duration Quizás 0 si el fallo se produjo antes de que se escribiera el primer segmento

Recuperación

app.post('/callbacks/vonage/archive', (req, res) => {
  const { status, reason, sessionId } = req.body;

  if (status === 'failed' && reason === 'Internal server failure') {
    // Start a new archive for the same session
    opentok.startArchive(sessionId, { name: 'Resumed recording' }, (err, archive) => {
      if (err) console.error('Failed to restart archive:', err);
      else console.log('New archive started:', archive.id);
    });
  }

  res.sendStatus(200);
});

Nota: Verify siempre que la sesión siga teniendo participantes activos antes de reiniciar el archivo. Iniciar un archivo en una sesión vacía provocará un error.


Interrupción de la emisión

Cuando un nodo de retransmisión falla, la transmisión HLS o RTMP se interrumpe y la retransmisión se marca como "failed". Se envía una respuesta de estado a tu URL de estado de difusión.

Carga útil de la llamada de retorno

{
  "id": "1748b707-0a81-464c-9759-c46ad10d3734",
  "sessionId": "2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4",
  "applicationId": 100,
  "createdAt": 1437676551000,
  "updatedAt": 1437676551000,
  "event": "broadcast",
  "group": "status",
  "resolution": "640x480",
  "streamMode" : "auto",
  "streams" : [],
  "broadcastUrls": {
    "hls" : "http://server/fakepath/playlist.m3u8",
    "hlsStatus": "error",
    "rtmp": {
      "foo": {
        "serverUrl": "rtmps://myfooserver:443/myfooapp",
        "streamName": "myfoostream",
        "status": "error"
      },
      "bar": {
        "serverUrl": "rtmp://mybarserver:443/mybarapp",
        "streamName": "mybarstream",
        "status": "error"
      }
    }
  },
  "settings": {
    "hls": {
      "dvr": false,
      "lowLatency": false
    }
  },
  "status": "failed",
  "reason": "Internal server failure"
}

Recuperación

  1. Recibe el "failed" llamada de retorno de estado.
  2. Espera a que los clientes se hayan vuelto a conectar a la sesión (espera a que se detecte connectionCreated eventos o participantes en las sesiones de votación).
  3. Iniciar una nueva retransmisión:
app.post('/callbacks/vonage/broadcast', (req, res) => {
  const { status, reason, sessionId } = req.body;

  if (status === 'failed' && reason === 'Internal server failure') {
    waitForParticipants(sessionId).then(() => {
      opentok.startBroadcast(sessionId, broadcastOptions, (err, broadcast) => {
        if (err) console.error('Failed to restart broadcast:', err);
        else notifyViewersOfNewStreamUrl(broadcast.broadcastUrls);
      });
    });
  }

  res.sendStatus(200);
});

Importante: La URL de HLS cambia con cada nueva emisión. Asegúrate de actualizar con la nueva URL todos los reproductores o sistemas posteriores que utilicen la transmisión.


Interrupción de una llamada SIP

Cuando un fallo en la pasarela SIP provoca la interrupción de un tramo de llamada activo, la conexión SIP se interrumpe y la plataforma envía callDestroyed a tu punto final de supervisión de sesiones con reason_message: "Unexpected Clearing". Los datos de una conexión SIP suelen contener un sip identificador para que puedas distinguirlo de las conexiones de los participantes habituales.

Carga útil de la llamada de retorno

{
  "sessionId": "2_MX4xMzExMjU3MX5-MTQ3MDI1NzY3OTkxOH45QXRr",
  "applicationId": "123456",
  "event": "callDestroyed",
  "reason_code":  "703",
  "reason_message": "Unexpected Clearing",
  "timestamp": 1718000050000,
  "call": {
    "id":  "<conference-id>",
    "connectionId":  "<sip-ot-connection-id>",
    "createdAt":  1470257688143
  }
}

Recuperación

Identificar las conexiones SIP mediante la inspección de connection.data, y luego vuelve a marcar:

app.post('/callbacks/vonage/session', (req, res) => {
  const { event, reason_message, connection, sessionId } = req.body;

  if (event === 'callDestroyed' && reason_message === 'Unexpected Clearing') {
    let connData = {};
    try { connData = JSON.parse(connection.data); } catch (_) {}

    if (connData.sip) {
      // Re-initiate the SIP call
      const sipUri = getSipUriForConnection(connection.id);
      opentok.dial(sessionId, token, sipUri, sipOptions, (err, call) => {
        if (err) console.error('SIP redial failed:', err);
        else console.log('SIP call re-established:', call.id);
      });
    }
  }

  res.sendStatus(200);
});

Interrupción de los subtítulos

Cuando el motor de subtítulos falla, la transcripción en directo se detiene y la sesión de subtítulos se marca como "failed". Se envía una respuesta de estado a la URL de estado de tus subtítulos.

Carga útil de la llamada de retorno

{
  "captionsId": "<captionsId>",
  "projectId": "<applicationId>",
  "sessionId": "<sessionId>",
  "status": "failed",
  "createdAt": 1651253477,
  "updatedAt": 1651253837,
  "duration": 360,
  "languageCode": "en-US",
  "reason": "Internal server failure",
  "provider": "aws-transcribe",
  "event": "sessionStatus"
}

Recuperación

app.post('/callbacks/vonage/captions', (req, res) => {
  const { status, reason, sessionId } = req.body;

  if (status === 'failed' && reason === 'Internal server failure') {
    // Restart captions for the session
    fetch(`https://video.api.vonage.com/v2/project/${PROJECT_ID}/captions`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${jwt}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ sessionId, token: generateToken(sessionId) })
    })
    .then(res => res.json())
    .then(data => console.log('Captions restarted:', data.captionsId))
    .catch(err => console.error('Failed to restart captions:', err));
  }

  res.sendStatus(200);
});

Buenas prácticas

  • Comprueba siempre el reason campo, pero no te fíes exclusivamente de ello. Aunque las interrupciones suelen conllevar "Internal server failure", tu lógica de recuperación debería gestionar cualquier "failed" estado o <something>Destroyed acontecimiento como una posible disrupción de la plataforma.
  • Implementar gestores de recuperación idempotentes. Las funciones de devolución de llamada pueden ejecutarse más de una vez. Utiliza el identificador del recurso (archive.id, captionsId, session.id) para eliminar los duplicados.
  • Utiliza las advertencias previas a la rotación. En sessionNotification evento (con remainingTime: 3600 o 14400) te avisa con antelación de las rotaciones previstas. Úsalo para detener de forma ordenada los archivos, las emisiones y los subtítulos antes de la rotación, evitando así un "forceDisconnected" rescisión.
  • Registrar todos los incidentes de interrupción del servicio con toda su carga útil para el análisis posterior al incidente. El timestamp Este campo es el valor de referencia para calcular la duración del impacto.
  • Para las sesiones, es preferible utilizar la migración de sesiones. Al habilitar la migración de sesiones se reduce drásticamente el alcance de los fallos del Media Router, ya que los clientes se transfieren de forma transparente a un servidor en buen estado. Véase Rotación de servidores y migración de sesiones.
  • Configura alertas en "Internal server failure" funciones de devolución de llamada. Un repunte en Internal server failure La aparición de eventos a lo largo de varias sesiones es un indicio temprano de un incidente más amplio en la plataforma.

Recursos relacionados