Build a KStream with a TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(5)) window; note that noGrace means late records are dropped, which is appropriate when downstream consumers cannot handle updates
For use cases requiring late-record acceptance, use TimeWindows.ofSizeAndGrace(Duration.ofMinutes(5), Duration.ofSeconds(30)) to allow a 30-second grace period
Chain .suppress(Suppressed.untilWindowCloses(Suppressed.BufferConfig.unbounded())) after the aggregation to hold results until the window is closed and emit only the final value
Understand that suppress uses stream time (max observed event timestamp) to close windows, not wall-clock time — if the input stream goes idle, windows will never close; add a punctuator as a fallback heartbeat
Configure commit.interval.ms and cache.max.bytes.buffering to control how frequently intermediate results flush before suppression fires
Test by injecting out-of-order events and confirming only one downstream record per window key appears after the grace period expires
Known gotchas
suppress with BufferConfig.unbounded() can cause out-of-memory errors if windows are large and cardinality is high; use BufferConfig.maxBytes(n).shutDownWhenFull() with monitoring in production
Stream time only advances when new records arrive; a topic partition with no traffic will freeze stream time and prevent windows on other partitions from closing — use a synthetic heartbeat record or wall-clock punctuator
Kafka Streams does not distinguish between event-time and processing-time at the API level by default; you must extract the timestamp field and use a TimestampExtractor to drive event-time semantics
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp