Cómo realizar cargas (conceptos avanzados)

Introducción

Poder cargar activos de manera fiable es esencial en las integraciones de C2C. Esta guía ofrece técnicas avanzadas y prácticas recomendadas para crear un sistema de carga sólido, resistente y eficiente que funcione bien incluso en entornos complejos.

Requisitos previos

Si aún no lo ha hecho, revise la guía Implementar C2C: Configuración antes de continuar. Necesitará el access_token que se obtiene durante el proceso de autenticación y autorización. Seguiremos usando el mismo activo de prueba de la guía de conceptos básicos sobre las cargas.

Parámetros avanzados de activos

Al crear activos en Frame.io, puede usar varios parámetros avanzados para personalizar el comportamiento de la carga. El parámetro offset es especialmente importante para que la integración funcione correctamente.

Offset: Gestión de dispositivos en pausa

Es esencial proporcionar un valor preciso para offset. Este parámetro especifica cuándo se creó un elemento multimedia y garantiza que su dispositivo no cargue contenido que no deba compartirse. Cuando un dispositivo está en pausa en Frame.io, el usuario está indicando que los medios creados durante la pausa no deben cargarse. Para obtener más detalles, consulte nuestra guía sobre la funcionalidad de pausa.

Ventajas adicionales del parámetro offset

El parámetro offset proporciona otra ventaja significativa para organizar medios en Frame.io. Al cargar contenido capturado en una fecha anterior, como cuando un usuario selecciona una foto realizada la semana anterior durante la reproducción, el parámetro offset garantiza que estos medios aparezcan en carpetas correspondientes a su fecha de captura original en lugar de la fecha de carga actual. Esta organización cronológica mantiene una línea de tiempo lógica en la estructura del proyecto de Frame.io. Sin el parámetro offset, los medios históricos se agruparían incorrectamente con el contenido de hoy, lo que podría confundir a los editores y otros colaboradores. Puede que desee permitir que los usuarios tengan opciones en lo que respecta a esta cuestión a través de su interfaz. Si los usuarios prefieren organizar todas las cargas por la fecha actual independientemente de cuándo se capturaron los medios, puede simplemente omitir el parámetro offset, ya que su valor predeterminado es 0 cuando no se especifica.

Debido al diseño de nuestra API, su dispositivo no tiene que hacer un seguimiento del estado de pausa. En su lugar, al cargar un archivo, indica hace cuántos segundos se creó el archivo. Nuestro servidor compara ese valor con las ventanas de pausa y rechaza la carga si se creó durante una pausa.

Para demostrar esta funcionalidad, ponga en pausa su dispositivo desde el menú de tres puntos en la pestaña Conexiones de C2C.

Ahora intente cargar un activo:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "name": "C2C_TEST_CLIP.mp4",
> "filetype": "video/mp4",
> "filesize": 21136250,
> "offset": 0
> }
>__JSON__
>} | python -m json.tool
Especificación del punto final de la API

La documentación para /v2/devices/assets está disponible aquí.

Recibirá este error:

1{
2 "code": 409,
3 "errors": [
4 {
5 "code": 409,
6 "detail": "The channel you're uploading from is currently paused.",
7 "status": 409,
8 "title": "Channel Paused"
9 }
10 ],
11 "message": "Channel Paused"
12}

Si reanuda el dispositivo y vuelve a intentar realizar la misma solicitud, se creará el activo.

Sin embargo, si el activo se creó durante la ventana de pausa, debe establecer el parámetro offset para reflejar cuándo se creó realmente:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "name": "C2C_TEST_CLIP.mp4",
> "filetype": "video/mp4",
> "filesize": 21136250,
> "offset": 60
> }
>__JSON__
>} | python -m json.tool

Esto le dice a Frame.io que el activo se creó hace 60 segundos (durante la pausa), lo que activa correctamente el error Channel Paused. Definir valores precisos para offset es esencial para evitar que se cargue contenido confidencial en contra de los deseos del usuario, lo que incluye propiedad intelectual protegida, metraje sensible u otro material restringido.

Offset y los reintentos

Al volver a intentar realizar una llamada de creación de activo que ha fallado, recuerde actualizar el valor de offset. Durante periodos de reintento prolongados, un valor estático para offset podría salirse de la ventana de pausa relevante, lo que podría permitir cargas que deberían bloquearse.

Cargar en un canal concreto

Si su dispositivo tiene varios canales, puede especificar cuál desea usar:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "name": "C2C_TEST_CLIP.mp4",
> "filetype": "video/mp4",
> "filesize": 21136250,
> "offset": -10,
> "channel": 2
> }
>__JSON__
>} | python -m json.tool

