Guida pratica: Caricamento (avanzato)

Introduzione

Il caricamento affidabile delle risorse è la funzione principale di ogni integrazione C2C. Questa guida fornisce tecniche avanzate e best practice per creare un sistema di caricamento affidabile, resiliente ed efficiente che funziona bene anche in ambienti complessi.

Prerequisiti

Se non l’hai già fatto, consulta la guida Implementazione C2C: configurazione prima di procedere. Avrai bisogno dell’access_token ottenuto durante il processo di autenticazione e autorizzazione. Useremo la stessa risorsa di test della guida sui caricamenti di base.

Parametri avanzati delle risorse

Quando crei delle risorse in Frame.io, puoi utilizzare diversi parametri avanzati per personalizzare le modalità di caricamento. Il parametro offset è particolarmente importante per un’integrazione corretta.

Offset - Gestione dei dispositivi in pausa

È fondamentale fornire un valore di offset accurato. Questo parametro specifica quando è stato creato un media e garantisce che il dispositivo non carichi contenuti che non dovrebbero essere condivisi. Quando un dispositivo è in pausa in Frame.io, l’utente sta indicando che i media creati durante la pausa non devono essere caricati. Per maggiori dettagli, consulta la nostra guida sulla funzionalità di pausa.

Ulteriori vantaggi del parametro offset

Il parametro offset offre un altro vantaggio significativo per organizzare i media all’interno di Frame.io. Quando carichi dei contenuti acquisiti in una data precedente, ad esempio quando un utente seleziona una foto scattata la settimana precedente durante la riproduzione, il parametro offset fa sì che questo contenuto multimediale appaia nelle cartelle corrispondenti alla data di acquisizione originale, invece che alla data di caricamento corrente. Questa organizzazione cronologica mantiene una timeline logica nella struttura dei progetti Frame.io. Senza il parametro offset, i media storici apparirebbero erroneamente raggruppati con i contenuti odierni, creando potenzialmente confusione per gli editor e altri collaboratori. Potresti voler offrire agli utenti una scelta al riguardo nell’interfaccia. Se gli utenti preferiscono organizzare tutti i caricamenti per data corrente, a prescindere da quando è stato acquisito il contenuto multimediale, puoi semplicemente omettere il parametro offset, dato che ha come impostazione predefinita 0 se non è specificato.

La progettazione delle nostre API elimina la necessità che il dispositivo tenga traccia dello stato di pausa. Quando carichi un file, indichi quanti secondi fa è stato creato il file. Il nostro server confronta questo dato con le finestre di pausa e rifiuta il caricamento se è stato creato durante una pausa.

Per dimostrare questa funzionalità, metti in pausa il dispositivo dal menu con i tre puntini nella scheda delle connessioni C2C.

Ora prova a caricare una risorsa:

${
>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
Specifica dell'endpoint API

La documentazione per /v2/devices/assets è disponibile qui.

Riceverai questo errore:

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}

Se annulli lo stato di pausa del dispositivo e riprovi con la stessa richiesta, la risorsa verrà creata.

Tuttavia, se la risorsa è stata creata durante la finestra di pausa, devi impostare il parametro offset in modo che rifletta quando è stata effettivamente creata la risorsa:

${
>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

Questo dice a Frame.io che la risorsa è stata creata 60 secondi fa (durante la pausa), attivando correttamente l’errore Channel Paused. È fondamentale che i valori di offset siano accurati per impedire di caricare contenuti sensibili contro la volontà dell’utente, inclusa proprietà intellettuale protetta, filmati sensibili o altro materiale riservato.

Offset e nuovi tentativi

Quando riprovi una chiamata di creazione della risorsa non riuscita, ricorda di aggiornare il valore di offset. Durante periodi prolungati di nuovi tentativi, uno offset statico potrebbe causare uno scostamento al di fuori dalla finestra di pausa, consentendo potenzialmente caricamenti che in realtà dovrebbero essere bloccati.

Caricamento su un canale specifico

Se il dispositivo ha più canali, puoi specificare quale usare:

${
>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

Se non specificato, il canale predefinito è 0. La maggior parte delle integrazioni non avrà bisogno di modificare questo valore.

Richiesta di un numero di chunk personalizzato

Per impostazione predefinita, il backend di Frame.io divide i file in chunk di circa 25 MB. Per le reti molto congestionate, potrebbe essere utile avere chunk più piccoli. Puoi richiedere un numero specifico di chunk con il parametro 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 risposta includerà quattro URL di caricamento:

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}

La dimensione del chunk sarà:

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

L’ultimo chunk sarà di 5.284.061 byte (calcolato come 21136250 - 5284063 * 3). Quando richiedi numeri di chunk personalizzati, tieni presente le limitazioni per i caricamenti multiparte di AWS S3:

  • Ogni parte deve essere di almeno 5 MiB (5.242.880 byte), eccetto l’ultima parte
  • Non possono esistere più di 10.000 parti

Se la richiesta viola questi vincoli, riceverai un errore 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"
}

