15 dic 2025·8 min di lettura

Evitare i timeout delle esportazioni: job asincroni, indicatori di progresso e streaming

Evita i timeout delle esportazioni con job asincroni, indicatori di progresso, paginazione e download in streaming per grandi report CSV e PDF.

Evitare i timeout delle esportazioni: job asincroni, indicatori di progresso e streaming

Perché le esportazioni vanno in timeout, in parole semplici

Un'esportazione va in timeout quando il server non termina il lavoro prima di una scadenza. Quella scadenza può essere impostata dal browser, da un reverse proxy, dal server dell'app o dalla connessione al database. Per l'utente spesso sembra casuale, perché a volte l'esportazione funziona e a volte no.

A schermo di solito appare così:

  • Una rotella/spinner che non finisce mai
  • Un download che inizia e poi si interrompe con un "network error"
  • Una pagina di errore dopo una lunga attesa
  • Un file che scarica ma è vuoto o corrotto

Le esportazioni grandi sono stressanti perché coinvolgono più parti del sistema contemporaneamente. Il database deve trovare e assemblare molte righe. Il server dell'app deve formattarle in CSV o renderizzarle in PDF. Poi il browser deve ricevere una risposta grande senza che la connessione cada.

Dataset enormi sono il trigger più ovvio, ma anche esportazioni "piccole" possono pesare. Join costosi, molti campi calcolati, lookup per riga e filtri senza indici possono trasformare un report normale in un timeout. I PDF sono particolarmente rischiosi perché coinvolgono layout, font, immagini, interruzioni di pagina e spesso query extra per raccogliere i dati correlati.

I retry spesso peggiorano la situazione. Quando un utente aggiorna la pagina o clicca di nuovo Esporta, il sistema può avviare lo stesso lavoro due volte: il database esegue query duplicate, il server costruisce file duplicati e hai un picco proprio quando il sistema è già sotto pressione.

Se vuoi prevenire i timeout, tratta un'esportazione come un'attività in background, non come un normale caricamento di pagina. Anche in uno strumento no-code come AppMaster il pattern conta più dello strumento: i lavori lunghi richiedono un flusso diverso rispetto a "clicca, aspetta la risposta".

Scegli il pattern di esportazione giusto per la tua app

La maggior parte dei fallimenti capita perché l'app usa lo stesso pattern per ogni situazione, anche quando la dimensione dei dati e il tempo di elaborazione variano molto.

Un'export sincrona semplice (l'utente clicca, il server genera, il download parte) va bene quando l'esportazione è piccola e prevedibile. Pensa a poche centinaia di righe, colonne basi, nessun formato pesante e non troppi utenti che lo fanno contemporaneamente. Se finisce sempre in un paio di secondi, la soluzione semplice è quasi sempre la migliore.

Per tutto ciò che è lungo o imprevedibile, usa job di esportazione asincroni. Questo vale per dataset grandi, calcoli complessi, lavoro di layout PDF e server condivisi dove un'esportazione lenta può bloccare altre richieste.

I job asincroni sono più adatti quando:

  • Le esportazioni impiegano regolarmente più di 10–15 secondi
  • Gli utenti richiedono intervalli di date ampi o "all time"
  • Generi PDF con grafici, immagini o molte pagine
  • Più team esportano nelle ore di picco
  • Ti servono retry sicuri quando qualcosa fallisce

I download in streaming aiutano quando l'esportazione è grande ma può essere prodotta in ordine. Il server inizia a inviare byte subito, cosa che dà una sensazione di maggiore velocità e evita di costruire tutto il file in memoria. Funziona bene per CSV lunghi, ma è meno utile se devi calcolare tutto prima di poter scrivere la prima riga.

Puoi combinare gli approcci: esegui un job asincrono per generare l'export (o preparare uno snapshot), poi fai lo streaming del download quando è pronto. In AppMaster, un approccio pratico è creare un record "Export Requested", generare il file in un Business Process backend e permettere all'utente di scaricare il risultato finito senza tenere aperta la richiesta del browser.

Passo dopo passo: costruire un job di esportazione asincrono

La modifica più importante è semplice: smetti di generare il file dentro la stessa richiesta che l'utente ha aperto.

Un job asincrono divide il lavoro in due parti: una richiesta rapida che crea il job, e il lavoro in background che costruisce il file mentre l'app resta reattiva.