Si no se especifica ninguno, el canal predeterminado es 0. Para la mayoría de las integraciones, no será necesario cambiar este valor.

Solicitar un recuento de fragmentos personalizado

De forma predeterminada, el backend de Frame.io divide los archivos en fragmentos de aproximadamente 25 MB. Para redes muy congestionadas, podría preferir fragmentos más pequeños. Puede solicitar un número específico de fragmentos con el parámetro parts:

${
>curl -X POST https://api.frame.io/v2/devices/assets \
> --header 'Authorization: Bearer [access_token]' \
> --header 'Content-Type: application/json' \
> --header 'x-client-version: 2.0.0' \
> --data-binary @- <<'__JSON__'
> {
> "name": "C2C_TEST_CLIP.mp4",
> "filetype": "video/mp4",
> "filesize": 21136250,
> "offset": 0,
> "parts": 4
> }
>__JSON__
>} | python -m json.tool

La respuesta incluirá cuatro URL de carga:

1{
2 ...
3 "upload_urls": [
4 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-01-path]",
5 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-02-path]",
6 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-03-path]",
7 "https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-04-path]"
8 ],
9 ...
10}

El tamaño de los fragmentos será:

Python
1math.ceiling(float(21136250) / float(4))
2# 5284063 bytes

El último fragmento ocupará 5 284 061 bytes (calculado como 21136250 - 5284063 * 3). Al solicitar recuentos de fragmentos personalizados, tenga en cuenta las limitaciones de carga multiparte de AWS S3:

  • Cada parte debe ocupar al menos 5 MiB (5 242 880 bytes), excepto la parte final
  • No puede haber más de 10 000 partes

Si su solicitud infringe estas restricciones, recibirá un mensaje 500: INTERNAL SERVER ERROR:

{
"code": 500,
"errors": [
{
"code": 500,
"detail": "There was a problem with your request",
"status": 500,
"title": "Something went wrong"
}
],
"message": "Something went wrong"
}

Asegúrese siempre de que su recuento de partes personalizado cumple los requisitos de S3.

Realizar la carga de manera eficiente

Los dispositivos de C2C suelen operar en entornos de red complejos, por lo que la eficiencia es crucial. A continuación, se muestran algunas estrategias para maximizar el rendimiento.

Reutilizar/Agrupar las conexiones TCP

Para establecer conexiones cifradas se necesita una sobrecarga de negociación significativa. Para que el funcionamiento sea eficiente, reutilice las conexiones TCP al realizar varias solicitudes. La mayoría de las bibliotecas HTTP proporcionan una abstracción de tipo Client o Session que mantiene conexiones persistentes.

El proceso de negociación para una nueva conexión HTTPS incluye protocolos de enlace criptográficos y la validación de los certificados. Al reutilizar conexiones, solo realiza esta sobrecarga una vez en lugar de hacerlo para cada solicitud.

Referencia de protocolo de enlace TCP

Para obtener detalles técnicos sobre los procesos de protocolo de enlace TLS, consulte la explicación de Cloudflare.

Para demostrar la reutilización de conexiones con curl, primero cree un nuevo activo en Frame.io como se describe en la guía de conceptos básicos sobre las cargas.

A continuación, divida el archivo en fragmentos independientes para realizar pruebas:

$head -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 > "C2C_TEST_CLIP-Chunk01"
$tail -c 10568125 ~/Downloads/C2C_TEST_CLIP.mp4 > "C2C_TEST_CLIP-Chunk02"

Ahora cargue ambos fragmentos a través de una sola conexión TCP mediante el parámetro --next de curl:

$curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-1-path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk01 \
>--next -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-2-path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk02

Compare esto con conexiones independientes:

$curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-1-path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk01 \
>&& curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-2-path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk02
Reutilizar URL de fragmentos

Puede cargar varias veces en la misma URL de fragmento, así que no dude en reutilizar URL para diferentes ejemplos.

En las pruebas, reutilizar conexiones suele mejorar el rendimiento en un 15-20 % para las cargas secuenciales.

Cargas paralelas

Para mejorar aún más el rendimiento, cargue varios fragmentos al mismo tiempo:

$curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-1-path] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk01 \
>& \
>curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[part-2-path]\
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk02 \
>&

Con suficiente ancho de banda, las cargas paralelas se completan aproximadamente en el tiempo de la carga individual más lenta.