Verifica sempre che il conteggio personalizzato delle parti sia conforme ai requisiti S3.

Caricamento efficiente

I dispositivi C2C funzionano spesso in ambienti di rete complessi, quindi l’efficienza è fondamentale. Ecco alcune strategie per massimizzare il throughput.

Riutilizzo/pooling delle connessioni TCP

Stabilire connessioni crittografate richiede un sovraccarico significativo in termini di negoziazione. Per un funzionamento efficiente, riutilizza le connessioni TCP se vengono effettuate più richieste. La maggior parte delle librerie HTTP fornisce un’astrazione Client o Session che mantiene connessioni persistenti.

Il processo di negoziazione per una nuova connessione HTTPS include handshake crittografici e convalida dei certificati. Riutilizzando le connessioni, il sovraccarico di verifica una sola volta, anziché per ogni richiesta.

Riferimento per l'handshake TCP

Per dettagli tecnici sui processi di handshake TLS, consulta la spiegazione di Cloudflare.

Per dimostrare il riutilizzo delle connessioni con curl, crea prima una nuova risorsa in Frame.io come descritto nella guida per il caricamento di base.

Quindi, dividi il file in chunk separati per il test:

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

Ora carica entrambi i chunk su una singola connessione TCP utilizzando il parametro --next di 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

Confronta il risultato con connessioni separate:

$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
Riutilizzo degli URL dei chunk

Puoi eseguire il caricamento sullo stesso URL di chunk più volte, quindi riutilizza senza problemi gli URL tra i vari esempi.

Nei test, il riutilizzo delle connessioni di solito migliora le prestazioni del 15-20% per i caricamenti sequenziali.

Caricamenti paralleli

Per un throughput ancora maggiore, carica più chunk contemporaneamente:

$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 \
>&

Se la larghezza di banda è sufficiente, i caricamenti paralleli si completano approssimativamente nel tempo del singolo caricamento più lento.

Per un parallelismo ottimale, una buona regola empirica è due caricamenti simultanei per core della CPU. Il superamento di questo rapporto può portare a conflitti delle risorse e a un rendimento inferiore.

Velocità del caricamento parallelo

Le condizioni di rete influiscono notevolmente sulle prestazioni del caricamento parallelo. In alcuni ambienti, i caricamenti sequenziali possono essere migliori rispetto a quelli paralleli. Le implementazioni avanzate potrebbero monitorare il throughput e regolare dinamicamente la contemporaneità. Esegui sempre la profilazione delle prestazioni nel tuo ambiente di produzione effettivo, invece di fare affidamento sulle tempistiche degli esempi.

Combinazione dei due approcci

Per avere la massima efficienza, combina i pool di connessioni con i caricamenti paralleli. Crea più processi, ognuno dei quali utilizza il pool di connessioni per la propria sequenza di caricamenti:

$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 \
>&
Funzionalità delle librerie HTTP

La maggior parte delle librerie HTTP fornisce astrazioni per il pool di connessioni e le richieste parallele. Sperimenta con le opzioni della tua libreria per determinare la configurazione ottimale per il tuo ambiente.

Tracciamento dell’avanzamento del caricamento

La tua integrazione deve fornire agli utenti un’indicazione di base dello stato di avanzamento. La granularità a livello di chunk è accettabile: per un caricamento di tre chunk, l’avanzamento potrebbe aumentare da 0% → 33% → 66% → 100% man mano che ogni chunk viene completato.

La generazione di report più dettagliati sull’avanzamento dipende dalle capacità della libreria HTTP che usi. Contatta il nostro team se hai bisogno di aiuto per implementare un tracciamento dell’avanzamento più dettagliato.

Caricamenti affidabili

Per una gestione affidabile degli errori, esamina la nostra guida agli errori. Le sezioni seguenti presuppongono che tu abbia implementato le strategie di gestione degli errori descritte in quella guida.

La creazione di un uploader da usare in produzione richiede considerazioni aggiuntive che vanno oltre la gestione degli errori delle singole richieste.

Creazione di una coda di caricamento

Negli scenari reali, il tuo dispositivo potrebbe generare i media più velocemente di quanto possa caricarli oppure potrebbe subire interruzioni di connessione prolungate. L’implementazione di un sistema di inserimento in coda separa la creazione dei media dalla gestione del caricamento.

Considera un’architettura a due code:

  1. Una coda dei media per registrare i file locali con Frame.io
  2. Una coda di chunk per caricare singoli chunk dei file

Ecco un’implementazione semplificata:

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)
Gestione degli errori

Nell’esempio precedente, si assume che le funzioni usate per le chiamate C2C gestiscano gli errori come descritto nella guida agli errori.

Accodamento persistente tra i cicli di potenza

L’approccio con le code in memoria funziona bene quando il dispositivo è acceso, ma cosa succede se l’alimentazione si interrompe prima del completamento dei caricamenti? Per creare un’integrazione davvero resiliente, dobbiamo assicurarci che il dispositivo possa riprendere da dove si era interrotto dopo il riavvio.

