Flushing & serverless
flush vs flush_sync/flushSync, the serverless() wrapper, shutdown, and edge caveats.
TokenPolice ships /log telemetry in the background so it never slows your call. In a long-running
server that's invisible. But when the process is about to stop — a serverless function freezing, a
script exiting — you need to drain those pending logs first, or the last calls are lost.
The one asymmetry to remember
| Call | Python | Node |
|---|---|---|
flush() | await flush() — real drain | await tp.flush() — real drain |
flush_sync / flushSync | flush_sync() — real blocking drain | flushSync() — diagnostic only, drains nothing |
Both SDKs have a real drain. The trap is flushSync in Node: it can't block on a promise, so
it does not drain — it's for diagnostics only. Node's real drain is always awaited.
# Python — either of these genuinely drains
import token_police as tp
tp.flush_sync() # blocking, for sync code
# or: await tp.flush() # for async code// Node — the real drain is awaited
import * as tp from "token-police";
await tp.flush();Serverless
Set deployment="serverless" (or leave it "auto" — most platforms are detected). That switches
internal behavior, but it does not flush for you. Two ways to drain before freeze:
Wrap the handler with serverless() — it drains in a finally:
import token_police as tp
@tp.serverless
async def handler(event, context):
... # drained automatically on the way outOr flush yourself in a finally:
export async function handler(event) {
try {
// ... your LLM calls
} finally {
await tp.flush();
}
}Node async handlers get a real drain from serverless() and from await tp.flush(). Node
sync handlers can't await, so durability there comes from keepalive on the /log requests
— the platform keeps them alive briefly after the handler returns.
Scripts and short-lived processes
A script that exits immediately can cut off in-flight logs — and in Node the open rule-stream can keep the event loop alive.
- Python: call
flush_sync()before exit. (Normal exits are also covered automatically.) Python has noshutdown()—flush_sync()is the whole story. - Node: call
await tp.shutdown()— it stops the stream and drains. Without it a short script may hang on the open connection.flushSync()is not a substitute: in Node it drains nothing.
await tp.shutdown(); // Node scripts/CLIs: stops the stream and drainsEdge runtimes
On edge runtimes (deployment="edge"), the underlying instrumentors can't load, so usage
metering is limited to the providers TokenPolice taps manually. Enforcement still works —
the pre-flight /check is a plain fetch and runs everywhere.