Para disfrutar de un paralelismo óptimo, una buena regla general es realizar dos cargas simultáneas por núcleo de CPU. Superar esta proporción puede provocar que se contengan recursos y el rendimiento disminuya.

Velocidades de carga paralela

Las condiciones de red afectan significativamente al rendimiento de la carga paralela. En algunos entornos, las cargas secuenciales pueden superar el rendimiento de las paralelas. Las implementaciones avanzadas pueden monitorizar el rendimiento y ajustar dinámicamente la concurrencia. Establezca siempre perfiles de rendimiento en su entorno de producción operativo en lugar de confiar en los tiempos de ejemplo.

Combinar ambos enfoques

Para maximizar la eficiencia, combine la agrupación de conexiones con las cargas paralelas. Cree varios procesos de modo que cada uno use la agrupación de conexiones para su propia secuencia de cargas:

$curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[asset01-chunk01] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk01 \
>--next -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[asset01-chunk02] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk02 \
>& \
>curl -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[asset02-chunk01] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk01 \
>--next -X PUT https://frameio-uploads-production.s3-accelerate.amazonaws.com/parts/[asset02-chunk02] \
> --include \
> --header 'content-type: video/mp4' \
> --header 'x-amz-acl: private' \
> --data-binary @C2C_TEST_CLIP-Chunk02 \
>&
Funciones de la biblioteca HTTP

La mayoría de las bibliotecas HTTP proporcionan abstracciones para la agrupación de conexiones y las solicitudes paralelas. Experimente con las opciones de su biblioteca para determinar la configuración óptima para su entorno.

Realizar un seguimiento del progreso de carga

Su integración debe proporcionar indicaciones básicas de progreso a los usuarios. La granularidad en el nivel de fragmento es aceptable: para una carga de tres fragmentos, el progreso podría incrementar de 0 % → 33 % → 66 % → 100 % a medida que se complete cada fragmento.

Los informes de progreso más detallados dependen de las capacidades de su biblioteca HTTP. Póngase en contacto con nuestro equipo si necesita orientación para implementar un seguimiento del progreso más detallado.

Realizar cargas fiables

Para gestionar adecuadamente los errores, revise nuestra guía sobre los errores. En las siguientes secciones se asume que ha implementado las estrategias de gestión de errores que se describen en ese documento.

Crear un cargador con calidad de producción requiere consideraciones adicionales más allá de la gestión de errores de solicitudes individuales.

Crear una cola de carga

En escenarios reales, es posible que su dispositivo genere medios más rápido de lo que puede cargarlos, o que experimente interrupciones de conexión prolongadas. Implementar un sistema de colas permite separar la creación de medios de la administración de las cargas.

Plantéese una arquitectura con dos colas:

  1. Una cola de medios para registrar archivos locales con Frame.io
  2. Una cola de fragmentos para cargar fragmentos de archivos individuales

A continuación, se muestra una implementación simplificada:

Python
1# Where we are going to queue new files.
2FILE_QUEUE = Queue()
3
4# Where we are going to queue new chunks.
5CHUNK_QUEUE = Queue()
6
7# The http session that will handle TCP
8# connection pooling for us.
9HTTP_SESSION = http.Session()
10
11def take_picture():
12 """Snaps a picture for the user."""
13
14 image = MY_DEVICE.capture()
15 file_path = MY_DEVICE.write_image(image)
16 FILE_QUEUE.add(file_path)
17
18def task_register_assets():
19 """
20 Pulls snapped pictures from the FILE_QUEUE, registers
21 with Frame.io, and adds the chunks to the CHUNK_QUEUE.
22 """
23 while True:
24 # Get the latest file added to the queue and register
25 # a C2C Asset for it.
26 new_file = FILE_QUEUE.get()
27 asset = c2c.crete_asset_for_file(HTTP_SESSION, new_file)
28
29 # Calculate the size for each chunk
30 chunk_size = c2c.calculate_chunk_size(asset, new_file)
31
32 # Create a message for each chunk with it's parameters
33 # and add it to the
34 # queue.
35 chunk_start = 0
36 for chunk_url in asset.upload_urls:
37 message = {
38 "file_path": new_file,
39 "chunk_url": chunk_url,
40 "chunk_start": chunk_start,
41 "chunk_size": chunk_size,
42 }
43
44 # Put the message in the queue and
45 CHUNK_QUEUE.put(message)
46 chunk_start += chunk_size
47
48def task_upload_chunk():
49 """Takes a chunks and uploads them."""
50
51 while True:
52 info = CHUNK_QUEUE.get()
53 c2c.upload_chunk(HTTP_SESSION, info)
54
55def launch_upload_tasks():
56 """Lauches our Frame.io upload tasks."""
57 # Create a list to hold all of our tasks.
58 tasks = list()
59
60 # Create one task for registering assets.
61 asset_task = run_task_in_thread(task_register_assets)
62 tasks.append(asset_task)
63
64 # Create 2 tasks per CPU core for uploading chunks.
65 for _ in range(0, GET_CPU_COUNT() * 2):
66 chunk_task = run_task_in_thread(task_upload_chunk)
67 tasks.append(chunk_task)
68
69 # Run these tasks until shutdown
70 run_forever(tasks)
Gestión de errores

