[{"data":1,"prerenderedAt":1878},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Foperating\u002Ftuning":314,"\u002Fdocs\u002Foperating\u002Ftuning-surround":1873},[4,38,86,149,176,219,257,273],{"title":5,"path":6,"stem":7,"children":8,"icon":37},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17,22,27,32],{"title":10,"path":6,"stem":7,"icon":11},"Getting started","i-lucide-flag",{"title":13,"path":14,"stem":15,"icon":16},"Modules overview","\u002Fdocs\u002Fgetting-started\u002Fmodules-overview","1.docs\u002F1.getting-started\u002F2.modules-overview","i-lucide-boxes",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F3.installation","i-lucide-download",{"title":23,"path":24,"stem":25,"icon":26},"License configuration","\u002Fdocs\u002Fgetting-started\u002Flicense-configuration","1.docs\u002F1.getting-started\u002F4.license-configuration","i-lucide-key-round",{"title":28,"path":29,"stem":30,"icon":31},"Your first app","\u002Fdocs\u002Fgetting-started\u002Ffirst-app","1.docs\u002F1.getting-started\u002F5.first-app","i-lucide-square-play",{"title":33,"path":34,"stem":35,"icon":36},"Project setup","\u002Fdocs\u002Fgetting-started\u002Fproject-setup","1.docs\u002F1.getting-started\u002F6.project-setup","i-lucide-package",false,{"title":39,"path":40,"stem":41,"children":42,"icon":45},"Core Concepts","\u002Fdocs\u002Fconcepts","1.docs\u002F2.concepts\u002F1.index",[43,46,51,56,61,66,71,76,81],{"title":44,"path":40,"stem":41,"icon":45},"Core concepts","i-lucide-book-open",{"title":47,"path":48,"stem":49,"icon":50},"Architecture","\u002Fdocs\u002Fconcepts\u002Farchitecture","1.docs\u002F2.concepts\u002F2.architecture","i-lucide-layers",{"title":52,"path":53,"stem":54,"icon":55},"Exactly-once semantics","\u002Fdocs\u002Fconcepts\u002Fexactly-once","1.docs\u002F2.concepts\u002F3.exactly-once","i-lucide-shield-check",{"title":57,"path":58,"stem":59,"icon":60},"Lanes and parallelism","\u002Fdocs\u002Fconcepts\u002Flanes-and-parallelism","1.docs\u002F2.concepts\u002F4.lanes-and-parallelism","i-lucide-split",{"title":62,"path":63,"stem":64,"icon":65},"State and thread-safety","\u002Fdocs\u002Fconcepts\u002Fstate-and-thread-safety","1.docs\u002F2.concepts\u002F5.state-and-thread-safety","i-lucide-lock",{"title":67,"path":68,"stem":69,"icon":70},"Event time and watermarks","\u002Fdocs\u002Fconcepts\u002Fevent-time-and-watermarks","1.docs\u002F2.concepts\u002F6.event-time-and-watermarks","i-lucide-clock",{"title":72,"path":73,"stem":74,"icon":75},"The configuration model","\u002Fdocs\u002Fconcepts\u002Fconfiguration-model","1.docs\u002F2.concepts\u002F7.configuration-model","i-lucide-sliders-horizontal",{"title":77,"path":78,"stem":79,"icon":80},"The error-handling model","\u002Fdocs\u002Fconcepts\u002Ferror-handling-model","1.docs\u002F2.concepts\u002F8.error-handling-model","i-lucide-triangle-alert",{"title":82,"path":83,"stem":84,"icon":85},"How StoatFlow differs from Kafka Streams","\u002Fdocs\u002Fconcepts\u002Fhow-stoatflow-differs-from-ks","1.docs\u002F2.concepts\u002F9.how-stoatflow-differs-from-ks","i-lucide-arrow-left-right",{"title":87,"path":88,"stem":89,"children":90,"icon":93},"Building Topologies","\u002Fdocs\u002Fbuilding","1.docs\u002F3.building\u002F1.index",[91,94,99,104,109,114,119,124,129,134,139,144],{"title":92,"path":88,"stem":89,"icon":93},"Building topologies","i-lucide-blocks",{"title":95,"path":96,"stem":97,"icon":98},"Error handling and DLQ","\u002Fdocs\u002Fbuilding\u002Ferror-handling-dlq","1.docs\u002F3.building\u002F10.error-handling-dlq","i-lucide-circle-x",{"title":100,"path":101,"stem":102,"icon":103},"State stores","\u002Fdocs\u002Fbuilding\u002Fstate-stores","1.docs\u002F3.building\u002F11.state-stores","i-lucide-database",{"title":105,"path":106,"stem":107,"icon":108},"Testing topologies","\u002Fdocs\u002Fbuilding\u002Ftesting","1.docs\u002F3.building\u002F12.testing","i-lucide-flask-conical",{"title":110,"path":111,"stem":112,"icon":113},"Sources and sinks","\u002Fdocs\u002Fbuilding\u002Fstreams-builder","1.docs\u002F3.building\u002F2.streams-builder","i-lucide-import",{"title":115,"path":116,"stem":117,"icon":118},"KStream and KTable operations","\u002Fdocs\u002Fbuilding\u002Fkstream-ktable","1.docs\u002F3.building\u002F3.kstream-ktable","i-lucide-waypoints",{"title":120,"path":121,"stem":122,"icon":123},"Aggregations","\u002Fdocs\u002Fbuilding\u002Faggregations","1.docs\u002F3.building\u002F4.aggregations","i-lucide-sigma",{"title":125,"path":126,"stem":127,"icon":128},"Windowing","\u002Fdocs\u002Fbuilding\u002Fwindowing","1.docs\u002F3.building\u002F5.windowing","i-lucide-calendar-clock",{"title":130,"path":131,"stem":132,"icon":133},"Joins","\u002Fdocs\u002Fbuilding\u002Fjoins","1.docs\u002F3.building\u002F6.joins","i-lucide-git-merge",{"title":135,"path":136,"stem":137,"icon":138},"The Processor API","\u002Fdocs\u002Fbuilding\u002Fprocessor-api","1.docs\u002F3.building\u002F7.processor-api","i-lucide-cpu",{"title":140,"path":141,"stem":142,"icon":143},"Scheduled sources","\u002Fdocs\u002Fbuilding\u002Fscheduled-sources","1.docs\u002F3.building\u002F8.scheduled-sources","i-lucide-timer",{"title":145,"path":146,"stem":147,"icon":148},"Serdes and Avro","\u002Fdocs\u002Fbuilding\u002Fserdes","1.docs\u002F3.building\u002F9.serdes","i-lucide-binary",{"title":150,"path":151,"stem":152,"children":153,"icon":75},"Configuration","\u002Fdocs\u002Fconfiguration","1.docs\u002F4.configuration\u002F1.index",[154,156,161,166,171],{"title":155,"path":151,"stem":152,"icon":75},"How configuration works",{"title":157,"path":158,"stem":159,"icon":160},"Engine configuration (:core)","\u002Fdocs\u002Fconfiguration\u002Fcore-config","1.docs\u002F4.configuration\u002F2.core-config","i-lucide-settings-2",{"title":162,"path":163,"stem":164,"icon":165},"Runtime configuration (:runtime)","\u002Fdocs\u002Fconfiguration\u002Fruntime-config","1.docs\u002F4.configuration\u002F3.runtime-config","i-lucide-server-cog",{"title":167,"path":168,"stem":169,"icon":170},"Defaults, adaptivity, and presets","\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets","1.docs\u002F4.configuration\u002F4.defaults-and-presets","i-lucide-gauge",{"title":172,"path":173,"stem":174,"icon":175},"Kafka client configuration","\u002Fdocs\u002Fconfiguration\u002Fkafka-client-config","1.docs\u002F4.configuration\u002F5.kafka-client-config","i-lucide-plug",{"title":177,"path":178,"stem":179,"children":180,"icon":183},"Running in Production","\u002Fdocs\u002Fruntime","1.docs\u002F5.runtime\u002F1.index",[181,184,189,194,199,204,209,214],{"title":182,"path":178,"stem":179,"icon":183},"The runtime","i-lucide-server",{"title":185,"path":186,"stem":187,"icon":188},"The REST API","\u002Fdocs\u002Fruntime\u002Frest-api","1.docs\u002F5.runtime\u002F2.rest-api","i-lucide-globe",{"title":190,"path":191,"stem":192,"icon":193},"Health checks","\u002Fdocs\u002Fruntime\u002Fhealth-checks","1.docs\u002F5.runtime\u002F3.health-checks","i-lucide-heart-pulse",{"title":195,"path":196,"stem":197,"icon":198},"Metrics","\u002Fdocs\u002Fruntime\u002Fmetrics","1.docs\u002F5.runtime\u002F4.metrics","i-lucide-activity",{"title":200,"path":201,"stem":202,"icon":203},"Pause and resume","\u002Fdocs\u002Fruntime\u002Fpause-unpause","1.docs\u002F5.runtime\u002F5.pause-unpause","i-lucide-pause",{"title":205,"path":206,"stem":207,"icon":208},"Plugins and lifecycle hooks","\u002Fdocs\u002Fruntime\u002Fplugins","1.docs\u002F5.runtime\u002F6.plugins","i-lucide-puzzle",{"title":210,"path":211,"stem":212,"icon":213},"Docker images","\u002Fdocs\u002Fruntime\u002Fdocker","1.docs\u002F5.runtime\u002F7.docker","i-lucide-container",{"title":215,"path":216,"stem":217,"icon":218},"GraalVM native image","\u002Fdocs\u002Fruntime\u002Fnative-image","1.docs\u002F5.runtime\u002F8.native-image","i-lucide-zap",{"title":220,"path":221,"stem":222,"children":223,"icon":226},"Deploying & Operating","\u002Fdocs\u002Foperating","1.docs\u002F6.operating\u002F1.index",[224,227,232,237,242,247,252],{"title":225,"path":221,"stem":222,"icon":226},"Deploying and operating","i-lucide-life-buoy",{"title":228,"path":229,"stem":230,"icon":231},"Running on Kubernetes","\u002Fdocs\u002Foperating\u002Fkubernetes","1.docs\u002F6.operating\u002F2.kubernetes","i-lucide-ship",{"title":233,"path":234,"stem":235,"icon":236},"High availability","\u002Fdocs\u002Foperating\u002Fhigh-availability","1.docs\u002F6.operating\u002F3.high-availability","i-lucide-copy",{"title":238,"path":239,"stem":240,"icon":241},"Liveness and readiness probes","\u002Fdocs\u002Foperating\u002Fprobes","1.docs\u002F6.operating\u002F4.probes","i-lucide-stethoscope",{"title":243,"path":244,"stem":245,"icon":246},"Observability","\u002Fdocs\u002Foperating\u002Fobservability","1.docs\u002F6.operating\u002F5.observability","i-lucide-telescope",{"title":248,"path":249,"stem":250,"icon":251},"Tuning under load","\u002Fdocs\u002Foperating\u002Ftuning","1.docs\u002F6.operating\u002F6.tuning","i-lucide-sliders",{"title":253,"path":254,"stem":255,"icon":256},"Production checklist","\u002Fdocs\u002Foperating\u002Fproduction-checklist","1.docs\u002F6.operating\u002F7.production-checklist","i-lucide-clipboard-check",{"title":258,"path":259,"stem":260,"children":261,"icon":85},"Migrating from Kafka Streams","\u002Fdocs\u002Fmigration","1.docs\u002F7.migration\u002F1.index",[262,263,268],{"title":258,"path":259,"stem":260,"icon":85},{"title":264,"path":265,"stem":266,"icon":267},"Migration without carrying state","\u002Fdocs\u002Fmigration\u002Fwithout-data-migration","1.docs\u002F7.migration\u002F2.without-data-migration","i-lucide-sparkles",{"title":269,"path":270,"stem":271,"icon":272},"Migration carrying state","\u002Fdocs\u002Fmigration\u002Fwith-data-migration","1.docs\u002F7.migration\u002F3.with-data-migration","i-lucide-database-backup",{"title":274,"path":275,"stem":276,"children":277,"icon":279},"Reference","\u002Fdocs\u002Freference","1.docs\u002F8.reference\u002F1.index",[278,280,285,290,295,300,305,309],{"title":274,"path":275,"stem":276,"icon":279},"i-lucide-list",{"title":281,"path":282,"stem":283,"icon":284},"Configuration reference","\u002Fdocs\u002Freference\u002Fconfiguration-reference","1.docs\u002F8.reference\u002F2.configuration-reference","i-lucide-table",{"title":286,"path":287,"stem":288,"icon":289},"REST API reference","\u002Fdocs\u002Freference\u002Frest-api-reference","1.docs\u002F8.reference\u002F3.rest-api-reference","i-lucide-network",{"title":291,"path":292,"stem":293,"icon":294},"Gradle plugin reference","\u002Fdocs\u002Freference\u002Fgradle-plugin-reference","1.docs\u002F8.reference\u002F4.gradle-plugin-reference","i-lucide-box",{"title":296,"path":297,"stem":298,"icon":299},"Maven reference","\u002Fdocs\u002Freference\u002Fmaven-reference","1.docs\u002F8.reference\u002F5.maven-reference","i-simple-icons-apachemaven",{"title":301,"path":302,"stem":303,"icon":304},"Kafka Streams compatibility matrix","\u002Fdocs\u002Freference\u002Fks-compatibility-matrix","1.docs\u002F8.reference\u002F6.ks-compatibility-matrix","i-lucide-table-2",{"title":306,"path":307,"stem":308,"icon":170},"Metrics reference","\u002Fdocs\u002Freference\u002Fmetrics-reference","1.docs\u002F8.reference\u002F7.metrics-reference",{"title":310,"path":311,"stem":312,"icon":313},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","1.docs\u002F8.reference\u002F8.glossary","i-lucide-book-a",{"id":315,"title":248,"body":316,"description":1866,"extension":1867,"meta":1868,"navigation":1869,"pageType":1870,"path":249,"seo":1871,"stem":250,"__hash__":1872},"docs\u002F1.docs\u002F6.operating\u002F6.tuning.md",{"type":317,"value":318,"toc":1849},"minimark",[319,328,351,410,415,430,451,455,468,471,514,517,537,600,609,614,624,627,654,658,672,677,745,760,810,813,834,887,902,906,909,954,990,994,1001,1012,1015,1046,1076,1079,1130,1141,1204,1208,1228,1248,1251,1255,1262,1271,1324,1353,1365,1392,1450,1454,1464,1487,1491,1501,1769,1773,1776,1808,1811,1815,1845],[320,321,322,323,327],"p",{},"StoatFlow ships with defaults that work for most topologies, and the parts that need to adapt to your workload — commit cadence and epoch size — self-tune within the bounds you set. This page covers the knobs you do set: lane count, the commit-cadence bounds, the memory and uncommitted-state limits, and RocksDB sizing. Each section starts from a ",[324,325,326],"strong",{},"symptom"," so you know when to reach for it.",[320,329,330,331,334,335,338,339,342,343,346,347,350],{},"For the why behind these mechanics, see ",[332,333,57],"a",{"href":58},", ",[332,336,337],{"href":53},"Exactly-once",", and ",[332,340,341],{"href":63},"State and thread safety",". For where each value comes from and how it's merged, see the ",[332,344,345],{"href":73},"Configuration model"," and ",[332,348,349],{"href":168},"Defaults and presets",".",[352,353,354],"tldr-panel",{},[355,356,357,364,378,388],"ul",{},[358,359,360,363],"li",{},[324,361,362],{},"Lane count"," scales per-key parallelism — start at CPU cores, raise it when processing is I\u002FO-bound, not CPU-bound.",[358,365,366,369,370,346,374,377],{},[324,367,368],{},"Commit cadence self-tunes"," between ",[371,372,373],"code",{},"commit-barrier.min-interval-ms",[371,375,376],{},"max-interval-ms",". You set the bounds; the engine picks the cadence inside them.",[358,379,380,383,384,387],{},[324,381,382],{},"Uncommitted state"," is bounded by ",[371,385,386],{},"state.uncommitted-max-bytes"," — the limit that protects you from OOM on stateful, high-fan-out topologies.",[358,389,390,393,394,397,398,401,402,405,406,409],{},[324,391,392],{},"RocksDB memory"," is a preset (",[371,395,396],{},"rocks-db.preset","): ",[371,399,400],{},"DEFAULT"," (256 MB), ",[371,403,404],{},"LOW_MEMORY"," (64 MB), ",[371,407,408],{},"HIGH_PERFORMANCE"," (1 GB).",[411,412,414],"h2",{"id":413},"before-you-tune","Before you tune",[320,416,417,418,421,422,425,426,429],{},"Tune one thing at a time, and tune against a representative load, not a synthetic burst. The defaults are deliberately conservative; most workloads need at most one or two of the knobs below. Always confirm the symptom first — reach for ",[371,419,420],{},"\u002Fmetrics"," and the ",[371,423,424],{},"\u002Fdebug\u002Fbarriers"," endpoint (see ",[332,427,428],{"href":186},"REST API",") rather than guessing.",[431,432,434],"callout",{"color":433,"icon":108},"warning",[320,435,436,437,440,441,444,445,448,449,350],{},"All values below are the ",[324,438,439],{},"defaults from the engine config",". Every knob has a YAML key under ",[371,442,443],{},"stoatflow.*"," and an environment-variable override (",[371,446,447],{},"STOATFLOW__\u003CSECTION>__\u003CKEY>","). The full list — with types, ranges, and overrides — is in the ",[332,450,281],{"href":282},[411,452,454],{"id":453},"lane-count-vs-cores","Lane count vs cores",[320,456,457,460,461,464,465,350],{},[324,458,459],{},"Knob:"," ",[371,462,463],{},"stoatflow.lanes.count"," — default ",[371,466,467],{},"max(2, CPU cores)",[320,469,470],{},"Lanes are the unit of per-key parallelism: every record is routed to a lane by its key, and each lane is a virtual thread that processes its keys in order. More lanes means more keys processed concurrently, at the cost of more queues and a little more dispatch overhead.",[472,473,478],"pre",{"className":474,"code":475,"language":476,"meta":477,"style":477},"language-yaml shiki shiki-themes vitesse-light","stoatflow:\n  lanes:\n    count: 16\n","yaml","",[371,479,480,493,501],{"__ignoreMap":477},[481,482,485,489],"span",{"class":483,"line":484},"line",1,[481,486,488],{"class":487},"su6XF","stoatflow",[481,490,492],{"class":491},"sYZai",":\n",[481,494,496,499],{"class":483,"line":495},2,[481,497,498],{"class":487},"  lanes",[481,500,492],{"class":491},[481,502,504,507,510],{"class":483,"line":503},3,[481,505,506],{"class":487},"    count",[481,508,509],{"class":491},":",[481,511,513],{"class":512},"s-TwI"," 16\n",[320,515,516],{},"How to size it:",[355,518,519,525,531],{},[358,520,521,524],{},[324,522,523],{},"CPU-bound processing"," (pure transforms, local aggregation): start at the number of CPU cores. Going much higher just adds scheduling overhead without more throughput, because the work is already saturating the cores.",[358,526,527,530],{},[324,528,529],{},"I\u002FO-bound processing"," (enrichment calls, blocking lookups, external APIs): go well above core count — virtual threads park cheaply while blocked, so 4×–8× cores keeps cores busy while many lanes wait on I\u002FO. This is the case where raising the lane count pays off most.",[358,532,533,536],{},[324,534,535],{},"Few distinct keys:"," lanes only help if keys spread across them. If your traffic is dominated by a handful of hot keys, extra lanes sit idle — the hot keys still serialize onto their assigned lanes. Fix the key distribution first.",[538,539,540,556],"table",{},[541,542,543],"thead",{},[544,545,546,550,553],"tr",{},[547,548,549],"th",{},"Symptom",[547,551,552],{},"Likely cause",[547,554,555],{},"Reach for",[557,558,559,575,589],"tbody",{},[544,560,561,565,568],{},[562,563,564],"td",{},"Cores underused, throughput plateaus, processing involves blocking calls",[562,566,567],{},"Too few lanes for an I\u002FO-bound topology",[562,569,570,571,574],{},"Raise ",[371,572,573],{},"lanes.count"," (4×–8× cores)",[544,576,577,580,583],{},[562,578,579],{},"High CPU, lots of context switching, no throughput gain from more lanes",[562,581,582],{},"Over-provisioned lanes for CPU-bound work",[562,584,585,586,588],{},"Lower ",[371,587,573],{}," toward core count",[544,590,591,594,597],{},[562,592,593],{},"A few keys dominate; most lanes idle",[562,595,596],{},"Skewed key distribution, not a lane-count problem",[562,598,599],{},"Re-key upstream; lane count won't help",[431,601,604],{"color":602,"icon":603},"info","i-lucide-info",[320,605,606,607,350],{},"Lane count is fixed at startup and cannot be changed while running — it's part of the engine's single-instance topology. Changing it requires a restart. See ",[332,608,57],{"href":58},[610,611,613],"h3",{"id":612},"lane-queue-capacity","Lane queue capacity",[320,615,616,460,618,464,621,350],{},[324,617,459],{},[371,619,620],{},"stoatflow.lanes.queue-capacity",[371,622,623],{},"300",[320,625,626],{},"Each lane has a bounded queue; when a lane fills, the dispatcher applies backpressure. Raise it if you see bursty input stalling dispatch and you have memory headroom; the default is sufficient for steady-state load.",[472,628,630],{"className":474,"code":629,"language":476,"meta":477,"style":477},"stoatflow:\n  lanes:\n    queue-capacity: 500\n",[371,631,632,638,644],{"__ignoreMap":477},[481,633,634,636],{"class":483,"line":484},[481,635,488],{"class":487},[481,637,492],{"class":491},[481,639,640,642],{"class":483,"line":495},[481,641,498],{"class":487},[481,643,492],{"class":491},[481,645,646,649,651],{"class":483,"line":503},[481,647,648],{"class":487},"    queue-capacity",[481,650,509],{"class":491},[481,652,653],{"class":512}," 500\n",[411,655,657],{"id":656},"commit-cadence","Commit cadence",[320,659,660,661,664,665,667,668,671],{},"StoatFlow commits in ",[324,662,663],{},"epochs"," — the work between two commit barriers becomes one Kafka transaction plus one state-store flush (see ",[332,666,337],{"href":53},"). The cadence — how often a barrier fires — is ",[324,669,670],{},"self-tuning",": the engine adapts it within the bounds you configure, so you set the envelope, not the exact interval. The algorithm itself stays in the source; what you control is the floor and ceiling.",[320,673,674],{},[324,675,676],{},"The bounds you set:",[538,678,679,692],{},[541,680,681],{},[544,682,683,686,689],{},[547,684,685],{},"Knob",[547,687,688],{},"YAML key",[547,690,691],{},"What it does",[557,693,694,707,720,732],{},[544,695,696,699,704],{},[562,697,698],{},"Seed interval",[562,700,701],{},[371,702,703],{},"commit-barrier.interval-ms",[562,705,706],{},"Starting interval before the cadence settles",[544,708,709,712,717],{},[562,710,711],{},"Interval factor",[562,713,714],{},[371,715,716],{},"commit-barrier.interval-factor",[562,718,719],{},"Target interval as a multiple of measured commit duration",[544,721,722,725,729],{},[562,723,724],{},"Minimum interval",[562,726,727],{},[371,728,373],{},[562,730,731],{},"Floor — barriers never fire closer together than this",[544,733,734,737,742],{},[562,735,736],{},"Maximum interval",[562,738,739],{},[371,740,741],{},"commit-barrier.max-interval-ms",[562,743,744],{},"Ceiling — barriers never fire further apart than this",[320,746,747,748,751,752,755,756,350],{},"Defaults and ",[371,749,750],{},"StreamsConfig"," field names for every ",[371,753,754],{},"commit-barrier.*"," knob are in ",[332,757,759],{"href":758},"\u002Fdocs\u002Fconfiguration\u002Fcore-config#commit-barrier-cadence","Engine configuration → Commit-barrier cadence",[472,761,763],{"className":474,"code":762,"language":476,"meta":477,"style":477},"stoatflow:\n  commit-barrier:\n    min-interval-ms: 150\n    max-interval-ms: 5000\n    interval-factor: 1.5\n",[371,764,765,771,778,788,799],{"__ignoreMap":477},[481,766,767,769],{"class":483,"line":484},[481,768,488],{"class":487},[481,770,492],{"class":491},[481,772,773,776],{"class":483,"line":495},[481,774,775],{"class":487},"  commit-barrier",[481,777,492],{"class":491},[481,779,780,783,785],{"class":483,"line":503},[481,781,782],{"class":487},"    min-interval-ms",[481,784,509],{"class":491},[481,786,787],{"class":512}," 150\n",[481,789,791,794,796],{"class":483,"line":790},4,[481,792,793],{"class":487},"    max-interval-ms",[481,795,509],{"class":491},[481,797,798],{"class":512}," 5000\n",[481,800,802,805,807],{"class":483,"line":801},5,[481,803,804],{"class":487},"    interval-factor",[481,806,509],{"class":491},[481,808,809],{"class":512}," 1.5\n",[320,811,812],{},"The trade-off is the classic latency-vs-throughput one:",[355,814,815,828],{},[358,816,817,820,821,823,824,827],{},[324,818,819],{},"Tighter, more frequent commits"," (lower ",[371,822,376],{},", lower ",[371,825,826],{},"interval-factor",") reduce end-to-end latency and bound how much work a crash replays — at the cost of more transaction and flush overhead per record.",[358,829,830,833],{},[324,831,832],{},"Looser, less frequent commits"," (higher bounds) amortize commit overhead over more records, raising throughput — at the cost of higher latency and a larger replay window after a restart.",[538,835,836,846],{},[541,837,838],{},[544,839,840,842,844],{},[547,841,549],{},[547,843,552],{},[547,845,555],{},[557,847,848,864,876],{},[544,849,850,853,856],{},[562,851,852],{},"End-to-end latency too high; output lags input",[562,854,855],{},"Cadence too loose; records wait for the next barrier",[562,857,585,858,860,861,863],{},[371,859,376],{}," (and\u002For ",[371,862,826],{},")",[544,865,866,869,872],{},[562,867,868],{},"Throughput capped; commit overhead dominates a profile",[562,870,871],{},"Cadence too tight for the volume",[562,873,570,874],{},[371,875,376],{},[544,877,878,881,884],{},[562,879,880],{},"Output is bursty in lockstep with commits",[562,882,883],{},"Working as designed — output is released at barriers",[562,885,886],{},"Tighten cadence if the burstiness hurts downstream",[431,888,889],{"color":602,"icon":603},[320,890,891,894,895,898,899,350],{},[371,892,893],{},"commit-barrier.timeout-ms"," is a ",[324,896,897],{},"safety bound",", not a cadence knob. It caps how long a commit may take; if a commit stalls past it, the engine aborts the in-flight transaction and the process restarts rather than freezing silently. Don't lower it to force faster commits — see ",[332,900,901],{"href":239},"Probes",[610,903,905],{"id":904},"epoch-size","Epoch size",[320,907,908],{},"You normally don't touch epoch size — it self-tunes within the bounds above. Two knobs exist for the edges:",[538,910,911,922],{},[541,912,913],{},[544,914,915,917,919],{},[547,916,685],{},[547,918,688],{},[547,920,921],{},"When to use",[557,923,924,937],{},[544,925,926,929,934],{},[562,927,928],{},"Hard cap on records per epoch",[562,930,931],{},[371,932,933],{},"commit-barrier.max-epoch-records",[562,935,936],{},"Unset by default (no cap) — set only if you need a deterministic upper bound on epoch size regardless of self-tuning",[544,938,939,942,947],{},[562,940,941],{},"Initial cap before warmup",[562,943,944],{},[371,945,946],{},"commit-barrier.initial-max-epoch-records",[562,948,949,950,953],{},"Lower for conservative startup on heavy-state topologies; ",[371,951,952],{},"-1"," for an unlimited first epoch",[472,955,957],{"className":474,"code":956,"language":476,"meta":477,"style":477},"stoatflow:\n  commit-barrier:\n    initial-max-epoch-records: 1024   # conservative startup for heavy-state topologies\n    # max-epoch-records: 25000        # optional deterministic ceiling\n",[371,958,959,965,971,985],{"__ignoreMap":477},[481,960,961,963],{"class":483,"line":484},[481,962,488],{"class":487},[481,964,492],{"class":491},[481,966,967,969],{"class":483,"line":495},[481,968,775],{"class":487},[481,970,492],{"class":491},[481,972,973,976,978,981],{"class":483,"line":503},[481,974,975],{"class":487},"    initial-max-epoch-records",[481,977,509],{"class":491},[481,979,980],{"class":512}," 1024",[481,982,984],{"class":983},"s8zF2","   # conservative startup for heavy-state topologies\n",[481,986,987],{"class":483,"line":790},[481,988,989],{"class":983},"    # max-epoch-records: 25000        # optional deterministic ceiling\n",[411,991,993],{"id":992},"memory-and-uncommitted-state","Memory and uncommitted state",[320,995,996,997,1000],{},"Between commits, a stateful topology accumulates ",[324,998,999],{},"uncommitted state"," in memory — the writes buffered since the last barrier, held until the transaction commits (KIP-892 transactional state stores). On topologies where one input record fans out into many state writes (multi-way joins, foreign-key joins, high-cardinality aggregations), this is the value most likely to threaten container memory.",[320,1002,1003,460,1005,464,1008,1011],{},[324,1004,459],{},[371,1006,1007],{},"stoatflow.state.uncommitted-max-bytes",[371,1009,1010],{},"268435456"," (256 MB).",[320,1013,1014],{},"When buffered uncommitted bytes approach this limit, the engine triggers an early commit barrier to flush state and bound peak memory. This is the backstop that keeps a high-fan-out epoch from running the container out of memory.",[472,1016,1018],{"className":474,"code":1017,"language":476,"meta":477,"style":477},"stoatflow:\n  state:\n    uncommitted-max-bytes: 268435456   # 256 MB (default)\n",[371,1019,1020,1026,1033],{"__ignoreMap":477},[481,1021,1022,1024],{"class":483,"line":484},[481,1023,488],{"class":487},[481,1025,492],{"class":491},[481,1027,1028,1031],{"class":483,"line":495},[481,1029,1030],{"class":487},"  state",[481,1032,492],{"class":491},[481,1034,1035,1038,1040,1043],{"class":483,"line":503},[481,1036,1037],{"class":487},"    uncommitted-max-bytes",[481,1039,509],{"class":491},[481,1041,1042],{"class":512}," 268435456",[481,1044,1045],{"class":983},"   # 256 MB (default)\n",[320,1047,1048,1049,1052,1053,1056,1057,1060,1061,1064,1065,1068,1069,1072,1073,1075],{},"The global ceiling has two ",[324,1050,1051],{},"per-store"," companions under ",[371,1054,1055],{},"stoatflow.caching",": ",[371,1058,1059],{},"max-estimated-bytes"," (default 256 MB per caching store) and ",[371,1062,1063],{},"max-entries"," (default unbounded). Exceeding a per-store cap fires the same early commit barrier — tagged ",[371,1066,1067],{},"CACHE_PRESSURE"," on the barrier-trigger metric — so one hot store can't monopolise the buffer. In practice ",[371,1070,1071],{},"uncommitted-max-bytes"," measures a superset and fires first; leave ",[371,1074,1063],{}," unbounded unless a specific store must bound its per-epoch key cardinality.",[320,1077,1078],{},"Sizing it against the container:",[538,1080,1081,1095],{},[541,1082,1083],{},[544,1084,1085,1088,1092],{},[547,1086,1087],{},"Container memory limit",[547,1089,1090],{},[371,1091,1071],{},[547,1093,1094],{},"Rationale",[557,1096,1097,1108,1119],{},[544,1098,1099,1102,1105],{},[562,1100,1101],{},"4 GiB",[562,1103,1104],{},"~1 GiB",[562,1106,1107],{},"Leaves headroom for heap, RocksDB, Kafka client buffers, and GC",[544,1109,1110,1113,1116],{},[562,1111,1112],{},"8 GiB",[562,1114,1115],{},"1–2 GiB",[562,1117,1118],{},"More room for GC and producer buffers",[544,1120,1121,1124,1127],{},[562,1122,1123],{},"16 GiB",[562,1125,1126],{},"2–4 GiB",[562,1128,1129],{},"Production sizing for heavy stateful topologies",[431,1131,1132],{"color":433,"icon":80},[320,1133,1134,1136,1137,1140],{},[371,1135,1071],{}," is one of several memory consumers in the process — it does ",[324,1138,1139],{},"not"," account for the JVM heap, the RocksDB memory budget (next section), or the Kafka producer's send buffer. On small-heap deployments with both heavy state writes and heavy sink output, leave generous headroom and watch container memory before raising it.",[538,1142,1143,1153],{},[541,1144,1145],{},[544,1146,1147,1149,1151],{},[547,1148,549],{},[547,1150,552],{},[547,1152,555],{},[557,1154,1155,1168,1192],{},[544,1156,1157,1160,1163],{},[562,1158,1159],{},"Container memory spikes near the limit; OOMKills under load",[562,1161,1162],{},"Uncommitted state per epoch too large for the container",[562,1164,585,1165,1167],{},[371,1166,1071],{},", or raise the container limit if you have hardware",[544,1169,1170,1173,1183],{},[562,1171,1172],{},"Very frequent commits; throughput suffers on a stateful topology",[562,1174,1175,1176,1179,1180,1182],{},"Early barriers firing on memory pressure (",[371,1177,1178],{},"MEMORY_PRESSURE"," trigger) or a per-store cache cap (",[371,1181,1067],{}," trigger) — the barrier-trigger metric tells you which",[562,1184,570,1185,1187,1188,1191],{},[371,1186,1071],{},", or the tripping store's ",[371,1189,1190],{},"caching.max-estimated-bytes"," (only if the container has the headroom)",[544,1193,1194,1197,1200],{},[562,1195,1196],{},"Slow time-to-first-commit on a heavy-state topology at startup",[562,1198,1199],{},"First epoch buffering too much before warmup",[562,1201,585,1202],{},[371,1203,946],{},[411,1205,1207],{"id":1206},"segmented-store-checkpoint-cadence","Segmented-store checkpoint cadence",[320,1209,1210,1211,1215,1216,1219,1220,1223,1224,1227],{},"Time-windowed and session stores are ",[1212,1213,1214],"em",{},"segmented",", and their RocksDB segments run with the write-ahead log off — so they only become durable on a clean ",[371,1217,1218],{},"close()",". A periodic checkpoint (flush dirty segments, then the offsets) makes them durable between commits and caps how much changelog a pod replays after an ",[1212,1221,1222],{},"ungraceful"," restart, and how much a ",[332,1225,1226],{"href":234},"hot-standby"," standby drains on promotion — to at most one checkpoint interval.",[320,1229,1230,460,1233,1236,1237,1240,1241,1236,1244,1247],{},[324,1231,1232],{},"Knobs:",[371,1234,1235],{},"stoatflow.state.segment-checkpoint-records"," (default ",[371,1238,1239],{},"100000",") and ",[371,1242,1243],{},"stoatflow.state.segment-checkpoint-ms",[371,1245,1246],{},"30000","), whichever fires first.",[320,1249,1250],{},"The defaults are deliberately coarse: a checkpoint flushes SST files, so a tight cadence trades a smaller recovery window against more SST\u002Fcompaction churn in steady state. Lower them only if your recovery-time objective needs a shorter ungraceful-restart catch-up than ~30 s \u002F 100k records of windowed writes; raise them if you see checkpoint-driven write amplification and can absorb a longer catch-up.",[411,1252,1254],{"id":1253},"rocksdb-for-large-state","RocksDB for large state",[320,1256,1257,1258,1261],{},"Persistent state lives in RocksDB. Unlike Kafka Streams' unbounded default, StoatFlow caps RocksDB memory by default to keep the process within its container. You pick a ",[324,1259,1260],{},"preset","; the framework wires the block cache and memtable budget for you.",[320,1263,1264,460,1266,464,1269,350],{},[324,1265,459],{},[371,1267,1268],{},"stoatflow.rocks-db.preset",[371,1270,400],{},[538,1272,1273,1286],{},[541,1274,1275],{},[544,1276,1277,1280,1283],{},[547,1278,1279],{},"Preset",[547,1281,1282],{},"Total RocksDB memory",[547,1284,1285],{},"Use for",[557,1287,1288,1300,1312],{},[544,1289,1290,1294,1297],{},[562,1291,1292],{},[371,1293,404],{},[562,1295,1296],{},"64 MB",[562,1298,1299],{},"Constrained containers, small state",[544,1301,1302,1306,1309],{},[562,1303,1304],{},[371,1305,400],{},[562,1307,1308],{},"256 MB",[562,1310,1311],{},"Most workloads",[544,1313,1314,1318,1321],{},[562,1315,1316],{},[371,1317,408],{},[562,1319,1320],{},"1 GB",[562,1322,1323],{},"Large state, read-heavy access patterns, high throughput",[472,1325,1327],{"className":474,"code":1326,"language":476,"meta":477,"style":477},"stoatflow:\n  rocks-db:\n    preset: HIGH_PERFORMANCE\n",[371,1328,1329,1335,1342],{"__ignoreMap":477},[481,1330,1331,1333],{"class":483,"line":484},[481,1332,488],{"class":487},[481,1334,492],{"class":491},[481,1336,1337,1340],{"class":483,"line":495},[481,1338,1339],{"class":487},"  rocks-db",[481,1341,492],{"class":491},[481,1343,1344,1347,1349],{"class":483,"line":503},[481,1345,1346],{"class":487},"    preset",[481,1348,509],{"class":491},[481,1350,1352],{"class":1351},"spphp"," HIGH_PERFORMANCE\n",[320,1354,1355,1356,1358,1359,1361,1362,1364],{},"When state grows large (millions of keys, hot read paths), ",[371,1357,400],{},"'s 256 MB block cache becomes a bottleneck: working-set reads start missing the cache and hit disk. ",[371,1360,408],{}," widens both the block cache and the memtable budget. Budget for it — it is real resident memory on top of the JVM heap and ",[371,1363,1071],{},", so size the container accordingly.",[320,1366,1367,1370,1371,1375,1376,1379,1380,1383,1384,1387,1388,1391],{},[324,1368,1369],{},"Confirm the diagnosis before you resize."," Enable the ",[332,1372,1374],{"href":1373},"\u002Fdocs\u002Foperating\u002Fobservability#rocksdb-metrics","RocksDB metrics"," (",[371,1377,1378],{},"rocks-db.metrics.enabled"," + ",[371,1381,1382],{},"statistics-enabled",") and watch ",[371,1385,1386],{},"stoatflow_rocksdb_block_cache_hit_ratio"," under load: a ratio falling toward the floor while ",[371,1389,1390],{},"stoatflow_rocksdb_shared_block_cache_usage_bytes"," sits at capacity is the signal that the cache is too small — the metric that turns the symptom below from a guess into a measurement.",[538,1393,1394,1404],{},[541,1395,1396],{},[544,1397,1398,1400,1402],{},[547,1399,549],{},[547,1401,552],{},[547,1403,555],{},[557,1405,1406,1422,1435],{},[544,1407,1408,1414,1417],{},[562,1409,1410,1411,863],{},"Read latency climbs as state grows; disk I\u002FO high (falling ",[371,1412,1413],{},"block.cache.hit.ratio",[562,1415,1416],{},"Block cache too small for the working set",[562,1418,1419],{},[371,1420,1421],{},"rocks-db.preset: HIGH_PERFORMANCE",[544,1423,1424,1427,1430],{},[562,1425,1426],{},"Memory tight on a small container with modest state",[562,1428,1429],{},"RocksDB budget larger than needed",[562,1431,1432],{},[371,1433,1434],{},"rocks-db.preset: LOW_MEMORY",[544,1436,1437,1440,1443],{},[562,1438,1439],{},"Need a budget between the presets",[562,1441,1442],{},"Preset granularity too coarse",[562,1444,1445,1446,1449],{},"Set a custom total via a programmatic ",[371,1447,1448],{},"RocksDBConfig"," (see below)",[610,1451,1453],{"id":1452},"backend-selection","Backend selection",[320,1455,1456,460,1458,464,1461,350],{},[324,1457,459],{},[371,1459,1460],{},"stoatflow.rocks-db.backend",[371,1462,1463],{},"AUTO",[320,1465,1466,1468,1469,1472,1473,1476,1477,1479,1480,1482,1483,1486],{},[371,1467,1463],{}," picks each runtime's faster path: the ",[371,1470,1471],{},"FFM"," (Foreign Function & Memory API) backend on the JVM — lower per-call overhead than JNI and no virtual-thread pinning during native RocksDB calls — and ",[371,1474,1475],{},"JNI"," under a native image, where FFM's critical-downcall advantage doesn't apply. Leave it on ",[371,1478,1463],{}," unless you have a specific reason to pin a backend; if you force ",[371,1481,1475],{}," on the JVM, also set ",[371,1484,1485],{},"stoatflow.lanes.thread-type: PLATFORM"," to avoid pinning carrier threads.",[610,1488,1490],{"id":1489},"custom-rocksdb-budget-programmatic","Custom RocksDB budget (programmatic)",[320,1492,1493,1494,1496,1497,1500],{},"The YAML preset is the supported path for most deployments. If you need a memory budget between the presets, set ",[371,1495,1448],{}," directly when building the engine config — ",[371,1498,1499],{},"RocksDBConfig.withTotalMemory(...)"," splits the budget evenly between block cache and memtables:",[1502,1503,1505,1614],"code-tabs",{"group":1504},"lang",[472,1506,1511],{"className":1507,"code":1508,"filename":1509,"language":1510,"meta":477,"style":477},"language-kotlin shiki shiki-themes vitesse-light","import io.stoatflow.core.config.StreamsConfig\nimport io.stoatflow.core.state.rocksdb.RocksDBConfig\n\nval config = StreamsConfig.builder(\"my-app\", \"localhost:9092\")\n    .rocksDbConfig(RocksDBConfig.withTotalMemory(512L * 1024 * 1024)) \u002F\u002F 512 MB total\n    .build()\n","Kotlin","kotlin",[371,1512,1513,1523,1530,1536,1568,1603],{"__ignoreMap":477},[481,1514,1515,1519],{"class":483,"line":484},[481,1516,1518],{"class":1517},"sbBg2","import",[481,1520,1522],{"class":1521},"sySUi"," io.stoatflow.core.config.StreamsConfig\n",[481,1524,1525,1527],{"class":483,"line":495},[481,1526,1518],{"class":1517},[481,1528,1529],{"class":1521}," io.stoatflow.core.state.rocksdb.RocksDBConfig\n",[481,1531,1532],{"class":483,"line":503},[481,1533,1535],{"emptyLinePlaceholder":1534},true,"\n",[481,1537,1538,1541,1545,1548,1551,1554,1557,1560,1562,1565],{"class":483,"line":790},[481,1539,1540],{"class":1517},"val",[481,1542,1544],{"class":1543},"suHK_"," config ",[481,1546,1547],{"class":491},"=",[481,1549,1550],{"class":1543}," StreamsConfig.",[481,1552,1553],{"class":1521},"builder",[481,1555,1556],{"class":1543},"(",[481,1558,1559],{"class":1351},"\"my-app\"",[481,1561,334],{"class":1543},[481,1563,1564],{"class":1351},"\"localhost:9092\"",[481,1566,1567],{"class":1543},")\n",[481,1569,1570,1573,1576,1579,1582,1584,1587,1591,1593,1595,1597,1600],{"class":483,"line":801},[481,1571,1572],{"class":1543},"    .",[481,1574,1575],{"class":1521},"rocksDbConfig",[481,1577,1578],{"class":1543},"(RocksDBConfig.",[481,1580,1581],{"class":1521},"withTotalMemory",[481,1583,1556],{"class":1543},[481,1585,1586],{"class":512},"512L",[481,1588,1590],{"class":1589},"si04Y"," *",[481,1592,980],{"class":512},[481,1594,1590],{"class":1589},[481,1596,980],{"class":512},[481,1598,1599],{"class":1543},")) ",[481,1601,1602],{"class":983},"\u002F\u002F 512 MB total\n",[481,1604,1606,1608,1611],{"class":483,"line":1605},6,[481,1607,1572],{"class":1543},[481,1609,1610],{"class":1521},"build",[481,1612,1613],{"class":1543},"()\n",[472,1615,1620],{"className":1616,"code":1617,"filename":1618,"language":1619,"meta":477,"style":477},"language-java shiki shiki-themes vitesse-light","import io.stoatflow.core.config.StreamsConfig;\nimport io.stoatflow.core.state.rocksdb.RocksDBConfig;\n\nvar config = StreamsConfig.builder(\"my-app\", \"localhost:9092\")\n    .rocksDbConfig(RocksDBConfig.withTotalMemory(512L * 1024 * 1024L)) \u002F\u002F 512 MB total\n    .build();\n","Java","java",[371,1621,1622,1650,1680,1684,1727,1760],{"__ignoreMap":477},[481,1623,1624,1626,1629,1631,1633,1635,1638,1640,1643,1645,1647],{"class":483,"line":484},[481,1625,1518],{"class":1517},[481,1627,1628],{"class":1543}," io",[481,1630,350],{"class":491},[481,1632,488],{"class":1543},[481,1634,350],{"class":491},[481,1636,1637],{"class":1543},"core",[481,1639,350],{"class":491},[481,1641,1642],{"class":1543},"config",[481,1644,350],{"class":491},[481,1646,750],{"class":1543},[481,1648,1649],{"class":491},";\n",[481,1651,1652,1654,1656,1658,1660,1662,1664,1666,1669,1671,1674,1676,1678],{"class":483,"line":495},[481,1653,1518],{"class":1517},[481,1655,1628],{"class":1543},[481,1657,350],{"class":491},[481,1659,488],{"class":1543},[481,1661,350],{"class":491},[481,1663,1637],{"class":1543},[481,1665,350],{"class":491},[481,1667,1668],{"class":1543},"state",[481,1670,350],{"class":491},[481,1672,1673],{"class":1543},"rocksdb",[481,1675,350],{"class":491},[481,1677,1448],{"class":1543},[481,1679,1649],{"class":491},[481,1681,1682],{"class":483,"line":503},[481,1683,1535],{"emptyLinePlaceholder":1534},[481,1685,1686,1689,1693,1696,1699,1701,1703,1705,1709,1712,1714,1717,1720,1723,1725],{"class":483,"line":790},[481,1687,1688],{"class":1589},"var",[481,1690,1692],{"class":1691},"svycV"," config",[481,1694,1695],{"class":491}," =",[481,1697,1698],{"class":1691}," StreamsConfig",[481,1700,350],{"class":491},[481,1702,1553],{"class":1521},[481,1704,1556],{"class":491},[481,1706,1708],{"class":1707},"sSP4y","\"",[481,1710,1711],{"class":1351},"my-app",[481,1713,1708],{"class":1707},[481,1715,1716],{"class":491},",",[481,1718,1719],{"class":1707}," \"",[481,1721,1722],{"class":1351},"localhost:9092",[481,1724,1708],{"class":1707},[481,1726,1567],{"class":491},[481,1728,1729,1731,1733,1735,1737,1739,1741,1743,1745,1747,1749,1751,1754,1757],{"class":483,"line":801},[481,1730,1572],{"class":491},[481,1732,1575],{"class":1521},[481,1734,1556],{"class":491},[481,1736,1448],{"class":1691},[481,1738,350],{"class":491},[481,1740,1581],{"class":1521},[481,1742,1556],{"class":491},[481,1744,1586],{"class":512},[481,1746,1590],{"class":1589},[481,1748,980],{"class":512},[481,1750,1590],{"class":1589},[481,1752,1753],{"class":512}," 1024L",[481,1755,1756],{"class":491},"))",[481,1758,1759],{"class":983}," \u002F\u002F 512 MB total\n",[481,1761,1762,1764,1766],{"class":483,"line":1605},[481,1763,1572],{"class":491},[481,1765,1610],{"class":1521},[481,1767,1768],{"class":491},"();\n",[411,1770,1772],{"id":1771},"watching-the-effect","Watching the effect",[320,1774,1775],{},"Tune against signals, not hunches. After each change, watch:",[355,1777,1778,1789,1798],{},[358,1779,1780,1784,1785,346,1787,350],{},[324,1781,1782],{},[371,1783,420],{}," — throughput, consumer lag, commit timing, and JVM\u002Fcontainer memory, scraped by Prometheus. See ",[332,1786,195],{"href":196},[332,1788,243],{"href":244},[358,1790,1791,1795,1796,350],{},[324,1792,1793],{},[371,1794,424],{}," — the live commit-pipeline state, which tells you whether barriers are firing on schedule and what's triggering them. See ",[332,1797,428],{"href":186},[358,1799,1800,1805,1806,350],{},[324,1801,1802],{},[371,1803,1804],{},"\u002Fhealth\u002Fready"," — readiness flips DOWN if the engine can't keep up or a commit stalls. See ",[332,1807,901],{"href":239},[320,1809,1810],{},"A clean tuning loop: change one knob → run representative load → read the metric that maps to the symptom → keep or revert. Resist changing several knobs at once; you won't know which one moved the needle.",[411,1812,1814],{"id":1813},"next-steps","Next steps",[355,1816,1817,1824,1831,1838],{},[358,1818,1819,1823],{},[324,1820,1821],{},[332,1822,349],{"href":168}," — where every default comes from and how layers merge.",[358,1825,1826,1830],{},[324,1827,1828],{},[332,1829,281],{"href":282}," — every key, type, range, default, and environment override.",[358,1832,1833,1837],{},[324,1834,1835],{},[332,1836,253],{"href":254}," — the pre-flight list before you take a topology to production.",[358,1839,1840,1844],{},[324,1841,1842],{},[332,1843,243],{"href":244}," — wiring metrics and dashboards so the symptoms above show up before users notice.",[1846,1847,1848],"style",{},"html pre.shiki code .su6XF, html code.shiki .su6XF{--shiki-default:#998418}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .s-TwI, html code.shiki .s-TwI{--shiki-default:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .suHK_, html code.shiki .suHK_{--shiki-default:#393A34}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .svycV, html code.shiki .svycV{--shiki-default:#B07D48}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}",{"title":477,"searchDepth":495,"depth":495,"links":1850},[1851,1852,1855,1858,1859,1860,1864,1865],{"id":413,"depth":495,"text":414},{"id":453,"depth":495,"text":454,"children":1853},[1854],{"id":612,"depth":503,"text":613},{"id":656,"depth":495,"text":657,"children":1856},[1857],{"id":904,"depth":503,"text":905},{"id":992,"depth":495,"text":993},{"id":1206,"depth":495,"text":1207},{"id":1253,"depth":495,"text":1254,"children":1861},[1862,1863],{"id":1452,"depth":503,"text":1453},{"id":1489,"depth":503,"text":1490},{"id":1771,"depth":495,"text":1772},{"id":1813,"depth":495,"text":1814},"Practical tuning for StoatFlow under load — lane count, commit-cadence bounds, the memory and uncommitted-state knobs, and RocksDB sizing for large state, each tied to the symptom that tells you to reach for it.","md",{},{"icon":251},"how-to",{"title":248,"description":1866},"hF95fVA-vIgqkAg3TbcOrr9RrD_qXEoCYbjgxckFl9U",[1874,1876],{"title":243,"path":244,"stem":245,"description":1875,"icon":246,"children":-1},"Operating-time visibility for a single-instance app — scrape \u002Fmetrics into Prometheus and Grafana, the meters worth alerting on, correlating logs to lanes and barriers via opt-in MDC, and the \u002Fdebug\u002Fthreads and \u002Fdebug\u002Fbarriers endpoints for diagnosing a frozen or slow pipeline.",{"title":253,"path":254,"stem":255,"description":1877,"icon":256,"children":-1},"A go-live checklist for StoatFlow — replica count, license, probes, metrics, error policies, tuning, and thread safety — each item linking to the canonical page that covers it in full.",1783713363138]