Overview

Troubleshooting & Best Practices

Questa pagina raccoglie i sintomi piu' frequenti su un'installazione WUIC, la causa reale e il rimedio verificato. Prima di cercare nel codice leggi i tre endpoint diagnostici: nella maggior parte dei casi la risposta e' li'.

Prima diagnosi: tre endpoint

EndpointCosa diceCampi da guardare
GET /api/Meta/LicenseStatusstato licenza e fingerprint della macchinalicenseValid, licenseReason, tier, features, machineFingerprint, dataDbms, metaDbms
GET /api/Meta/FirstRunStatusse l'installazione e' ancora in first-runfirstRun
GET /api/Rag/Healthstato dell'engine RAG .NETstatus (ok / not-initialized), engine, lastError

Sintomi frequenti

Le liste mostrano al massimo 20 record

Il backend gira in modalita' Trial: licenza assente, scaduta o con fingerprint non autorizzato. LicenseStatus risponde licenseValid=false con il motivo in licenseReason (invalid_signature, machine_fingerprint_not_authorized, machine_fingerprint_missing, license_expired). Rimedio: pagina Licensing; dopo aver inserito license-payload e license-signature riavvia il backend e ricontrolla licenseValid=true.

Una feature Pro apre la pagina "accesso negato"

Il tier della licenza non include la feature (features in LicenseStatus): designer, workflow, report, spreadsheet, pivot-grid e RAG chatbot sono Professional. Il guard requireFeature della route blocca l'accesso con Developer.

"Server RAG non raggiungibile" / RAG offline

  • status=not-initialized senza lastError: l'engine sta scaricando modelli e indice (~4,5 GB, 1-5 min) o li sta caricando (warm-up ~30 s). Attendi la notifica in-app.
  • lastError valorizzato: download fallito (CDN non raggiungibile, disco pieno) oppure rag-engine/WuicRagEngine.dll mancante. Controlla rag-engine-models-url, lo spazio disco e rag-engine-dll-path.
  • rag-use-dotnet-engine=false senza server Python: il controller fa da bridge verso 127.0.0.1:8765, che non esiste. Riporta la chiave a true.
  • Query lente (15-25 s): normale su CPU. Con GPU NVIDIA verifica CUDA 12.x + cuDNN 9 e rag-engine-cuda-path.
  • Cold start lento su Windows: aggiungi rag-engine/artifacts/ alle esclusioni dell'antivirus (Defender scansiona vectors.npy a ogni avvio).

Le modifiche ai metadata non si vedono

La cache runtime dei metadata e' ancora valida. Dopo modifiche dirette in SQL alle tabelle _metadati__* chiama MetaService.invalidateMetadataRuntime con body esplicito {"clearAll":true} (senza body il flush e' parziale) e verifica che projectMetadataVersion cambi con MetaService.getProjectMetadataVersion. Le modifiche fatte dal designer o dal chatbot invalidano da sole.

Ogni query piu' lunga di pochi secondi fallisce

AppSettings.autoGeneratedQueryTimeout e' il timeout in secondi delle query autogenerate: un valore troppo basso (es. 1) fa fallire qualunque lista non banale. Riportalo a 30 o piu'; la chiave e' hot-reload.

"Errore concorrenza ottimistica" in salvataggio

Il record e' stato modificato da un altro utente o processo dopo la lettura: ricarica e riapplica la modifica. Se compare su tutte le scritture, controlla che non ci siano due backend sullo stesso database (tipico in test: uno lanciato a mano piu' quello del dispatcher). Vedi Concorrenza ottimistica.

La sessione viene chiusa da sola (session_replaced)

Il framework applica la sessione singola per utente: un secondo login dello stesso utente sostituisce il primo. Se succede senza un secondo login, di nuovo: due backend sullo stesso DB metadata.

Il wizard di first-run riappare a ogni avvio

