marko/packages/runtime-class/docs/troubleshooting-streaming.md
2025-07-11 15:35:43 -07:00

3.8 KiB
Raw Permalink Blame History

Troubleshooting HTTP Streams

The way Marko streams HTML is old and well-supported, but default configurations and assumptions by other software can foil it. This page describes some known culprits that may buffer your Node servers output HTTP streams.

Reverse proxies/load balancers

  • Turn off proxy buffering, or if you cant, set the proxy buffer sizes to be reasonably small.

  • Make sure the “upstream” HTTP version is 1.1 or higher; HTTP/1.0 and lower do not support streaming.

  • Some software doesnt support HTTP/2 or higher “upstream” connections at all or very well — if your Node server uses HTTP/2, you may need to downgrade.

  • Check if “upstream” connections are keep-alive: overhead from closing and reopening connections may delay responses.

  • For typical modern webpage filesizes, the following bullet points probably wont matter. But if you want to stream small chunks of data with the lowest latency, investigate these sources of buffering:

NGiNX

Most of NGiNXs relevant parameters are inside its builtin http_proxy module:

proxy_http_version 1.1; # 1.0 by default
proxy_buffering off; # on by default

Apache

Apaches default configuration works fine with streaming, but your host may have it configured differently. The relevant Apache configuration is inside its mod_proxy and mod_proxy_* modules and their associated environment variables.

CDNs

Content Delivery Networks (CDNs) consider efficient streaming one of their best features, but it may be off by default or if certain features are enabled.

Node.js itself

For extreme cases where Node streams very small HTML chunks with its built-in compression modules, you may need to tweak the compressor stream settings. Heres an example with createGzip and its Z_PARTIAL_FLUSH flag:

import http from "http";
import zlib from "zlib";

import MarkoTemplate from "./something.marko";

http
  .createServer(function (request, response) {
    response.writeHead(200, { "content-type": "text/html;charset=utf-8" });
    const templateStream = MarkoTemplate.stream({});
    const gzipStream = zlib.createGzip({
      flush: zlib.constants.Z_PARTIAL_FLUSH,
    });
    templateStream.pipe(outputStream).pipe(response);
  })
  .listen(80);