Un flusso pratico in 5 passi

  1. Cattura la richiesta di esportazione (chi ha richiesto, filtri, colonne selezionate, formato output).
  2. Crea un record di job con stato (queued, running, done, failed), timestamp e un campo errore.
  3. Esegui il lavoro pesante in background usando una coda, un worker schedulato o un processo worker dedicato.
  4. Scrivi il risultato su storage (object storage o file store), poi salva un riferimento al download nel record del job.
  5. Notifica l'utente quando è pronto usando una notifica in-app, email o un canale di messaggistica che il team già usa.

Tieni il record del job come fonte di verità. Se l'utente aggiorna la pagina, cambia dispositivo o chiude la tab, puoi comunque mostrare lo stesso stato del job e lo stesso pulsante di download.

Esempio: un manager support esporta tutti i ticket dell'ultimo trimestre. Invece di aspettare su una tab che gira, vede un entry del job muoversi da queued a done e poi apparire il download. In AppMaster puoi modellare la tabella dei job nel Data Designer, costruire la logica in background nel Business Process Editor e usare un campo status per guidare lo stato dell'interfaccia.

Indicatori di progresso di cui gli utenti si fidano

Un buon indicatore di progresso riduce l'ansia e impedisce alle persone di cliccare Esporta cinque volte. Aiuta anche a prevenire indirettamente i timeout, perché gli utenti sono più disposti ad aspettare quando l'app mostra un vero avanzamento.

Mostra il progresso in termini comprensibili. La sola percentuale spesso è fuorviante, quindi abbinala a qualcosa di concreto:

  • Step corrente (Preparing data, Fetching rows, Building file, Uploading, Ready)
  • Righe processate su totale (o pagine processate)
  • Ora di inizio e ultimo aggiornamento
  • Tempo stimato rimanente (solo se resta ragionevolmente stabile)

Evita precisione fasulla. Se non conosci ancora il lavoro totale, non mostrare 73%. Usa milestone iniziali, poi passa alla percentuale quando conosci il denominatore. Un pattern semplice è 0%–10% per l'impostazione, 10%–90% basato sulle righe processate e 90%–100% per la finalizzazione del file. Per PDF con dimensioni di pagina variabili, traccia verità più piccole come "records rendered" o "sections completed".

Aggiorna abbastanza spesso da far sembrare il sistema vivo, ma non così spesso da sovraccaricare il database o la coda. Un approccio comune è scrivere il progresso ogni 1–3 secondi, o ogni N record (per esempio ogni 500 o 1.000 righe), qualunque sia meno frequente. Registra anche un timestamp di heartbeat leggero così la UI può mostrare "Still working" anche quando la percentuale non si muove.

Dai agli utenti controllo quando le cose prendono più tempo del previsto. Permetti di cancellare un'export in esecuzione, avviare una nuova senza perdere la prima e visualizzare la cronologia esportazioni con stato (Queued, Running, Failed, Ready) più un breve messaggio d'errore.

In AppMaster, un record tipico è ExportJob (status, processed_count, total_count, step, updated_at). La UI effettua polling su quel record e mostra un progresso onesto mentre il job asincrono genera il file in background.

Paginazione e filtri per mantenere il lavoro limitato

Impedisci i doppio clic su Esporta
Rendi sicure le retry riutilizzando lo stesso job invece di crearne di duplicati.
Inizia a costruire

La maggior parte dei timeout avviene perché l'esportazione cerca di fare tutto in un colpo: troppe righe, troppe colonne, troppi join. La soluzione più veloce è limitare il lavoro in modo che gli utenti esportino una porzione più piccola e chiara di dati.

Parti dall'obiettivo dell'utente. Se qualcuno ha bisogno di "le fatture del mese scorso che hanno fallito", non imporgli per default "tutte le fatture di sempre". Rendi i filtri normali, non un compito noioso. Un range di date semplice più un filtro di stato spesso riduce il dataset del 90%.

Un buon form di richiesta di esportazione include normalmente un intervallo di date (con default sensati come ultimi 7 o 30 giorni), uno o due stati chiave, ricerca opzionale o selezione cliente/team e un'anteprima del conteggio quando possibile (anche solo una stima).

Lato server, leggi i dati a blocchi usando la paginazione. Questo mantiene la memoria stabile e ti dà checkpoint naturali per il progresso. Usa sempre un ordinamento stabile quando fai paging (per esempio order by created_at, poi id). Senza questo, nuove righe possono scivolare in pagine precedenti e rischi di perdere o duplicare record.