En el ejemplo anterior, asumimos que las funciones invocadas para las llamadas a C2C están gestionando errores como se analiza en la guía sobre los errores.

Colas persistentes entre ciclos de encendido

El enfoque de cola en memoria funciona bien mientras el dispositivo permanece encendido, pero ¿qué sucede si se pierde la alimentación antes de que se completen las cargas? Para crear una integración verdaderamente resistente, debemos garantizar que el dispositivo pueda continuar desde donde se quedó tras un reinicio.

Esto requiere persistir el estado de la cola en el almacenamiento entre ciclos de encendido. Una base de datos integrada como SQLite proporciona unos cimientos excelentes para esta funcionalidad.

Su implementación de cola persistente debe admitir estas operaciones clave:

  • Añadir los nuevos archivos creados a la cola de carga
  • Monitorizar cuándo se crean correctamente los activos en Frame.io
  • Registrar cuándo falla la creación de activos debido a errores
  • Almacenar información de fragmentos de archivos para tareas de carga
  • Recuperar el próximo fragmento que se va a cargar
  • Marcar fragmentos como cargados correctamente
  • Registrar fallos en la carga de fragmentos
  • Proporcionar al usuario información sobre el estado de los archivos

A continuación, se muestra cómo podríamos adaptar nuestro ejemplo anterior para usar un sistema de almacenamiento persistente:

Python
1# Our persistence layer for queuing uploads, potentially using SQLite
2# or another embedded database
3C2C_UPLOAD_STORE = NewC2CUploadStore()
4
5# HTTP session for connection pooling
6HTTP_SESSION = http.Session()
7
8def take_picture():
9 """Captures an image and adds it to the upload queue."""
10 image = MY_DEVICE.capture()
11 file_path = MY_DEVICE.write_image(image)
12
13 # Register the file with our persistent store
14 C2C_UPLOAD_STORE.add_file(file_path)
15
16def task_register_assets():
17 """
18 Processes files from persistent storage and registers
19 them with Frame.io for upload.
20 """
21 while True:
22 # Get the next available file from our store
23 file_record = C2C_UPLOAD_STORE.get_file()
24
25 try:
26 # Register the asset with Frame.io
27 asset = c2c.create_asset_for_file(HTTP_SESSION, file_record)
28 chunk_size = c2c.calculate_chunk_size(asset, file_record)
29
30 # Create entries for each chunk in our persistent store
31 chunk_start = 0
32 for chunk_url in asset.upload_urls:
33 message = {
34 "file_path": file_record,
35 "chunk_url": chunk_url,
36 "chunk_start": chunk_start,
37 "chunk_size": chunk_size,
38 }
39
40 C2C_UPLOAD_STORE.new_chunk(message)
41 chunk_start += chunk_size
42
43 except BaseException as error:
44 # Record the error in our persistent store
45 C2C_UPLOAD_STORE.file_asset_create_error(file_record, error)
46 else:
47 # Mark the asset as successfully created
48 C2C_UPLOAD_STORE.file_asset_created(file_record)
49
50def task_upload_chunk():
51 """Uploads individual file chunks from the persistent queue."""
52 while True:
53 # Get the next chunk, marking it as "in progress" to prevent
54 # other tasks from processing it simultaneously
55 chunk_record = C2C_UPLOAD_STORE.get_chunk()
56
57 try:
58 c2c.upload_chunk(HTTP_SESSION, chunk_record)
59 except BaseException as error:
60 # Record the error for potential retry
61 C2C_UPLOAD_STORE.chunk_error(chunk_record, error)
62 else:
63 # Mark successful completion
64 C2C_UPLOAD_STORE.chunk_success(chunk_record)
65
66def launch_upload_tasks():
67 """Launches Frame.io upload processing tasks."""
68 tasks = []
69
70 # Asset registration task
71 asset_task = run_task_in_thread(task_register_assets)
72 tasks.append(asset_task)
73
74 # Multiple parallel chunk upload tasks
75 worker_count = GET_CPU_COUNT() * 2
76 for _ in range(worker_count):
77 chunk_task = run_task_in_thread(task_upload_chunk)
78 tasks.append(chunk_task)
79
80 # Run indefinitely
81 run_forever(tasks)

