Create a StateTtlConfig with StateTtlConfig.newBuilder(Time.minutes(30)).setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite).setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired).build()
Apply TTL to a state descriptor before registering it: valueStateDescriptor.enableTimeToLive(ttlConfig); do this in the open() method of a RichFunction before calling getRuntimeContext().getState(descriptor)
Choose UpdateType.OnReadAndWrite if state should be refreshed on reads (session-like semantics) or OnCreateAndWrite for strict wall-clock expiry from last write
Set cleanupStrategies: use StateTtlConfig.CleanupStrategies.inRocksdbCompactFilter(1000) with RocksDB backend to expire state lazily during compaction without a full scan
Monitor state size via Flink metrics (numBytesInLocal, rocksdb.estimate-live-data-size) to verify TTL is bounding state growth as expected
Known gotchas
TTL expiry is based on processing time, not event time; if the job processes historical data in bulk, states may be expired prematurely because processing time advances faster than the events' timestamps
Expired state is not immediately removed from RocksDB storage; it accumulates until a compaction filter runs, so heap and disk usage may remain elevated for hours after the TTL expires
Restoring a job from a savepoint taken before TTL was enabled on an existing state descriptor may fail if the savepoint format does not include TTL metadata; add TTL only to newly created state or plan a full state rebuild
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