replay a stream.place chat from a jetstream archive streamplace-mcp.fastmcp.app/stats
streamplace-mcp docs limits.md
2.8 kB · 68 lines
Markdown
at main

limits #

One replay spends other people's resources: up to ~150 MB of archive reads from a shared box, a socket on a public Jetstream instance, sixteen HTTP connections in flight. The endpoint is open, so every caller is a stranger. Three layers bound what a stranger can spend; all live in guard.py.

per-caller rate limit #

Tool calls are metered per client address (the first hop of x-forwarded-for behind Horizon's proxy) with a token bucket: a burst of 4, then one call every 2 seconds. initialize and tools/list are not metered, so a client can always connect and see the tools. Over the limit, the call fails with a rate limit error naming the numbers.

Callers behind one NAT share a bucket; a caller with many addresses does not. That is what the global caps are for.

global slots #

Two semaphores cap concurrent expensive work across all sessions:

work slots wait
archive reads 4 10s
socket tails 8 10s

A call that cannot get a slot within the wait fails with a busy error rather than queueing indefinitely. The numbers are first guesses sized to the archive key's 100 Mbps meter (four full replays at once is roughly the meter) and should be retuned from the box's rate_bps metrics, not from this table.

caches #

what keyed by lifetime
segment list archive host forever, topped up incrementally
resolved session the stream argument forever if ended, 30s if live
archive window streamer, window, sealed edge forever if the window ended before the sealed edge, else 60s
handle and account status DID 1h

A sealed window reads the same forever, so a popular historical stream costs the archive one read and every later caller gets it from memory. Caches are per process and bounded by entry count; a redeploy starts cold.

upstream backstops #

The archive key on stream.waow.tech is metered at 100 Mbps; past that the box answers 429 and block fetches back off 1s/2s/4s before failing. The public Jetstream instances are shared infrastructure with their own admission limits; the tail opens one socket per call and closes it when the budget ends.

what is not bounded #

Memory for cached windows (64 entries, each a session's worth of rows) and the size of a single response (limit defaults to 200 messages, maximum 1000). Neither has been measured under load; if the process grows, the window cache is the first place to look.

watching it #

/stats on the hosted server shows this process's counters: calls by tool with p50/p95, why replays stopped, refusals by the limiter and the slots, archive bytes and cache hits, socket time. They reset on deploy. The durable record is Horizon's usage API; scripts/usage.py prints calls, error rate, latency, and callers by client name for a date range.