I dati cambiano durante esportazioni lunghe, quindi decidi cosa significa "coerente". Un approccio semplice è registrare un tempo di snapshot quando il job parte, poi esportare solo le righe fino a quel timestamp. Se ti servono garanzie strette, usa una lettura consistente o una transazione dove il database lo supporta.

In uno strumento no-code come AppMaster, questo si mappa bene a un business process: valida i filtri, imposta il tempo snapshot, poi cicla sulle pagine finché non c'è più niente da prendere.

Streaming dei download senza sovraccaricare il server

Aggiungi una tabella Export Job
Crea un modello ExportJob e monitora gli stati queued, running, done e failed.
Inizia a costruire

Lo streaming significa iniziare a inviare il file all'utente mentre lo stai ancora generando. Il server non deve costruire tutto il CSV o il PDF in memoria prima. È uno dei modi più affidabili per evitare timeout quando i file diventano grandi.

Lo streaming non rende magiche le query lente. Se il lavoro sul database richiede cinque minuti prima che il primo byte sia pronto, la richiesta può ancora andare in timeout. La soluzione tipica è combinare streaming con paging: prendi un chunk, scrivilo, e continua.

Per mantenere la memoria bassa, scrivi man mano. Genera un chunk (per esempio 1.000 righe CSV o una pagina PDF), scrivilo nella response, poi flush così il client continua a ricevere dati. Evita di accumulare righe in un grande array "solo per ordinare dopo". Se ti serve un ordine stabile, fai l'ordinamento nel database.

Header, nomi e content-type

Usa header chiari così browser e app mobile trattano correttamente il download. Imposta il content type giusto (come text/csv o application/pdf) e un nome file sicuro. I nomi file dovrebbero evitare caratteri speciali, restare corti e includere un timestamp se gli utenti esportano lo stesso report più volte.

Ripresa e download parziali

Decidi presto se supporti la ripresa. Lo streaming di base spesso non supporta il resume tramite range di byte, specialmente per PDF generati. Se lo supporti, devi gestire le richieste Range e generare un output consistente per lo stesso job.

Prima di rilasciare assicurati di:

  • Inviare gli header prima di scrivere il body, poi scrivere a chunk e flushare
  • Mantenere le dimensioni dei chunk costanti così la memoria rimane piatta sotto carico
  • Usare un ordinamento deterministico così gli utenti possono fidarsi dell'output
  • Documentare se il resume è supportato e cosa succede se la connessione cade
  • Aggiungere limiti lato server (max rows, max time) e restituire un errore amichevole quando vengono raggiunti

Se costruisci le esportazioni in AppMaster, tieni la logica di generazione in un flow backend e fai lo streaming dal lato server, non dal browser.

Grandi esportazioni CSV: tattiche pratiche

Per grandi CSV, smetti di trattare il file come un unico blob. Costruiscilo in un loop: leggi una fetta di dati, scrivi le righe, ripeti. Questo mantiene la memoria piatta e rende i retry più sicuri.

Scrivi il CSV riga per riga. Anche se generi l'export in un job asincrono, evita "colleziona tutte le righe e poi stringifica". Tieni un writer aperto e aggiungi ogni riga appena pronta. Se la tua stack lo supporta, usa un cursor del database o fai paging dei risultati così non carichi milioni di record in memoria.

La correttezza del CSV conta tanto quanto la velocità. Un file può sembrare a posto finché qualcuno non lo apre in Excel e alcune colonne si spostano.

Regole CSV per prevenire file rotti

  • Escape sempre virgole, virgolette e newline (racchiudi il campo tra virgolette e raddoppia le virgolette interne)
  • Output in UTF-8 e testa nomi non inglesi end-to-end
  • Usa una riga header stabile e mantieni l'ordine delle colonne fisso tra gli export
  • Normalizza date e decimali (scegli un formato e usalo)
  • Evita formule se i dati possono iniziare con =, +, - o @

Le prestazioni spesso muoiono sull'accesso ai dati, non sulla scrittura. Attento agli N+1 lookup (per esempio caricare ogni cliente dentro un loop). Prendi i dati correlati in una query sola o preload ciò che ti serve, poi scrivi le righe.