Ciò richiede il salvataggio persistente dello stato della coda nell’archiviazione tra i cicli di potenza. Un database integrato come SQLite fornisce una base eccellente per questa funzionalità.

L’implementazione di una coda persistente deve supportare queste operazioni chiave:

  • Aggiunta di file appena creati alla coda di caricamento
  • Tracciamento della creazione riuscita delle risorse in Frame.io
  • Registrazione degli errori di creazione delle risorse
  • Archiviazione delle informazioni sui chunk di file per le attività di caricamento
  • Recupero del prossimo chunk da caricare
  • Contrassegno dei chunk come caricati
  • Registrazione degli errori di caricamento dei chunk
  • Fornitura di informazioni sullo stato del file per la visualizzazione da parte dell’utente

Ecco come adattare l’esempio precedente per utilizzare un sistema di archiviazione 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 questo approccio di archiviazione persistente, l’integrazione può affrontare eventuali interruzioni di corrente. Quando il dispositivo si riavvia, continua semplicemente l’elaborazione dall’ultimo stato salvato. Questa architettura fornisce anche le basi per implementare funzionalità più avanzate, come il tracciamento degli errori e il rilevamento dei caricamenti bloccati.

Tracciamento degli errori di caricamento

Un sistema di caricamento affidabile deve tracciare attentamente gli errori. Dopo aver riprovato un’operazione utilizzando le strategie indicate nella guida agli errori, registra questi errori nell’archivio persistente. Ciò consente al sistema di:

  1. Ridurre la priorità dei caricamenti problematici per impedire che blocchino l’intera coda
  2. Fornire agli utenti informazioni accurate sullo stato
  3. Consentire l’intervento amministrativo per problemi persistenti

Quando si verifica un errore irreversibile, contrassegna l’elemento per evitare nuovi tentativi non necessari.

Gestione dei caricamenti bloccati

Implementa delle contromisure per i caricamenti bloccati indefinitamente. Imposta una durata massima (ad es. 30 minuti) dopo la quale un’attività di caricamento di un chunk deve essere terminata e riavviata. Questo previene possibili scenari in cui tutti i worker di caricamento vengono bloccati da operazioni che non rispondono.

Recupero da errori silenziosi

Gli arresti anomali del sistema, la perdita di alimentazione o la terminazione del processo possono impedire la normale generazione di report sugli errori. Quando recuperi elementi dalla coda, registra l’ora di checkout. Se un elemento rimane nello stato “in elaborazione” oltre una soglia ragionevole (ad es. 30 minuti) senza segnalare un’operazione riuscita o non riuscita, rimettilo automaticamente nel pool disponibile per l’elaborazione da parte di un altro worker.

Mitigazione dei caricamenti danneggiati

Un elemento della coda “danneggiato” non riesce mai a causa di problemi intrinseci con i dati o l’ambiente. Se questi elementi continuano a entrare nella coda, possono bloccare l’intero sistema di caricamento. Considera queste strategie per gestire tali casi:

  • Dopo più errori, riduci la priorità dell’elemento in modo che il contenuto più recente possa procedere
  • Traccia sia gli errori espliciti sia il numero di tentativi di elaborazione
  • Segui le best practice di connessione e autorizzazione per distinguere tra problemi ambientali transitori e problemi intrinseci del file
  • Implementa limiti di nuovi tentativi progressivi (ad es. riprova le operazioni individuali 10 volte all’interno di ciascuno dei 3 tentativi di lavoro, per un totale di 30 tentativi)
  • Fornisci un’interfaccia per ripristinare manualmente i caricamenti problematici una volta risolti i problemi ambientali

I caricamenti danneggiati possono essere causati da:

  • Dati di file corrotti che causano errori di I/O
  • Errori catastrofici del processo che impediscono la generazione di report sugli errori
  • Errori normalmente ripetibili attivati da condizioni sottostanti permanenti

Riprova dopo il riavvio del sistema

Prima di abbandonare definitivamente i caricamenti problematici, contrassegnali per un ultimo tentativo dopo il prossimo riavvio del sistema. Questo risolve i casi in cui i caricamenti non riescono a causa di problemi temporanei dello stato del sistema con memoria, driver o allocazione delle risorse. Se un caricamento continua a non riuscire dopo un riavvio completo, puoi contrassegnarlo con maggiore sicurezza come definitivamente problematico.

Cancellazione della coda

Ricorda di rimuovere i file non disponibili dalla coda. Quando i media vengono rimossi fisicamente o i file vengono eliminati, elimina le voci corrispondenti dalla coda di caricamento per prevenire errori non necessari.

È importante cancellare la coda di caricamento quando ti connetti a un nuovo progetto. I media in coda per un progetto non devono mai apparire in un altro. Quando un utente associa il dispositivo con un progetto diverso, verifica se il progetto è cambiato e, in tal caso, cancella completamente la coda esistente.

Passaggi successivi

Ti incoraggiamo a contattare il nostro team per qualsiasi domanda, poi vai alla guida sui caricamenti avanzati. Saremo lieti di aiutarti nel tuo percorso di implementazione.