Gran parte del lavoro di ingegneria che abbiamo svolto negli ultimi anni si è concentrato sull'aiutare i clienti a ridurre l'uso della CPU e il tempo di wall clock. Qualche mese fa abbiamo aggiornato il nostro modello di prezzi per riflettere questo cambiamento, rimuovendo il misuratore della durata per concentrarci rigorosamente sulle richieste e sul consumo di vCPU. Questo nuovo modello offre ai clienti più controllo, così quando scrivono codice più efficiente riducono direttamente la spesa.
Questa spinta verso l’efficienza si riflette anche in alcuni dei nostri recenti lavori di engineering guidati dai clienti, in cui ci siamo trovati di fronte alla necessità di supportare richieste backend di durata maggiore, in particolare per flussi di lavoro agentici ad alta intensità di calcolo, che fanno sì che i servizio raggiungano il loro limite di tempo di esecuzione.
Poiché il proxy delle richieste ai Large Language Models (LLMs) richiede tempo, volevamo offrire agli sviluppatori un modo per attendere queste risposte senza occupare le risorse edge disponibili. Rispondere a questa esigenza si è evoluto in un miglioramento più ampio della piattaforma che continueremo a espandere. Il miglioramento è una nuova funzionalità di handoff delle richieste, ed è già disponibile nella versione 0.13.0 di Fastly Rust SDK.
Gestione dei limiti dei guest Wasm e delle richieste a lunga esecuzione
Compute applica in genere un timeout di wall clock di 2 minuti per i guest Wasm. Questo limite è intenzionale per proteggere le risorse e garantire un ricambio sano delle richieste. Il design funziona inoltre perfettamente per la grande maggioranza dei microservizi e della logica edge, dove manteniamo una mappatura 1:1 tra i guest Wasm in esecuzione e le richieste in arrivo.
Tuttavia, questa architettura a volte può diventare problematica quando si attende backend lenti o che non rispondono. Ciò può essere dovuto a un carico elevato sull'origine che rallenta tutte le richieste in corso, oppure alla necessità di completare un calcolo intensivo per generare una risposta. A volte potrebbe non dipendere nemmeno dall'origine, come nel caso di una richiesta POST di lunga durata che impiega un po' di tempo a scrivere i byte del body nell'origine a causa di un caricamento di grandi dimensioni o di un flusso lento di byte da un client mobile.
(Nota: i guest Wasm sono moduli Wasm compilati che vengono eseguiti all’interno di un host Wasm. I guest Wasm vengono eseguiti in una sandbox rigorosa, così l’host può eseguire in sicurezza codice non attendibile senza consentirgli di compromettere il sistema sottostante.)
La soluzione: PendingRequest::send_to_client
Per supportare meglio queste richieste backend di lunga durata e aumentare il throughput RPS, abbiamo introdotto una nuova funzionalità di PendingRequest::send_to_client. Con questa nuova funzionalità, possiamo inviare una richiesta asincrona a un’origine e, se si tratta di un passaggio diretto o di una richiesta hit-for-pass, possiamo trasferirla dal guest all’host mentre è ancora in corso, anche prima di conoscere la risposta finale. Quindi istruiamo la piattaforma a ritrasmettere la risposta al client downstream quando viene infine risolta. Poiché la richiesta continua a essere eseguita in background, il guest Wasm può terminare in anticipo e liberare le proprie risorse per richieste future. Questo approccio aumenta drasticamente il throughput RPS e protegge i servizi Compute dall'esaurire le istanze Compute disponibili in attesa del completamento delle richieste a lunga esecuzione.
Esempio Hello World:
use fastly::{Error, Request};
fn main() -> Result<(), Error> {
// 1. Receive the incoming downstream request from the client:
let req = Request::from_client();
// 2. Dispatch the direct pass request asynchronously to your slow backend:
let pending_req = req.with_pass(true).send_async("my_slow_origin_backend")?;
// 3. Hand off the unresolved, in-flight request directly to the host daemon:
pending_req.send_to_client()?;
// 4. Terminate the guest cleanly.
// The host daemon takes over, monitoring the request and piping the eventual
// response back downstream completely independently.
Ok(())
}Casi d'uso chiave
Gateway IA con calcolo intensivo e loop LLM di lunga durata: All'inizio di quest'anno, abbiamo esplorato come gli sviluppatori stanno creando loop di agenti IA a bassa latenza sicuri direttamente su Fastly Compute. In un flusso di lavoro agentico, un servizio edge spesso coordina più iterazioni di ragionamento, chiamate agli strumenti e prompt di modelli esterni. Sebbene il nostro runtime offra un ambiente eccezionalmente sicuro per eseguire questi agenti autonomi, attività pesanti di generazione di testo o elaborazioni complesse da provider LLM upstream possono aumentare drasticamente i tempi di elaborazione prima che vengano generate le intestazioni. Riutilizzando questi modelli di connessione con la nuova API nell'SDK Rust, puoi usare Fastly Compute come gateway IA intelligente ad alta velocità effettiva. La tua applicazione edge può autorizzare la richiesta tramite backend dinamici, valutare le autorizzazioni del client o inserire livelli di caching semantico, quindi avviare in modo asincrono la pesante chiamata LLM.
Ottimizzazione della schermatura: La maggior parte delle architetture instrada le richieste iniziali a un point of presence edge, che poi funge da proxy verso un point of presence shield dove avviene la manipolazione pesante. Il point of presence edge spesso non modifica la risposta finale, ma si limita invece a inoltrare direttamente la risposta del point of presence shield. Con il pending request handoff, il point of presence edge può avviare la richiesta shield in modo asincrono, trasferirla e terminare istantaneamente la propria impronta locale del guest, riducendo drasticamente il tempo totale di wall clock nei point of presence edge più vicini.