Quando le esportazioni sono davvero enormi, dividile apposta. Un approccio pratico è un file per mese, per cliente o per tipo di entità. Un "5 anni di ordini" può diventare 60 file mensili, ciascuno generato indipendentemente così un mese lento non blocca tutto.

Se usi AppMaster, modella il dataset nel Data Designer ed esegui l'export come Business Process in background, scrivendo righe mentre scorre le pagine dei record.

Grandi esportazioni PDF: mantienile prevedibili

Esporta grandi dataset a blocchi
Scorri i record a blocchi per mantenere stabile la memoria nelle esportazioni grandi.
Inizia

La generazione PDF è di solito più lenta del CSV perché è pesante in CPU. Non stai solo muovendo dati: stai disponendo pagine, posizionando font, disegnando tabelle e spesso ridimensionando immagini. Tratta il PDF come un'attività in background con limiti chiari, non come una risposta rapida.

Le scelte del template determinano se un'export da 2 minuti diventa da 20 minuti. I layout semplici vincono: meno colonne, meno tabelle annidate e interruzioni di pagina prevedibili. Le immagini sono uno dei modi più veloci per rallentare tutto, specialmente se sono grandi, ad alta risoluzione o recuperate da storage remoto durante il rendering.

Decisioni sul template che di solito migliorano velocità e affidabilità:

  • Usa uno o due font e evita catene di fallback pesanti
  • Mantieni header e footer semplici (evita grafici dinamici su ogni pagina)
  • Preferisci icone vettoriali a immagini raster grandi
  • Limita i layout "auto fit" che ricalcolano il testo molte volte
  • Evita trasparenze complesse e ombre

Per grandi esportazioni, renderizza a batch. Genera una sezione o un piccolo intervallo di pagine alla volta, scrivilo in un file temporaneo e poi componi il PDF finale. Questo mantiene la memoria stabile e rende i retry più sicuri se un worker crasha a metà. Si abbina bene ai job asincroni e a un progresso che avanza per passi significativi (per esempio: "Preparing data", "Rendering pages 1–50", "Finalizing file").

Chiediti anche se il PDF è davvero necessario. Se gli utenti vogliono principalmente righe e colonne per analisi, offri il CSV insieme a "Export PDF". Puoi generare un PDF riepilogativo più piccolo per reportistica e lasciare il dataset completo in CSV.

In AppMaster, tutto questo si integra naturalmente: esegui la generazione PDF come job in background, riporta il progresso e consegna il file finito come download quando il job è completo.

Errori comuni che causano timeout

I fallimenti nelle esportazioni di solito non sono misteriosi. Alcune scelte vanno bene con 200 righe e poi si rompono a 200.000.

Gli errori più comuni:

  • Eseguire tutta l'esportazione dentro una richiesta web. Il browser aspetta, il worker del server resta occupato e una query lenta o un file grande ti portano oltre i limiti di tempo.
  • Mostrare il progresso basato sul tempo invece che sul lavoro. Un timer che corre fino al 90% e poi si blocca fa sì che gli utenti aggiornino, cancellino o rilancino l'export.
  • Caricare ogni riga in memoria prima di scrivere il file. Facile da implementare, e un modo rapido per raggiungere i limiti di memoria.
  • Tenere transazioni di database lunghe o ignorare i lock. Le query di esportazione possono bloccare le scritture, o essere bloccate dalle scritture, e il rallentamento si propaga nell'app.
  • Permettere esportazioni illimitate senza pulizia. Click ripetuti accumulano job, riempiono lo storage e lasciano file vecchi in giro.

Un esempio concreto: un lead support esporta tutti i ticket degli ultimi due anni e clicca due volte perché sembra che non succeda nulla. Ora due esportazioni identiche competono per lo stesso database, entrambe costruiscono file enormi in memoria e entrambe vanno in timeout.

Se costruisci questo in uno strumento no-code come AppMaster, valgono le stesse regole: tieni le esportazioni fuori dal percorso della richiesta, traccia il progresso per righe processate, scrivi l'output mentre vai e metti limiti semplici su quante esportazioni un utente può avere in corso.

Controlli rapidi prima del rilascio

Evita i timeout delle esportazioni velocemente
Crea job di esportazione asincroni così gli utenti non aspettano una singola richiesta web.
Prova AppMaster

Prima di mettere in produzione una funzione di export, fai una rapida verifica con mentalità da timer. Il lavoro lungo avviene fuori dalla richiesta, gli utenti vedono progresso onesto e il server non cerca di fare tutto in una volta.