AppSettings.firstRun e' ancora "true" nel file appsettings.{Environment}.json letto dall'host in esecuzione (attenzione all'ambiente attivo: Development vs Production). Il wizard lo porta a false a fine provisioning; se il file non e' scrivibile dal processo, resta true.

Un lookup mostra [object Object]

mcuilookupdata_value_field, mcuilookupdata_text_field e mc_ui_grid_*_id_field devono contenere il nome friendly della colonna (= mc_nome_colonna): sono chiavi di accesso al JSON della response. I campi che emettono SQL (md_nome_tabella, mc_real_column_name) devono invece avere il case fisico esatto dello schema.

Il filtro in query string viene ignorato

Le URL verso <route>/List accettano filterInfo=..., non filter=....

Route con spazi non trovate

Le route metadata possono contenere spazi significativi: non applicare trim() o normalizzazioni quando le costruisci o le confronti.

Errore 10316 durante lo scaffolding del tutorial

SQL Server 2017, o Express con il cap RAM, sotto carico spatial. Requisito: SQL Server 2019+; per il dev locale Developer Edition o LocalDB.

Linux dietro reverse proxy: URL con porta o schema sbagliati

Il vhost nginx deve inoltrare host e schema: proxy_set_header Host $http_host; e proxy_set_header X-Forwarded-Proto $scheme;. Gli upgrade non riscrivono un vhost esistente.

Linux: connessioni rifiutate con centinaia di utenti

Con i default di nginx e dei database (nginx 768 connessioni per worker, MySQL 151 connessioni, PostgreSQL 100, Oracle Free 200 processi) il server rifiuta connessioni prima che l'applicazione sia carica: nell'error.log di nginx compare worker_connections are not enough, nel log dell'applicazione Too many connections (MySQL), 53300: sorry, too many clients already (PostgreSQL) oppure ORA-12516 / ORA-00020 (Oracle). L'installer Linux alza questi limiti: nginx 4096 connessioni per worker con keep-alive verso Kestrel, MySQL e PostgreSQL 300 connessioni e buffer al 25% della RAM, Oracle 400 processi. Un'installazione fatta con un installer precedente mantiene i vecchi valori: i comandi per alzarli a mano sono in scripts/linux/README.md, sezione "Capacity for hundreds of concurrent users". SQL Server Express resta limitato a 4 core e circa 1,4 GB di buffer pool, qualunque sia il server.

Report non generati su Linux

Le versioni precedenti alla 1.7.0 gestivano i font con una libreria disponibile solo su Windows: aggiorna il pacchetto.

Login rifiutato dopo molti tentativi (HTTP 429)

Il login risponde 429 errors.auth.login_rate_limited: e' scattato il limite dei tentativi di login, e retryAfterSeconds dice quanti secondi aspettare. Le cause sono due:

  • Stesso utente: 5 password sbagliate in 5 minuti bloccano quell'utente per 1 minuto. Aspetta il minuto; un login riuscito azzera il contatore. Questo limite non si spegne.
  • Molti login dallo stesso IP (stress test, ufficio dietro un NAT condiviso): scatta solo se loginRateLimitPerIpPerMinute e' maggiore di 0, e blocca l'IP per 1 minuto. Alza il valore, oppure aggiungi l'IP a loginRateLimitExemptIps (es. 10.0.2.2 per una VM VirtualBox in NAT, che vede l'host con quell'indirizzo). Fino alla 1.7.15 il limite per IP era fisso a 30 tentativi al minuto e l'unica eccezione era il loopback.

Vedi Autenticazione & Autorizzazioni.

Checklist rapida

1. Network tab: request e response del MetaService.* che fallisce. Una chiave JSON sbagliata non ritorna 400: il backend usa i default e la diagnosi viene falsata.

2. md_props_bag della route e configurazione colonne (mc_ui_column_type, lookup, flag hide).

3. LicenseStatus, FirstRunStatus, Rag/Health come sopra.

4. appsettings.{Environment}.json dell'ambiente effettivamente attivo.

5. Un solo backend per database.

Best practice

  • Chiavi primarie e indici sulle tabelle esposte: filtri, paginazione e ordinamento autogenerati li usano.
  • Modifica i metadata dal designer o dal chatbot quando puoi: l'invalidazione della cache e' automatica.
  • Abilita AppSettings:enablePerformanceInspector per misurare fetch e render per route (media, p95, massimo) prima di ottimizzare a intuito.
  • Dopo un upgrade confronta appsettings.json con il template del pacchetto: le nuove chiavi hanno default conservativi, ma il confronto evita sorprese.
  • Usa le eccezioni tipizzate per gli errori applicativi: vedi Gestione eccezioni custom.