Figura 1: Il grafico mostra un servizio Compute che esegue lo shielding verso NYC e riceve traffico costante a Brisbane (BNE), trasferendo le sue richieste di shielding. Il tempo di clock a parete a BNE quasi scompare dopo l’uso della funzionalità di handoff.
Caricamenti di lunga durata: se il tuo servizio riceve contenuti in ingresso ai bordi della rete da client con larghezza di banda ridotta, l’uso di questa funzionalità consente al tuo servizio di evitare i timeout del tempo di clock reale del guest permettendo alla piattaforma di continuare il caricamento indipendentemente dall’esecuzione del guest Wasm.
Modifica delle intestazioni e gestione degli errori
Questa nuova funzionalità include anche la possibilità di modificare le intestazioni nella risposta finale. Puoi mettere in coda modifiche per rimuovere o inserire intestazioni specifiche prima di eseguire l'handoff effettivo. Questo ti consente di specificare modifiche come “rimuovi questo nome di intestazione” oppure “inserisci questa intestazione con valore X”, che verranno applicate una volta ricevuta la risposta:
use fastly::{Error, Request};
use fastly::http::request::PendingResponseKind;
fn main() -> Result<(), Error> {
// 1. Receive the incoming downstream request from the client:
let req = Request::from_client();
// 2. Dispatch the direct pass request asynchronously to your slow backend:
let mut pending = req.with_pass(true).send_async("my_slow_origin_backend")?;
// 3.1 Remove the `Server` header added by the origin's application server:
pending.remove_response_header("Server", PendingResponseKind::Response);
// 3.2 Insert the current service version for debugging:
pending.set_response_header(
"X-Service-Version",
fastly::compute_runtime::service_version().to_string(),
PendingResponseKind::Any
);
// 4. Hand off the unresolved, in-flight request directly to the host daemon:
pending.send_to_client()?;
// 5. Terminate the guest cleanly.
// The host daemon takes over, monitoring the request and piping the eventual
// response back downstream completely independently.
Ok(())
}Nota l'uso del tipo PendingResponseKind nell'esempio precedente. Ciò consente al servizio di controllare se le modifiche dell’intestazione vengono applicate alle risposte dell’origine PendingResponseKind::Response, alle risposte di errore sintetiche generate quando la richiesta in corso non riesce PendingResponseKind::Error, o a entrambe PendingResponseKind::Any. Nei casi in cui la richiesta in corso non riesca, verrà generata una risposta 5XX appropriata e inviata al client. In genere sarà una delle seguenti:
504 Gateway Timeout: restituito automaticamente se la connessione all'origine supera il timeout o se viene raggiunto il First Byte Timeout per il backend.
502 Bad Gateway: restituito se l’origine restituisce un corpo della risposta incompleto o non valido, il backend ha un certificato Transport Layer Security non valido o non funziona e non risponde correttamente.
Puoi usare il grafico “Richieste backend ed errori” nella dashboard di osservabilità del Pannello di controllo Fastly per vedere quali tipi di errori backend sono responsabili delle risposte 502 e 504. Per ulteriori informazioni, consulta Errori di richiesta backend.
Inizia oggi
Non è necessario aspettare di aver distribuito il servizio in produzione per vedere in che modo questa nuova funzionalità può offrire benefici! È pienamente supportato nei recenti rilasci di Viceroy, il nostro ambiente di test locale. Puoi emulare timeout backend di lunga durata, rifattorizzare il codice per usare Request::send_async/PendingRequest::send_to_client ed eseguire il debug delle Operazioni sulle intestazioni in coda direttamente dal terminale di sviluppo locale. Sebbene la funzionalità di handoff sia attualmente esclusiva del nostro SDK Rust (v0.13.0), la estenderemo al resto dei nostri SDK ufficiali. Inoltre, consulta la nostra documentazione per maggiori informazioni e facci sapere cosa stai creando nel nostro forum.