Una checklist pre-flight:

  • Le esportazioni grandi girano come job in background (quelle piccole possono essere sincrone se finiscono sempre velocemente)
  • Gli utenti vedono stati chiari come queued, running, done o failed, con timestamp
  • I dati vengono letti a blocchi con un ordine stabile (per esempio created time più un tie-breaker su id)
  • I file finiti possono essere scaricati dopo senza dover rilanciare l'export, anche se l'utente chiude la tab
  • C'è un piano di limiti e pulizia per file e cronologia job vecchi (cancellazione per età, max job per utente, limiti di storage)

Un buon controllo di sanità è provare il tuo caso peggiore: esporta l'intervallo di date più grande che permetti mentre qualcun altro aggiunge record. Se trovi duplicati, righe mancanti o progresso bloccato, il tuo ordinamento o chunking non è stabile.

Se costruisci su AppMaster, questi controlli si mappano chiaramente: un processo in background nel Business Process Editor, un record Export Job nel database e un campo status che la UI legge e aggiorna.

Rendi il fallimento sicuro. Un job fallito dovrebbe mantenere il suo messaggio d'errore, permettere un retry e evitare di creare file parziali che sembrano "completi" ma non lo sono.

Esempio: esportare anni di dati senza bloccare l'app

Itera senza riscrivere la logica
Mantieni le esportazioni manutenibili rigenerando il codice sorgente quando i requisiti cambiano.
Prova AppMaster

Un manager operations ha bisogno di due esportazioni ogni mese: un CSV con gli ultimi 2 anni di ordini per l'analisi e un insieme di PDF fatture mensili per la contabilità. Se l'app prova a costruire uno di questi durante una normale richiesta web, prima o poi arrivano i limiti di tempo.

Inizia limitando il lavoro. La schermata di export chiede un intervallo di date (default: ultimi 30 giorni), filtri opzionali (status, regione, sales rep) e una scelta chiara di colonne. Questo spesso trasforma un problema di 2 anni e 2 milioni di righe in qualcosa gestibile.

Quando l'utente clicca Esporta, l'app crea un record Export Job (type, filters, requested_by, status, progress, error_text) e lo mette in coda. In AppMaster questo è un modello nel Data Designer più un Business Process che gira in background.

Mentre il job gira, la UI mostra uno stato affidabile: queued, processing (per esempio 3 di 20 chunk), generating file, ready (pulsante download) o failed (errore chiaro e retry).

Il chunking è il dettaglio chiave. Il job CSV legge gli ordini a pagine (per esempio 50.000 alla volta), scrive ogni pagina nell'output e aggiorna il progresso dopo ogni chunk. Il job PDF fa lo stesso per batch di fatture (per esempio un mese alla volta) così un mese lento non blocca tutto.

Se qualcosa si rompe (filtro sbagliato, permesso mancante, errore di storage), il job viene marcato Failed con un messaggio breve che l'utente può usare: "Impossibile generare le fatture di marzo. Riprova o contatta support con Job ID 8F21." Un retry riusa gli stessi filtri così l'utente non deve ricominciare da zero.

Prossimi passi: rendi le esportazioni una funzionalità integrata, non un incidente

La via più rapida per prevenire i timeout a lungo termine è smettere di trattare le esportazioni come un pulsante una tantum e farne una funzione standard con un pattern ripetibile.

Scegli un approccio di default e usalo ovunque: un job asincrono genera un file in background e poi l'utente può scaricarlo quando è pronto. Questa singola decisione rimuove la maggior parte delle sorprese del tipo "funzionava in test", perché la richiesta dell'utente non deve aspettare il file completo.

Rendi facile per le persone trovare ciò che hanno già generato. Una pagina di cronologia esportazioni (per utente, workspace o account) riduce i retry, aiuta il support a rispondere "dov'è il mio file?" e ti dà un posto naturale per mostrare stato, errori ed eventuale scadenza.

Se costruisci questo pattern dentro AppMaster, aiuta che la piattaforma genera codice sorgente reale e supporta logica backend, modellazione DB e UI web/mobile in un unico posto. Per i team che vogliono spedire job di export asincroni affidabili velocemente, appmaster.io è spesso usato per creare la tabella dei job, il processo in background e l'interfaccia di progresso senza cablare tutto a mano.

