Quick Framework e algumas Melhorias de Performance


Muito feliz em compartilhar mais melhorias implementadas no Quick Framework, desenvolvido por @jeffotoni. Essas atualizações focam em robustez, performance e suporte a protocolos modernos.

O que foi implementado?

1. Proteção contra WriteHeader Duplicado

Implementamos um wrapper customizado (responseWriter) que previne erros de “superfluous response.WriteHeader”. Agora, múltiplas chamadas a WriteHeader são tratadas silenciosamente, evitando crashes em chains complexas de middleware.

2. Suporte Hijacker

O responseWriter agora implementa a interface http.Hijacker, permitindo upgrades de conexão de forma nativa. Isso habilita comunicação bidirecional em tempo real diretamente através do Quick.

3. HTTP/2 Server Push

Adicionamos suporte à interface http.Pusher com método c.Pusher(), habilitando HTTP/2 Server Push para melhorar performance ao enviar recursos proativamente ao cliente antes mesmo deles serem requisitados, reduzindo latência e round-trips.

Exemplo:

q.Get("https://dev.to/", func(c *quick.Ctx) error {
    pusher, ok := c.Pusher()
    if ok {
        pusher.Push("/static/style.css", nil)
        pusher.Push("/static/app.js", nil)
    }
    return c.Status(200).SendString("<html>...</html>")
})
Enter fullscreen mode

Exit fullscreen mode

4. Server-Sent Events(SSE) Simplificado para Streaming de LLMs

Implementamos o método c.Flusher() que facilita streaming de dados em tempo real, essencial para aplicações modernas com LLMs (Large Language Models). Permite enviar tokens progressivamente conforme são gerados, criando experiências interativas tanto no browser quanto em CLIs.

Casos de uso reais:
Streaming de respostas de ChatGPT, Claude, Gemini
Logs em tempo real de deployments
Atualizações progressivas de dashboards
Notificações push do servidor

Exemplo1:

q.Post("/ai/chat", func(c *quick.Ctx) error {
    c.Set("Content-Type", "text/event-stream")
    c.Set("Cache-Control", "no-cache")
    c.Set("Connection", "keep-alive")

    flusher, ok := c.Flusher()
    if !ok {
        return c.Status(500).SendString("Streaming not supported")
    }

    // Simula streaming de tokens de uma LLM
    tokens := []string{"Hello", " this", " is", " a", " streaming", " response", " from", " AI"}

    for _, token := range tokens {
        // Formato SSE padrão
        fmt.Fprintf(c.Response, "data: %s\n\n", token)
        flusher.Flush() // Envia imediatamente ao cliente
        time.Sleep(100 * time.Millisecond) // Simula latência da LLM
    }

    // Sinaliza fim do stream
    fmt.Fprintf(c.Response, "data: [DONE]\n\n")
    flusher.Flush()
    return nil
})
Enter fullscreen mode

Exit fullscreen mode

Exemplo2:

q.Get("/events", func(c *quick.Ctx) error {
    c.Set("Content-Type", "text/event-stream")
    c.Set("Cache-Control", "no-cache")

    flusher, ok := c.Flusher()
    if !ok {
        return c.Status(500).SendString("Streaming not supported")
    }

    for i := 0; i < 10; i++ {
        fmt.Fprintf(c.Response, "data: Message %d\n\n", i)
        flusher.Flush()
        time.Sleep(time.Second)
    }
    return nil
})
Enter fullscreen mode

Exit fullscreen mode

Cliente JavaScript (Browser):

const eventSource = new EventSource('/ai/chat');
eventSource.onmessage = (event) => {
    if (event.data === '[DONE]') {
        eventSource.close();
        return;
    }
    document.getElementById('response').innerText += event.data;
};
Enter fullscreen mode

Exit fullscreen mode

Cliente CLI (Go):

resp, _ := http.Post("http://localhost:8080/ai/chat", "application/json", body)
reader := bufio.NewReader(resp.Body)
for {
    line, _ := reader.ReadString('\n')
    if strings.Contains(line, "[DONE]") {
        break
    }
    fmt.Print(strings.TrimPrefix(line, "data: "))
}
Enter fullscreen mode

Exit fullscreen mode

Funciona perfeitamente com HTTP/2 multiplexing, permitindo múltiplos streams simultâneos na mesma conexão.

5. Otimização de Pooling

O método Reset() foi otimizado para reusar o wrapper existente ao invés de recriá-lo a cada requisição. Isso reduz alocações de memória no hot path, melhorando throughput.

6. Prevenção de Memory Leaks

Implementamos limpeza completa de contexto no releaseCtx(), incluindo campos Context e wroteHeader, garantindo que nenhum state residual permaneça entre requisições.

Impacto

✅ Maior robustez em cenários de alta concorrência
✅ Suporte nativo a HTTP/2
✅ Server-Sent Events (SSE) facilitado com c.Flusher()
✅ Redução de alocações por requisição
✅ Zero breaking changes e 100% retrocompatível

Todas as mudanças mantêm compatibilidade total com código existente.

Contribuições

Quick é um projeto open-source em constante evolução. Feedbacks e contribuições são sempre bem-vindos!
GitHub: Quick



Source link