Con este enfoque de almacenamiento persistente, su integración se vuelve resistente a las interrupciones de alimentación. Cuando el dispositivo se reinicia, simplemente sigue procesando desde su último estado guardado. Esta arquitectura también proporciona la base para implementar funciones más avanzadas, como el seguimiento de errores y la detección de cargas detenidas.

Realizar un seguimiento de los errores de carga

Un sistema de carga sólido debe realizar un seguimiento cuidadoso de los errores. Tras volver a intentar una operación usando las estrategias de la guía sobre los errores, registre estos fallos en su almacén de persistencia. Esto permite a su sistema:

  1. Dar menor prioridad a las cargas problemáticas para evitar que bloqueen toda la cola
  2. Proporcionar a los usuarios información precisa sobre el estado
  3. Admitir intervenciones administrativas para problemas persistentes

Cuando se produce un error grave, marque el elemento para evitar reintentos innecesarios.

Administrar cargas detenidas

Implemente medidas de protección contra cargas detenidas indefinidamente. Establezca una duración máxima (por ejemplo, 30 minutos) después de la cual una tarea de carga de fragmentos debe terminarse y reiniciarse. Esto evita escenarios donde todos los trabajadores de carga se bloquean debido a operaciones que no responden.

Recuperarse de fallos silenciosos

Los bloqueos del sistema, la pérdida de alimentación o la finalización de procesos pueden impedir que se informe adecuadamente de los errores. Al recuperar elementos de su cola, registre la hora de comprobación. Si un elemento permanece en el estado “in progress” más de un umbral razonable (por ejemplo, 30 minutos) sin que se informe de éxito o fallo, devuélvalo automáticamente al grupo disponible para que lo procese otro trabajador secundario.

Mitigar las cargas envenenadas

Un elemento de cola “envenenado” falla constantemente debido a problemas inherentes con los datos o el entorno. Si estos elementos se ponen continuamente en una cola, pueden acabar bloqueando efectivamente todo su sistema de carga. Considere estas estrategias para abordar tales casos:

  • Tras varios fallos, dar menor prioridad al elemento para que el contenido más nuevo pueda proceder
  • Realizar un seguimiento tanto de los errores explícitos como del número de intentos de procesar
  • Seguir las prácticas recomendadas de conexión y autorización para distinguir entre problemas del entorno transitorios y problemas intrínsecos del archivo
  • Implementar límites de reintento escalonados (por ejemplo, volver a intentar operaciones individuales 10 veces por cada uno de tres intentos del trabajo, lo que equivale a 30 intentos totales)
  • Proporcionar una interfaz de usuario para restablecer manualmente las cargas problemáticas cuando se resuelvan los problemas del entorno

Las cargas envenenadas pueden ser el resultado de:

  • Datos de archivo dañados que provocan errores de E/S
  • Fallos irrecuperables de procesos que impiden crear informes de errores
  • Errores normalmente reintentables activados por condiciones subyacentes permanentes

Volver a intentarlo después de un reinicio del sistema

Antes de abandonar permanentemente las cargas problemáticas, márquelas para un último reintento después del siguiente reinicio del sistema. Esto aborda los casos en los que las cargas fallan debido a problemas temporales del estado del sistema con la memoria, los controladores o la asignación de recursos. Si una carga sigue fallando después de un reinicio limpio, puede marcarla con más confianza como permanentemente problemática.

Limpiar la cola

Recuerde quitar los archivos no disponibles de su cola. Cuando se quiten medios físicamente o se eliminen archivos, purgue las entradas correspondientes de su cola de carga para evitar errores innecesarios.

Es importante que limpie su cola de carga al conectarse a un nuevo proyecto. Los medios en cola de un proyecto nunca deben aparecer en otro. Cuando un usuario empareja el dispositivo con un proyecto diferente, verifique si el proyecto ha cambiado y, de ser así, limpie completamente la cola existente.

Próximos pasos

Le recomendamos que se ponga en contacto con nuestro equipo si tiene alguna pregunta y a continuar con la guía avanzada sobre las cargas. Esperamos poder ayudarle con el progreso de su integración.