Poi misura ciò che davvero fa male. Traccia query database lente, tempo speso a generare CSV e tempo di render PDF. Non ti serve osservabilità perfetta per cominciare: loggare durata e conteggio righe per esportazione ti mostrerà presto quale report o combinazione di filtri è il vero problema.

Tratta le esportazioni come qualsiasi altra funzionalità di prodotto: coerente, misurabile e facile da supportare.

FAQ

Perché le esportazioni vanno in timeout anche se a volte funzionano?

Un'esportazione va in timeout quando il lavoro non termina prima di una soglia impostata lungo il percorso della richiesta. Quel limite può venire dal browser, da un reverse proxy, dal server dell'app o dalla connessione al database, perciò può sembrare casuale anche se la causa reale è carico elevato o query lente.

Quando va bene una esportazione “clicca e scarica” e quando dovrei usare job asincroni?

Usa un'export sincrona solo quando finisce in modo affidabile in un paio di secondi con dimensioni dati prevedibili. Se le esportazioni impiegano spesso più di 10–15 secondi, coinvolgono range di date estesi, calcoli pesanti o PDF, passa a un job asincrono così la richiesta del browser non deve restare aperta.

Qual è il flusso asincrono più semplice che posso implementare in AppMaster?

Crea prima un record di job, poi esegui il lavoro pesante in background e infine lascia che l'utente scarichi il file finito. In AppMaster è comune avere un modello ExportJob nel Data Designer e un Business Process backend che aggiorna status, i campi di progresso e una referenza al file salvato durante l'esecuzione.

Come mostro un progresso che gli utenti si fidano davvero?

Monitora il lavoro reale, non il tempo trascorso. Una soluzione pratica è salvare campi come step, processed_count, total_count (quando noto) e updated_at, poi far effettuare il polling alla UI per mostrare stati chiari così gli utenti non si sentono bloccati e non premono ripetutamente il pulsante di esportazione.

Come evito che gli utenti avviino la stessa esportazione più volte?

Rendi la richiesta di esportazione idempotente e usa il record del job come fonte di verità. Se l'utente clicca di nuovo, mostra il job già in esecuzione (o blocca duplicati con gli stessi filtri) invece di avviare lo stesso lavoro costoso due volte.

Qual è il modo più sicuro per paginare i dati nelle esportazioni grandi?

Leggi e scrivi a blocchi così la memoria rimane costante e ottieni checkpoint naturali. Usa paginazione stabile con un ordinamento deterministico (per esempio per created_at e poi id) in modo da non perdere o duplicare righe mentre i dati cambiano durante un'esportazione lunga.

Come mantengo le esportazioni coerenti se i dati cambiano mentre il job è in esecuzione?

Registra un timestamp di snapshot quando il job parte ed esporta solo le righe fino a quel momento in modo che l'output non “si muova” mentre è in corso. Se ti servono garanzie più forti, usa letture consistenti o transazioni supportate dal tuo database; comunque, partire da una regola di snapshot chiara è spesso sufficiente per la maggior parte degli utenti.

Lo streaming dei download previene i timeout da solo?

Lo streaming aiuta quando puoi produrre l'output in ordine e iniziare a inviare byte presto, specialmente per grandi CSV. Non risolve query lente che richiedono minuti prima del primo byte, e la richiesta può ancora andare in timeout se nulla viene scritto per troppo tempo; quindi lo streaming funziona meglio se combinato con la paginazione che scrive chunk continuamente.

Quali sono le cause più comuni di esportazioni CSV rotte o lente?

Scrivi le righe mano a mano e segui le regole di escaping CSV così il file non si rompe in Excel o altri strumenti. Mantieni la codifica coerente (di solito UTF-8), fissa header e ordine delle colonne, ed evita lookup per riga che trasformano una singola esportazione in migliaia di query aggiuntive.

Perché le esportazioni PDF falliscono più spesso delle CSV e come le rendo affidabili?

La generazione di PDF è più pesante perché richiede layout, font, immagini e gestione delle pagine, quindi trattala come un job in background con limiti chiari. Mantieni i template semplici, evita immagini grandi o remote durante il rendering e segnala il progresso in passi significativi così gli utenti capiscono che il processo sta procedendo.

Facile da avviare
Creare qualcosa di straordinario

Sperimenta con AppMaster con un piano gratuito.
Quando sarai pronto potrai scegliere l'abbonamento appropriato.

Iniziare