[{"data":1,"prerenderedAt":2256},["ShallowReactive",2],{"navigation":3,"/actix-web/observability":240,"/actix-web/observability-surround":2251},[4,34,66,87,106,145,166,176,204],{"title":5,"path":6,"stem":7,"children":8,"icon":32,"defaultOpen":33},"Getting Started","/getting-started","1.getting-started/1.index",[9,12,17,22,27],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-info",{"title":13,"path":14,"stem":15,"icon":16},"Installation","/getting-started/installation","1.getting-started/2.installation","i-lucide-download",{"title":18,"path":19,"stem":20,"icon":21},"Quickstart (Local)","/getting-started/quickstart-local","1.getting-started/3.quickstart-local","i-lucide-zap",{"title":23,"path":24,"stem":25,"icon":26},"Quickstart (Redis)","/getting-started/quickstart-redis","1.getting-started/4.quickstart-redis","i-lucide-database",{"title":28,"path":29,"stem":30,"icon":31},"Quickstart (Hybrid)","/getting-started/quickstart-hybrid","1.getting-started/5.quickstart-hybrid","i-lucide-arrow-left-right","i-lucide-rocket",true,{"title":35,"icon":36,"defaultOpen":33,"path":37,"stem":38,"children":39,"page":65},"Concepts","i-lucide-lightbulb","/concepts","2.concepts",[40,45,50,55,60],{"title":41,"path":42,"stem":43,"icon":44},"Keys","/concepts/keys","2.concepts/1.keys","i-lucide-key-round",{"title":46,"path":47,"stem":48,"icon":49},"Rate Limits","/concepts/rate-limits","2.concepts/2.rate-limits","i-lucide-badge-percent",{"title":51,"path":52,"stem":53,"icon":54},"Sliding Windows","/concepts/sliding-windows","2.concepts/3.sliding-windows","i-lucide-timer-reset",{"title":56,"path":57,"stem":58,"icon":59},"Decisions","/concepts/decisions","2.concepts/4.decisions","i-lucide-check-check",{"title":61,"path":62,"stem":63,"icon":64},"Configuration Types","/concepts/configuration-types","2.concepts/5.configuration-types","i-lucide-box",false,{"title":67,"icon":68,"defaultOpen":33,"path":69,"stem":70,"children":71,"page":65},"Strategies","i-lucide-git-branch","/strategies","3.strategies",[72,77,82],{"title":73,"path":74,"stem":75,"icon":76},"Absolute","/strategies/absolute","3.strategies/1.absolute","i-lucide-shield",{"title":78,"path":79,"stem":80,"icon":81},"Suppressed","/strategies/suppressed","3.strategies/2.suppressed","i-lucide-activity",{"title":83,"path":84,"stem":85,"icon":86},"How Suppression Works","/strategies/how-suppression-works","3.strategies/3.how-suppression-works","i-lucide-function-square",{"title":88,"icon":89,"defaultOpen":33,"path":90,"stem":91,"children":92,"page":65},"Providers","i-lucide-layers","/providers","4.providers",[93,98,102],{"title":94,"path":95,"stem":96,"icon":97},"Local","/providers/local","4.providers/1.local","i-lucide-cpu",{"title":99,"path":100,"stem":101,"icon":26},"Redis","/providers/redis","4.providers/2.redis",{"title":103,"path":104,"stem":105,"icon":31},"Hybrid","/providers/hybrid","4.providers/3.hybrid",{"title":107,"path":108,"stem":109,"children":110,"icon":76,"defaultOpen":65},"Actix Web","/actix-web","5.actix-web/1.index",[111,113,118,122,127,131,136,140],{"title":112,"path":108,"stem":109,"icon":76},"Overview",{"title":114,"path":115,"stem":116,"icon":117},"Client IPs","/actix-web/client-ips","5.actix-web/2.client-ips","i-lucide-network",{"title":119,"path":120,"stem":121,"icon":44},"Keys and custom extractors","/actix-web/keys","5.actix-web/3.keys",{"title":123,"path":124,"stem":125,"icon":126},"Limits","/actix-web/limits","5.actix-web/4.limits","i-lucide-gauge",{"title":128,"path":129,"stem":130,"icon":26},"Backends","/actix-web/backends","5.actix-web/5.backends",{"title":132,"path":133,"stem":134,"icon":135},"Responses","/actix-web/responses","5.actix-web/6.responses","i-lucide-reply",{"title":137,"path":138,"stem":139,"icon":81},"Observability","/actix-web/observability","5.actix-web/7.observability",{"title":141,"path":142,"stem":143,"icon":144},"Performance","/actix-web/performance","5.actix-web/8.performance","i-lucide-timer",{"title":146,"icon":147,"defaultOpen":65,"path":148,"stem":149,"children":150,"page":65},"Guides","i-lucide-map","/guides","5.guides",[151,156,161],{"title":152,"path":153,"stem":154,"icon":155},"Configuration","/guides/configuration","5.guides/1.configuration","i-lucide-sliders-horizontal",{"title":157,"path":158,"stem":159,"icon":160},"Cleanup","/guides/cleanup","5.guides/2.cleanup","i-lucide-trash-2",{"title":162,"path":163,"stem":164,"icon":165},"Troubleshooting","/guides/troubleshooting","5.guides/4.troubleshooting","i-lucide-wrench",{"title":167,"icon":168,"defaultOpen":65,"path":169,"stem":170,"children":171,"page":65},"Reference","i-lucide-file-text","/reference","6.reference",[172],{"title":173,"path":174,"stem":175,"icon":168},"API Reference Guide","/reference/api","6.reference/1.api",{"title":177,"icon":126,"defaultOpen":65,"path":178,"stem":179,"children":180,"page":65},"Benchmarks","/benchmarks","7.benchmarks",[181,186,190],{"title":182,"path":183,"stem":184,"icon":185},"Benchmark Concepts","/benchmarks/benchmark-concepts","7.benchmarks/0.benchmark-concepts","i-lucide-book-open",{"title":187,"path":188,"stem":189,"icon":126},"Benchmarking & Load Testing","/benchmarks/benchmarking-load-testing","7.benchmarks/1.benchmarking-load-testing",{"title":191,"path":192,"stem":193,"children":194,"icon":203},"Benchmark Results","/benchmarks/benchmark-results","7.benchmarks/2.benchmark-results",[195,199],{"title":196,"path":197,"stem":198,"icon":97},"Local Benchmark Comparison","/benchmarks/benchmark-results/local-benchmark-comparison","7.benchmarks/2.benchmark-results/1.local-benchmark-comparison",{"title":200,"path":201,"stem":202,"icon":26},"Redis + Hybrid Benchmark Comparison","/benchmarks/benchmark-results/redis-benchmark-comparison","7.benchmarks/2.benchmark-results/2.redis-benchmark-comparison","i-lucide-chart-no-axes-combined",{"title":205,"path":206,"stem":207,"children":208,"icon":210,"defaultOpen":65},"Changelog","/changelog","8.changelog/0.index",[209,211,216,220,224,228,232,236],{"title":205,"path":206,"stem":207,"icon":210},"i-lucide-scroll",{"title":212,"path":213,"stem":214,"icon":215},"v2.2.1","/changelog/v2-2-1","8.changelog/1.v2-2-1","i-lucide-tag",{"title":217,"path":218,"stem":219,"icon":215},"v2.2.0","/changelog/v2-2-0","8.changelog/2.v2-2-0",{"title":221,"path":222,"stem":223,"icon":215},"v2.1.0","/changelog/v2-1-0","8.changelog/3.v2-1-0",{"title":225,"path":226,"stem":227,"icon":215},"v2.0.0","/changelog/v2-0-0","8.changelog/4.v2-0-0",{"title":229,"path":230,"stem":231,"icon":215},"v1.1.0","/changelog/v1-1-0","8.changelog/5.v1-1-0",{"title":233,"path":234,"stem":235,"icon":215},"v1.0.1","/changelog/v1-0-1","8.changelog/6.v1-0-1",{"title":237,"path":238,"stem":239,"icon":215},"v1.0.0","/changelog/v1-0-0","8.changelog/7.v1-0-0",{"id":241,"title":137,"authors":242,"badge":242,"body":243,"date":242,"description":2245,"extension":2246,"links":242,"meta":2247,"navigation":2248,"path":138,"seo":2249,"stem":139,"__hash__":2250},"docs/5.actix-web/7.observability.md",null,{"type":244,"value":245,"toc":2236},"minimark",[246,251,259,869,880,884,894,972,1350,1353,1358,1369,1574,1587,1591,1609,1688,1697,1701,1711,1729,1732,1736,1742,1748,1978,1988,2221,2232],[247,248,250],"h2",{"id":249},"shadow-mode","Shadow mode",[252,253,254,258],"p",{},[255,256,257],"code",{},"permissive(true)"," runs a limiter without enforcing it: usage is tracked and every decision is\nrecorded, but every request is admitted. Use it to size a new limit against real traffic before\nswitching it on.",[260,261,266],"pre",{"className":262,"code":263,"language":264,"meta":265,"style":265},"language-rust shiki shiki-themes material-theme-lighter github-light github-dark monokai","use actix_trypema::{LimitOutcome, Local, RateLimitInfo, Strategy, TrypemaLimiter, extract::PeerIp};\nuse actix_web::{App, HttpResponse, Responder, web};\nuse trypema::{RateLimit, WindowSize};\n\nlet limiter = TrypemaLimiter::builder(Local::new(WindowSize::seconds_or_panic(60))?)\n    .namespace(\"ip\")\n    .extractor(PeerIp::default())\n    .rate(RateLimit::per_minute_or_panic(60.0))\n    // Absolute rejections record nothing in Trypema, so shadow counts under-count overload;\n    // the suppressed strategy keeps accurate counts.\n    .strategy(Strategy::Suppressed)\n    .permissive(true)\n    .build()?;\n\nasync fn handler(info: RateLimitInfo) -> impl Responder {\n    match info.outcome() {\n        LimitOutcome::Limited { .. } | LimitOutcome::Suppressed { admitted: false, .. } => {\n            tracing::info!(\"would have been rate limited\");\n            HttpResponse::Ok().body(\"served anyway\")\n        }\n        _ => HttpResponse::Ok().body(\"within limits\"),\n    }\n}\n\nlet app = App::new().wrap(limiter).route(\"/\", web::get().to(handler));\n","rust","",[255,267,268,326,359,381,387,444,467,487,518,525,531,550,565,581,586,622,641,692,715,744,750,783,789,795,800],{"__ignoreMap":265},[269,270,273,277,281,285,289,292,295,298,300,303,305,308,310,313,315,318,320,323],"span",{"class":271,"line":272},"line",1,[269,274,276],{"class":275},"shWJe","use",[269,278,280],{"class":279},"sKvfc"," actix_trypema",[269,282,284],{"class":283},"sGXK2","::",[269,286,288],{"class":287},"swvn1","{",[269,290,291],{"class":279},"LimitOutcome",[269,293,294],{"class":287},",",[269,296,297],{"class":279}," Local",[269,299,294],{"class":287},[269,301,302],{"class":279}," RateLimitInfo",[269,304,294],{"class":287},[269,306,307],{"class":279}," Strategy",[269,309,294],{"class":287},[269,311,312],{"class":279}," TrypemaLimiter",[269,314,294],{"class":287},[269,316,317],{"class":279}," extract",[269,319,284],{"class":283},[269,321,322],{"class":279},"PeerIp",[269,324,325],{"class":287},"};\n",[269,327,329,331,334,336,338,341,343,346,348,351,353,357],{"class":271,"line":328},2,[269,330,276],{"class":275},[269,332,333],{"class":279}," actix_web",[269,335,284],{"class":283},[269,337,288],{"class":287},[269,339,340],{"class":279},"App",[269,342,294],{"class":287},[269,344,345],{"class":279}," HttpResponse",[269,347,294],{"class":287},[269,349,350],{"class":279}," Responder",[269,352,294],{"class":287},[269,354,356],{"class":355},"s6Ffr"," web",[269,358,325],{"class":287},[269,360,362,364,367,369,371,374,376,379],{"class":271,"line":361},3,[269,363,276],{"class":275},[269,365,366],{"class":279}," trypema",[269,368,284],{"class":283},[269,370,288],{"class":287},[269,372,373],{"class":279},"RateLimit",[269,375,294],{"class":287},[269,377,378],{"class":279}," WindowSize",[269,380,325],{"class":287},[269,382,384],{"class":271,"line":383},4,[269,385,386],{"emptyLinePlaceholder":33},"\n",[269,388,390,394,398,401,403,405,409,412,414,416,419,421,424,426,429,431,435,438,441],{"class":271,"line":389},5,[269,391,393],{"class":392},"srJo8","let",[269,395,397],{"class":396},"ss--_"," limiter ",[269,399,400],{"class":283},"=",[269,402,312],{"class":279},[269,404,284],{"class":283},[269,406,408],{"class":407},"sD0ED","builder",[269,410,411],{"class":287},"(",[269,413,94],{"class":279},[269,415,284],{"class":283},[269,417,418],{"class":407},"new",[269,420,411],{"class":287},[269,422,423],{"class":279},"WindowSize",[269,425,284],{"class":283},[269,427,428],{"class":407},"seconds_or_panic",[269,430,411],{"class":287},[269,432,434],{"class":433},"sYThS","60",[269,436,437],{"class":287},"))",[269,439,440],{"class":283},"?",[269,442,443],{"class":287},")\n",[269,445,447,450,453,455,459,463,465],{"class":271,"line":446},6,[269,448,449],{"class":283},"    .",[269,451,452],{"class":407},"namespace",[269,454,411],{"class":287},[269,456,458],{"class":457},"siCPE","\"",[269,460,462],{"class":461},"sLACW","ip",[269,464,458],{"class":457},[269,466,443],{"class":287},[269,468,470,472,475,477,479,481,484],{"class":271,"line":469},7,[269,471,449],{"class":283},[269,473,474],{"class":407},"extractor",[269,476,411],{"class":287},[269,478,322],{"class":279},[269,480,284],{"class":283},[269,482,483],{"class":407},"default",[269,485,486],{"class":287},"())\n",[269,488,490,492,495,497,499,501,504,506,508,512,515],{"class":271,"line":489},8,[269,491,449],{"class":283},[269,493,494],{"class":407},"rate",[269,496,411],{"class":287},[269,498,373],{"class":279},[269,500,284],{"class":283},[269,502,503],{"class":407},"per_minute_or_panic",[269,505,411],{"class":287},[269,507,434],{"class":433},[269,509,511],{"class":510},"sMTiH",".",[269,513,514],{"class":433},"0",[269,516,517],{"class":287},"))\n",[269,519,521],{"class":271,"line":520},9,[269,522,524],{"class":523},"ss7Ak","    // Absolute rejections record nothing in Trypema, so shadow counts under-count overload;\n",[269,526,528],{"class":271,"line":527},10,[269,529,530],{"class":523},"    // the suppressed strategy keeps accurate counts.\n",[269,532,534,536,539,541,544,546,548],{"class":271,"line":533},11,[269,535,449],{"class":283},[269,537,538],{"class":407},"strategy",[269,540,411],{"class":287},[269,542,543],{"class":279},"Strategy",[269,545,284],{"class":283},[269,547,78],{"class":279},[269,549,443],{"class":287},[269,551,553,555,558,560,563],{"class":271,"line":552},12,[269,554,449],{"class":283},[269,556,557],{"class":407},"permissive",[269,559,411],{"class":287},[269,561,562],{"class":510},"true",[269,564,443],{"class":287},[269,566,568,570,573,576,578],{"class":271,"line":567},13,[269,569,449],{"class":283},[269,571,572],{"class":407},"build",[269,574,575],{"class":287},"()",[269,577,440],{"class":283},[269,579,580],{"class":287},";\n",[269,582,584],{"class":271,"line":583},14,[269,585,386],{"emptyLinePlaceholder":33},[269,587,589,592,595,598,600,603,606,608,611,614,617,619],{"class":271,"line":588},15,[269,590,591],{"class":275},"async",[269,593,594],{"class":275}," fn",[269,596,597],{"class":407}," handler",[269,599,411],{"class":287},[269,601,602],{"class":396},"info",[269,604,605],{"class":283},":",[269,607,302],{"class":279},[269,609,610],{"class":287},")",[269,612,613],{"class":283}," ->",[269,615,616],{"class":275}," impl",[269,618,350],{"class":279},[269,620,621],{"class":287}," {\n",[269,623,625,629,632,634,637,639],{"class":271,"line":624},16,[269,626,628],{"class":627},"sRxSC","    match",[269,630,631],{"class":396}," info",[269,633,511],{"class":283},[269,635,636],{"class":407},"outcome",[269,638,575],{"class":287},[269,640,621],{"class":287},[269,642,644,647,649,652,655,658,661,664,667,669,671,673,676,678,681,683,685,687,690],{"class":271,"line":643},17,[269,645,646],{"class":279},"        LimitOutcome",[269,648,284],{"class":283},[269,650,651],{"class":279},"Limited",[269,653,654],{"class":287}," {",[269,656,657],{"class":283}," ..",[269,659,660],{"class":287}," }",[269,662,663],{"class":283}," |",[269,665,666],{"class":279}," LimitOutcome",[269,668,284],{"class":283},[269,670,78],{"class":279},[269,672,654],{"class":287},[269,674,675],{"class":396}," admitted",[269,677,605],{"class":283},[269,679,680],{"class":510}," false",[269,682,294],{"class":287},[269,684,657],{"class":283},[269,686,660],{"class":287},[269,688,689],{"class":283}," =>",[269,691,621],{"class":287},[269,693,695,698,700,703,705,707,710,712],{"class":271,"line":694},18,[269,696,697],{"class":279},"            tracing",[269,699,284],{"class":283},[269,701,702],{"class":407},"info!",[269,704,411],{"class":287},[269,706,458],{"class":457},[269,708,709],{"class":461},"would have been rate limited",[269,711,458],{"class":457},[269,713,714],{"class":287},");\n",[269,716,718,721,723,726,728,730,733,735,737,740,742],{"class":271,"line":717},19,[269,719,720],{"class":279},"            HttpResponse",[269,722,284],{"class":283},[269,724,725],{"class":279},"Ok",[269,727,575],{"class":287},[269,729,511],{"class":283},[269,731,732],{"class":407},"body",[269,734,411],{"class":287},[269,736,458],{"class":457},[269,738,739],{"class":461},"served anyway",[269,741,458],{"class":457},[269,743,443],{"class":287},[269,745,747],{"class":271,"line":746},20,[269,748,749],{"class":287},"        }\n",[269,751,753,756,759,761,763,765,767,769,771,773,775,778,780],{"class":271,"line":752},21,[269,754,755],{"class":396},"        _ ",[269,757,758],{"class":283},"=>",[269,760,345],{"class":279},[269,762,284],{"class":283},[269,764,725],{"class":279},[269,766,575],{"class":287},[269,768,511],{"class":283},[269,770,732],{"class":407},[269,772,411],{"class":287},[269,774,458],{"class":457},[269,776,777],{"class":461},"within limits",[269,779,458],{"class":457},[269,781,782],{"class":287},"),\n",[269,784,786],{"class":271,"line":785},22,[269,787,788],{"class":287},"    }\n",[269,790,792],{"class":271,"line":791},23,[269,793,794],{"class":287},"}\n",[269,796,798],{"class":271,"line":797},24,[269,799,386],{"emptyLinePlaceholder":33},[269,801,803,805,808,810,813,815,817,819,821,824,826,829,831,833,836,838,840,843,845,847,849,851,854,856,858,861,863,866],{"class":271,"line":802},25,[269,804,393],{"class":392},[269,806,807],{"class":396}," app ",[269,809,400],{"class":283},[269,811,812],{"class":279}," App",[269,814,284],{"class":283},[269,816,418],{"class":407},[269,818,575],{"class":287},[269,820,511],{"class":283},[269,822,823],{"class":407},"wrap",[269,825,411],{"class":287},[269,827,828],{"class":396},"limiter",[269,830,610],{"class":287},[269,832,511],{"class":283},[269,834,835],{"class":407},"route",[269,837,411],{"class":287},[269,839,458],{"class":457},[269,841,842],{"class":461},"/",[269,844,458],{"class":457},[269,846,294],{"class":287},[269,848,356],{"class":279},[269,850,284],{"class":283},[269,852,853],{"class":407},"get",[269,855,575],{"class":287},[269,857,511],{"class":283},[269,859,860],{"class":407},"to",[269,862,411],{"class":287},[269,864,865],{"class":396},"handler",[269,867,868],{"class":287},"));\n",[252,870,871,872,875,876,879],{},"In shadow mode a key error forwards the request instead of answering ",[255,873,874],{},"400",", and a backend\nfailure is admitted whatever ",[255,877,878],{},"on_backend_error"," says.",[247,881,883],{"id":882},"reading-decisions-in-handlers","Reading decisions in handlers",[252,885,886,889,890,893],{},[255,887,888],{},"record_outcome(true)"," records the decision while still enforcing it. Handlers read it with the\n",[255,891,892],{},"RateLimitInfo"," extractor:",[895,896,897,911],"table",{},[898,899,900],"thead",{},[901,902,903,908],"tr",{},[904,905,906],"th",{},[255,907,291],{},[904,909,910],{},"Meaning",[912,913,914,932,942,952,962],"tbody",{},[901,915,916,922],{},[917,918,919],"td",{},[255,920,921],{},"Admitted { limit, remaining }",[917,923,924,925,928,929,511],{},"Admitted; ",[255,926,927],{},"remaining"," is filled with ",[255,930,931],{},"remaining_header(true)",[901,933,934,939],{},[917,935,936],{},[255,937,938],{},"Limited { retry_after }",[917,940,941],{},"Over the limit. Only reaches a handler in shadow mode.",[901,943,944,949],{},[917,945,946],{},[255,947,948],{},"Suppressed { factor, admitted }",[917,950,951],{},"The suppressed strategy decided at random with this factor.",[901,953,954,959],{},[917,955,956],{},[255,957,958],{},"Bypassed",[917,960,961],{},"Excluded, allow-listed, cost 0, or a bypassed key error.",[901,963,964,969],{},[917,965,966],{},[255,967,968],{},"BackendError",[917,970,971],{},"The backend failed and the policy admitted the request.",[260,973,975],{"className":262,"code":974,"language":264,"meta":265,"style":265},"use actix_trypema::{LimitOutcome, Local, RateLimitInfo, TrypemaLimiter, extract::PeerIp};\nuse actix_web::{HttpResponse, Responder};\nuse trypema::{RateLimit, WindowSize};\n\nlet limiter = TrypemaLimiter::builder(Local::new(WindowSize::seconds_or_panic(60))?)\n    .namespace(\"ip\")\n    .extractor(PeerIp::default())\n    .rate(RateLimit::per_minute_or_panic(60.0))\n    .remaining_header(true)\n    .record_outcome(true)\n    .build()?;\n\nasync fn handler(info: RateLimitInfo) -> impl Responder {\n    match info.outcome() {\n        // Serve a lighter page to clients close to their limit.\n        LimitOutcome::Admitted { remaining: Some(remaining), .. } if *remaining \u003C 5 => {\n            HttpResponse::Ok().body(\"light\")\n        }\n        _ => HttpResponse::Ok().body(\"full\"),\n    }\n}\n",[255,976,977,1011,1030,1048,1052,1092,1108,1124,1148,1161,1174,1186,1190,1216,1230,1235,1284,1309,1313,1342,1346],{"__ignoreMap":265},[269,978,979,981,983,985,987,989,991,993,995,997,999,1001,1003,1005,1007,1009],{"class":271,"line":272},[269,980,276],{"class":275},[269,982,280],{"class":279},[269,984,284],{"class":283},[269,986,288],{"class":287},[269,988,291],{"class":279},[269,990,294],{"class":287},[269,992,297],{"class":279},[269,994,294],{"class":287},[269,996,302],{"class":279},[269,998,294],{"class":287},[269,1000,312],{"class":279},[269,1002,294],{"class":287},[269,1004,317],{"class":279},[269,1006,284],{"class":283},[269,1008,322],{"class":279},[269,1010,325],{"class":287},[269,1012,1013,1015,1017,1019,1021,1024,1026,1028],{"class":271,"line":328},[269,1014,276],{"class":275},[269,1016,333],{"class":279},[269,1018,284],{"class":283},[269,1020,288],{"class":287},[269,1022,1023],{"class":279},"HttpResponse",[269,1025,294],{"class":287},[269,1027,350],{"class":279},[269,1029,325],{"class":287},[269,1031,1032,1034,1036,1038,1040,1042,1044,1046],{"class":271,"line":361},[269,1033,276],{"class":275},[269,1035,366],{"class":279},[269,1037,284],{"class":283},[269,1039,288],{"class":287},[269,1041,373],{"class":279},[269,1043,294],{"class":287},[269,1045,378],{"class":279},[269,1047,325],{"class":287},[269,1049,1050],{"class":271,"line":383},[269,1051,386],{"emptyLinePlaceholder":33},[269,1053,1054,1056,1058,1060,1062,1064,1066,1068,1070,1072,1074,1076,1078,1080,1082,1084,1086,1088,1090],{"class":271,"line":389},[269,1055,393],{"class":392},[269,1057,397],{"class":396},[269,1059,400],{"class":283},[269,1061,312],{"class":279},[269,1063,284],{"class":283},[269,1065,408],{"class":407},[269,1067,411],{"class":287},[269,1069,94],{"class":279},[269,1071,284],{"class":283},[269,1073,418],{"class":407},[269,1075,411],{"class":287},[269,1077,423],{"class":279},[269,1079,284],{"class":283},[269,1081,428],{"class":407},[269,1083,411],{"class":287},[269,1085,434],{"class":433},[269,1087,437],{"class":287},[269,1089,440],{"class":283},[269,1091,443],{"class":287},[269,1093,1094,1096,1098,1100,1102,1104,1106],{"class":271,"line":446},[269,1095,449],{"class":283},[269,1097,452],{"class":407},[269,1099,411],{"class":287},[269,1101,458],{"class":457},[269,1103,462],{"class":461},[269,1105,458],{"class":457},[269,1107,443],{"class":287},[269,1109,1110,1112,1114,1116,1118,1120,1122],{"class":271,"line":469},[269,1111,449],{"class":283},[269,1113,474],{"class":407},[269,1115,411],{"class":287},[269,1117,322],{"class":279},[269,1119,284],{"class":283},[269,1121,483],{"class":407},[269,1123,486],{"class":287},[269,1125,1126,1128,1130,1132,1134,1136,1138,1140,1142,1144,1146],{"class":271,"line":489},[269,1127,449],{"class":283},[269,1129,494],{"class":407},[269,1131,411],{"class":287},[269,1133,373],{"class":279},[269,1135,284],{"class":283},[269,1137,503],{"class":407},[269,1139,411],{"class":287},[269,1141,434],{"class":433},[269,1143,511],{"class":510},[269,1145,514],{"class":433},[269,1147,517],{"class":287},[269,1149,1150,1152,1155,1157,1159],{"class":271,"line":520},[269,1151,449],{"class":283},[269,1153,1154],{"class":407},"remaining_header",[269,1156,411],{"class":287},[269,1158,562],{"class":510},[269,1160,443],{"class":287},[269,1162,1163,1165,1168,1170,1172],{"class":271,"line":527},[269,1164,449],{"class":283},[269,1166,1167],{"class":407},"record_outcome",[269,1169,411],{"class":287},[269,1171,562],{"class":510},[269,1173,443],{"class":287},[269,1175,1176,1178,1180,1182,1184],{"class":271,"line":533},[269,1177,449],{"class":283},[269,1179,572],{"class":407},[269,1181,575],{"class":287},[269,1183,440],{"class":283},[269,1185,580],{"class":287},[269,1187,1188],{"class":271,"line":552},[269,1189,386],{"emptyLinePlaceholder":33},[269,1191,1192,1194,1196,1198,1200,1202,1204,1206,1208,1210,1212,1214],{"class":271,"line":567},[269,1193,591],{"class":275},[269,1195,594],{"class":275},[269,1197,597],{"class":407},[269,1199,411],{"class":287},[269,1201,602],{"class":396},[269,1203,605],{"class":283},[269,1205,302],{"class":279},[269,1207,610],{"class":287},[269,1209,613],{"class":283},[269,1211,616],{"class":275},[269,1213,350],{"class":279},[269,1215,621],{"class":287},[269,1217,1218,1220,1222,1224,1226,1228],{"class":271,"line":583},[269,1219,628],{"class":627},[269,1221,631],{"class":396},[269,1223,511],{"class":283},[269,1225,636],{"class":407},[269,1227,575],{"class":287},[269,1229,621],{"class":287},[269,1231,1232],{"class":271,"line":588},[269,1233,1234],{"class":523},"        // Serve a lighter page to clients close to their limit.\n",[269,1236,1237,1239,1241,1244,1246,1249,1251,1254,1256,1258,1261,1263,1265,1268,1271,1274,1277,1280,1282],{"class":271,"line":624},[269,1238,646],{"class":279},[269,1240,284],{"class":283},[269,1242,1243],{"class":279},"Admitted",[269,1245,654],{"class":287},[269,1247,1248],{"class":396}," remaining",[269,1250,605],{"class":283},[269,1252,1253],{"class":279}," Some",[269,1255,411],{"class":287},[269,1257,927],{"class":396},[269,1259,1260],{"class":287},"),",[269,1262,657],{"class":283},[269,1264,660],{"class":287},[269,1266,1267],{"class":627}," if",[269,1269,1270],{"class":283}," *",[269,1272,1273],{"class":396},"remaining ",[269,1275,1276],{"class":283},"\u003C",[269,1278,1279],{"class":433}," 5",[269,1281,689],{"class":283},[269,1283,621],{"class":287},[269,1285,1286,1288,1290,1292,1294,1296,1298,1300,1302,1305,1307],{"class":271,"line":643},[269,1287,720],{"class":279},[269,1289,284],{"class":283},[269,1291,725],{"class":279},[269,1293,575],{"class":287},[269,1295,511],{"class":283},[269,1297,732],{"class":407},[269,1299,411],{"class":287},[269,1301,458],{"class":457},[269,1303,1304],{"class":461},"light",[269,1306,458],{"class":457},[269,1308,443],{"class":287},[269,1310,1311],{"class":271,"line":694},[269,1312,749],{"class":287},[269,1314,1315,1317,1319,1321,1323,1325,1327,1329,1331,1333,1335,1338,1340],{"class":271,"line":717},[269,1316,755],{"class":396},[269,1318,758],{"class":283},[269,1320,345],{"class":279},[269,1322,284],{"class":283},[269,1324,725],{"class":279},[269,1326,575],{"class":287},[269,1328,511],{"class":283},[269,1330,732],{"class":407},[269,1332,411],{"class":287},[269,1334,458],{"class":457},[269,1336,1337],{"class":461},"full",[269,1339,458],{"class":457},[269,1341,782],{"class":287},[269,1343,1344],{"class":271,"line":746},[269,1345,788],{"class":287},[269,1347,1348],{"class":271,"line":752},[269,1349,794],{"class":287},[252,1351,1352],{},"Recording costs a small allocation per request, so it is off unless you turn it on.",[1354,1355,1357],"h3",{"id":1356},"several-limiters","Several limiters",[252,1359,1360,1361,1364,1365,1368],{},"When several recording limiters wrap a route, ",[255,1362,1363],{},"outcome()"," returns the innermost one, and\n",[255,1366,1367],{},"for_namespace"," returns a specific one:",[260,1370,1372],{"className":262,"code":1371,"language":264,"meta":265,"style":265},"use actix_trypema::{LimitOutcome, RateLimitInfo};\nuse actix_web::{HttpResponse, Responder};\n\nasync fn handler(info: RateLimitInfo) -> impl Responder {\n    let near_ip_limit = matches!(\n        info.for_namespace(\"ip\"),\n        Some(LimitOutcome::Admitted { remaining: Some(0..=4), .. })\n    );\n\n    HttpResponse::Ok().body(if near_ip_limit { \"slow down\" } else { \"ok\" })\n}\n",[255,1373,1374,1392,1410,1414,1440,1456,1475,1513,1518,1522,1570],{"__ignoreMap":265},[269,1375,1376,1378,1380,1382,1384,1386,1388,1390],{"class":271,"line":272},[269,1377,276],{"class":275},[269,1379,280],{"class":279},[269,1381,284],{"class":283},[269,1383,288],{"class":287},[269,1385,291],{"class":279},[269,1387,294],{"class":287},[269,1389,302],{"class":279},[269,1391,325],{"class":287},[269,1393,1394,1396,1398,1400,1402,1404,1406,1408],{"class":271,"line":328},[269,1395,276],{"class":275},[269,1397,333],{"class":279},[269,1399,284],{"class":283},[269,1401,288],{"class":287},[269,1403,1023],{"class":279},[269,1405,294],{"class":287},[269,1407,350],{"class":279},[269,1409,325],{"class":287},[269,1411,1412],{"class":271,"line":361},[269,1413,386],{"emptyLinePlaceholder":33},[269,1415,1416,1418,1420,1422,1424,1426,1428,1430,1432,1434,1436,1438],{"class":271,"line":383},[269,1417,591],{"class":275},[269,1419,594],{"class":275},[269,1421,597],{"class":407},[269,1423,411],{"class":287},[269,1425,602],{"class":396},[269,1427,605],{"class":283},[269,1429,302],{"class":279},[269,1431,610],{"class":287},[269,1433,613],{"class":283},[269,1435,616],{"class":275},[269,1437,350],{"class":279},[269,1439,621],{"class":287},[269,1441,1442,1445,1448,1450,1453],{"class":271,"line":389},[269,1443,1444],{"class":392},"    let",[269,1446,1447],{"class":396}," near_ip_limit ",[269,1449,400],{"class":283},[269,1451,1452],{"class":407}," matches!",[269,1454,1455],{"class":287},"(\n",[269,1457,1458,1461,1463,1465,1467,1469,1471,1473],{"class":271,"line":446},[269,1459,1460],{"class":396},"        info",[269,1462,511],{"class":283},[269,1464,1367],{"class":407},[269,1466,411],{"class":287},[269,1468,458],{"class":457},[269,1470,462],{"class":461},[269,1472,458],{"class":457},[269,1474,782],{"class":287},[269,1476,1477,1480,1482,1484,1486,1488,1490,1492,1494,1496,1498,1500,1503,1506,1508,1510],{"class":271,"line":469},[269,1478,1479],{"class":279},"        Some",[269,1481,411],{"class":287},[269,1483,291],{"class":279},[269,1485,284],{"class":283},[269,1487,1243],{"class":279},[269,1489,654],{"class":287},[269,1491,1248],{"class":396},[269,1493,605],{"class":283},[269,1495,1253],{"class":279},[269,1497,411],{"class":287},[269,1499,514],{"class":433},[269,1501,1502],{"class":283},"..=",[269,1504,1505],{"class":433},"4",[269,1507,1260],{"class":287},[269,1509,657],{"class":283},[269,1511,1512],{"class":287}," })\n",[269,1514,1515],{"class":271,"line":489},[269,1516,1517],{"class":287},"    );\n",[269,1519,1520],{"class":271,"line":520},[269,1521,386],{"emptyLinePlaceholder":33},[269,1523,1524,1527,1529,1531,1533,1535,1537,1539,1542,1544,1546,1549,1552,1554,1556,1559,1561,1563,1566,1568],{"class":271,"line":527},[269,1525,1526],{"class":279},"    HttpResponse",[269,1528,284],{"class":283},[269,1530,725],{"class":279},[269,1532,575],{"class":287},[269,1534,511],{"class":283},[269,1536,732],{"class":407},[269,1538,411],{"class":287},[269,1540,1541],{"class":627},"if",[269,1543,1447],{"class":396},[269,1545,288],{"class":287},[269,1547,1548],{"class":457}," \"",[269,1550,1551],{"class":461},"slow down",[269,1553,458],{"class":457},[269,1555,660],{"class":287},[269,1557,1558],{"class":627}," else",[269,1560,654],{"class":287},[269,1562,1548],{"class":457},[269,1564,1565],{"class":461},"ok",[269,1567,458],{"class":457},[269,1569,1512],{"class":287},[269,1571,1572],{"class":271,"line":533},[269,1573,794],{"class":287},[252,1575,1576,1577,1579,1580,1583,1584,1586],{},"A handler that asks for ",[255,1578,892],{}," when no limiter recorded anything gets\n",[255,1581,1582],{},"500 Internal Server Error",", so turn on ",[255,1585,1167],{}," on every limiter whose outcome a\nhandler reads.",[247,1588,1590],{"id":1589},"metrics","Metrics",[252,1592,1593,1594,1596,1597,1605,1606,605],{},"With the ",[255,1595,1589],{}," feature, every limiter reports through the\n",[1598,1599,1603],"a",{"href":1600,"rel":1601},"https://crates.io/crates/metrics",[1602],"nofollow",[255,1604,1589],{}," facade, so any recorder works, such as\n",[255,1607,1608],{},"metrics-exporter-prometheus",[895,1610,1611,1624],{},[898,1612,1613],{},[901,1614,1615,1618,1621],{},[904,1616,1617],{},"Metric",[904,1619,1620],{},"Type",[904,1622,1623],{},"Counts",[912,1625,1626,1639,1651,1663,1675],{},[901,1627,1628,1633,1636],{},[917,1629,1630],{},[255,1631,1632],{},"ratelimit_admitted_total",[917,1634,1635],{},"counter",[917,1637,1638],{},"Admitted requests, including failures the policy admitted.",[901,1640,1641,1646,1648],{},[917,1642,1643],{},[255,1644,1645],{},"ratelimit_rejected_total",[917,1647,1635],{},[917,1649,1650],{},"Rejected requests, including key-error rejections.",[901,1652,1653,1658,1660],{},[917,1654,1655],{},[255,1656,1657],{},"ratelimit_bypassed_total",[917,1659,1635],{},[917,1661,1662],{},"Excluded, allow-listed and zero-cost requests.",[901,1664,1665,1670,1672],{},[917,1666,1667],{},[255,1668,1669],{},"ratelimit_backend_errors_total",[917,1671,1635],{},[917,1673,1674],{},"Redis and hybrid failures (also counted as admitted or rejected).",[901,1676,1677,1682,1685],{},[917,1678,1679],{},[255,1680,1681],{},"ratelimit_backend_latency_seconds",[917,1683,1684],{},"histogram",[917,1686,1687],{},"Backend calls that await Redis.",[252,1689,1690,1691,1693,1694,1696],{},"Every metric carries ",[255,1692,452],{}," and ",[255,1695,538],{}," labels. Each request increments exactly one of\nthe admitted, rejected and bypassed counters.",[247,1698,1700],{"id":1699},"logs","Logs",[252,1702,1703,1704,605],{},"The middleware logs through ",[1598,1705,1708],{"href":1706,"rel":1707},"https://crates.io/crates/tracing",[1602],[255,1709,1710],{},"tracing",[1712,1713,1714,1722],"ul",{},[1715,1716,1717,1718,1721],"li",{},"rejections and key errors at ",[255,1719,1720],{},"debug",", with the namespace;",[1715,1723,1724,1725,1728],{},"Redis and hybrid failures at ",[255,1726,1727],{},"warn",", at most once per second per process, with the namespace\nand the failure kind.",[252,1730,1731],{},"Logs never include the key or the error text, which can contain client data or connection\ndetails.",[247,1733,1735],{"id":1734},"managing-keys","Managing keys",[252,1737,1738,1741],{},[255,1739,1740],{},"derived_key(namespace, key)"," returns the key a limiter stores. Pass it to the backend's provider\nto inspect a client, lift a block, or change its rate in place.",[252,1743,1744,1745,1747],{},"With ",[255,1746,94],{},", the provider is synchronous:",[260,1749,1751],{"className":262,"code":1750,"language":264,"meta":265,"style":265},"use actix_trypema::{Local, derived_key};\nuse trypema::{RateLimit, WindowSize};\n\nlet backend = Local::new(WindowSize::seconds_or_panic(60))?;\nlet key = derived_key(\"ip\", \"203.0.113.7\");\nlet limiter = backend.provider().absolute();\n\nlet used = limiter.get(&key); // requests in the current window\nlimiter.delete(&key); // forget the client: its next request starts fresh\nlimiter.set_rate_limit(&key, &RateLimit::per_minute_or_panic(600.0)); // raise its limit\n",[255,1752,1753,1772,1790,1794,1827,1857,1883,1887,1917,1937],{"__ignoreMap":265},[269,1754,1755,1757,1759,1761,1763,1765,1767,1770],{"class":271,"line":272},[269,1756,276],{"class":275},[269,1758,280],{"class":279},[269,1760,284],{"class":283},[269,1762,288],{"class":287},[269,1764,94],{"class":279},[269,1766,294],{"class":287},[269,1768,1769],{"class":355}," derived_key",[269,1771,325],{"class":287},[269,1773,1774,1776,1778,1780,1782,1784,1786,1788],{"class":271,"line":328},[269,1775,276],{"class":275},[269,1777,366],{"class":279},[269,1779,284],{"class":283},[269,1781,288],{"class":287},[269,1783,373],{"class":279},[269,1785,294],{"class":287},[269,1787,378],{"class":279},[269,1789,325],{"class":287},[269,1791,1792],{"class":271,"line":361},[269,1793,386],{"emptyLinePlaceholder":33},[269,1795,1796,1798,1801,1803,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825],{"class":271,"line":383},[269,1797,393],{"class":392},[269,1799,1800],{"class":396}," backend ",[269,1802,400],{"class":283},[269,1804,297],{"class":279},[269,1806,284],{"class":283},[269,1808,418],{"class":407},[269,1810,411],{"class":287},[269,1812,423],{"class":279},[269,1814,284],{"class":283},[269,1816,428],{"class":407},[269,1818,411],{"class":287},[269,1820,434],{"class":433},[269,1822,437],{"class":287},[269,1824,440],{"class":283},[269,1826,580],{"class":287},[269,1828,1829,1831,1834,1836,1838,1840,1842,1844,1846,1848,1850,1853,1855],{"class":271,"line":389},[269,1830,393],{"class":392},[269,1832,1833],{"class":396}," key ",[269,1835,400],{"class":283},[269,1837,1769],{"class":407},[269,1839,411],{"class":287},[269,1841,458],{"class":457},[269,1843,462],{"class":461},[269,1845,458],{"class":457},[269,1847,294],{"class":287},[269,1849,1548],{"class":457},[269,1851,1852],{"class":461},"203.0.113.7",[269,1854,458],{"class":457},[269,1856,714],{"class":287},[269,1858,1859,1861,1863,1865,1868,1870,1873,1875,1877,1880],{"class":271,"line":446},[269,1860,393],{"class":392},[269,1862,397],{"class":396},[269,1864,400],{"class":283},[269,1866,1867],{"class":396}," backend",[269,1869,511],{"class":283},[269,1871,1872],{"class":407},"provider",[269,1874,575],{"class":287},[269,1876,511],{"class":283},[269,1878,1879],{"class":407},"absolute",[269,1881,1882],{"class":287},"();\n",[269,1884,1885],{"class":271,"line":469},[269,1886,386],{"emptyLinePlaceholder":33},[269,1888,1889,1891,1894,1896,1899,1901,1903,1905,1908,1911,1914],{"class":271,"line":489},[269,1890,393],{"class":392},[269,1892,1893],{"class":396}," used ",[269,1895,400],{"class":283},[269,1897,1898],{"class":396}," limiter",[269,1900,511],{"class":283},[269,1902,853],{"class":407},[269,1904,411],{"class":287},[269,1906,1907],{"class":283},"&",[269,1909,1910],{"class":396},"key",[269,1912,1913],{"class":287},");",[269,1915,1916],{"class":523}," // requests in the current window\n",[269,1918,1919,1921,1923,1926,1928,1930,1932,1934],{"class":271,"line":520},[269,1920,828],{"class":396},[269,1922,511],{"class":283},[269,1924,1925],{"class":407},"delete",[269,1927,411],{"class":287},[269,1929,1907],{"class":283},[269,1931,1910],{"class":396},[269,1933,1913],{"class":287},[269,1935,1936],{"class":523}," // forget the client: its next request starts fresh\n",[269,1938,1939,1941,1943,1946,1948,1950,1952,1954,1957,1959,1961,1963,1965,1968,1970,1972,1975],{"class":271,"line":527},[269,1940,828],{"class":396},[269,1942,511],{"class":283},[269,1944,1945],{"class":407},"set_rate_limit",[269,1947,411],{"class":287},[269,1949,1907],{"class":283},[269,1951,1910],{"class":396},[269,1953,294],{"class":287},[269,1955,1956],{"class":283}," &",[269,1958,373],{"class":279},[269,1960,284],{"class":283},[269,1962,503],{"class":407},[269,1964,411],{"class":287},[269,1966,1967],{"class":433},"600",[269,1969,511],{"class":510},[269,1971,514],{"class":433},[269,1973,1974],{"class":287},"));",[269,1976,1977],{"class":523}," // raise its limit\n",[252,1979,1744,1980,1693,1982,1984,1985,605],{},[255,1981,99],{},[255,1983,103],{},", the calls are async and take a ",[255,1986,1987],{},"RedisKey",[260,1989,1991],{"className":262,"code":1990,"language":264,"meta":265,"style":265},"use actix_trypema::{Redis, derived_key};\nuse trypema::{RateLimit, WindowSize, redis::RedisKey};\n\nlet backend = Redis::new(connection, WindowSize::minutes_or_panic(1))?;\nlet key = RedisKey::try_from(derived_key(\"apikey\", \"pro:account-2\"))?;\nlet limiter = backend.provider().absolute();\n\nlimiter.delete(&key).await?;\nlimiter.set_rate_limit(&key, &RateLimit::per_minute_or_panic(1_000.0)).await?;\n",[255,1992,1993,2011,2038,2042,2082,2127,2149,2153,2178],{"__ignoreMap":265},[269,1994,1995,1997,1999,2001,2003,2005,2007,2009],{"class":271,"line":272},[269,1996,276],{"class":275},[269,1998,280],{"class":279},[269,2000,284],{"class":283},[269,2002,288],{"class":287},[269,2004,99],{"class":279},[269,2006,294],{"class":287},[269,2008,1769],{"class":355},[269,2010,325],{"class":287},[269,2012,2013,2015,2017,2019,2021,2023,2025,2027,2029,2032,2034,2036],{"class":271,"line":328},[269,2014,276],{"class":275},[269,2016,366],{"class":279},[269,2018,284],{"class":283},[269,2020,288],{"class":287},[269,2022,373],{"class":279},[269,2024,294],{"class":287},[269,2026,378],{"class":279},[269,2028,294],{"class":287},[269,2030,2031],{"class":279}," redis",[269,2033,284],{"class":283},[269,2035,1987],{"class":279},[269,2037,325],{"class":287},[269,2039,2040],{"class":271,"line":361},[269,2041,386],{"emptyLinePlaceholder":33},[269,2043,2044,2046,2048,2050,2053,2055,2057,2059,2062,2064,2066,2068,2071,2073,2076,2078,2080],{"class":271,"line":383},[269,2045,393],{"class":392},[269,2047,1800],{"class":396},[269,2049,400],{"class":283},[269,2051,2052],{"class":279}," Redis",[269,2054,284],{"class":283},[269,2056,418],{"class":407},[269,2058,411],{"class":287},[269,2060,2061],{"class":396},"connection",[269,2063,294],{"class":287},[269,2065,378],{"class":279},[269,2067,284],{"class":283},[269,2069,2070],{"class":407},"minutes_or_panic",[269,2072,411],{"class":287},[269,2074,2075],{"class":433},"1",[269,2077,437],{"class":287},[269,2079,440],{"class":283},[269,2081,580],{"class":287},[269,2083,2084,2086,2088,2090,2093,2095,2098,2100,2103,2105,2107,2110,2112,2114,2116,2119,2121,2123,2125],{"class":271,"line":389},[269,2085,393],{"class":392},[269,2087,1833],{"class":396},[269,2089,400],{"class":283},[269,2091,2092],{"class":279}," RedisKey",[269,2094,284],{"class":283},[269,2096,2097],{"class":407},"try_from",[269,2099,411],{"class":287},[269,2101,2102],{"class":407},"derived_key",[269,2104,411],{"class":287},[269,2106,458],{"class":457},[269,2108,2109],{"class":461},"apikey",[269,2111,458],{"class":457},[269,2113,294],{"class":287},[269,2115,1548],{"class":457},[269,2117,2118],{"class":461},"pro:account-2",[269,2120,458],{"class":457},[269,2122,437],{"class":287},[269,2124,440],{"class":283},[269,2126,580],{"class":287},[269,2128,2129,2131,2133,2135,2137,2139,2141,2143,2145,2147],{"class":271,"line":446},[269,2130,393],{"class":392},[269,2132,397],{"class":396},[269,2134,400],{"class":283},[269,2136,1867],{"class":396},[269,2138,511],{"class":283},[269,2140,1872],{"class":407},[269,2142,575],{"class":287},[269,2144,511],{"class":283},[269,2146,1879],{"class":407},[269,2148,1882],{"class":287},[269,2150,2151],{"class":271,"line":469},[269,2152,386],{"emptyLinePlaceholder":33},[269,2154,2155,2157,2159,2161,2163,2165,2167,2169,2171,2174,2176],{"class":271,"line":489},[269,2156,828],{"class":396},[269,2158,511],{"class":283},[269,2160,1925],{"class":407},[269,2162,411],{"class":287},[269,2164,1907],{"class":283},[269,2166,1910],{"class":396},[269,2168,610],{"class":287},[269,2170,511],{"class":283},[269,2172,2173],{"class":627},"await",[269,2175,440],{"class":283},[269,2177,580],{"class":287},[269,2179,2180,2182,2184,2186,2188,2190,2192,2194,2196,2198,2200,2202,2204,2207,2209,2211,2213,2215,2217,2219],{"class":271,"line":520},[269,2181,828],{"class":396},[269,2183,511],{"class":283},[269,2185,1945],{"class":407},[269,2187,411],{"class":287},[269,2189,1907],{"class":283},[269,2191,1910],{"class":396},[269,2193,294],{"class":287},[269,2195,1956],{"class":283},[269,2197,373],{"class":279},[269,2199,284],{"class":283},[269,2201,503],{"class":407},[269,2203,411],{"class":287},[269,2205,2206],{"class":433},"1_000",[269,2208,511],{"class":510},[269,2210,514],{"class":433},[269,2212,437],{"class":287},[269,2214,511],{"class":283},[269,2216,2173],{"class":627},[269,2218,440],{"class":283},[269,2220,580],{"class":287},[252,2222,2223,2224,2227,2228,2231],{},"Use ",[255,2225,2226],{},"provider().suppressed()"," for limiters with ",[255,2229,2230],{},"Strategy::Suppressed",". Hybrid providers record\nthese changes in Redis, where the other instances pick them up the next time they read the key.",[2233,2234,2235],"style",{},"html pre.shiki code .shWJe, html code.shiki .shWJe{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .sKvfc, html code.shiki .sKvfc{--shiki-light:#E2931D;--shiki-light-text-decoration:inherit;--shiki-default:#6F42C1;--shiki-default-text-decoration:inherit;--shiki-dark:#B392F0;--shiki-dark-text-decoration:inherit;--shiki-sepia:#A6E22E;--shiki-sepia-text-decoration:underline}html pre.shiki code .sGXK2, html code.shiki .sGXK2{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583;--shiki-sepia:#F92672}html pre.shiki code .swvn1, html code.shiki .swvn1{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .s6Ffr, html code.shiki .s6Ffr{--shiki-light:#E2931D;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .srJo8, html code.shiki .srJo8{--shiki-light:#9C3EDA;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#66D9EF;--shiki-sepia-font-style:italic}html pre.shiki code .ss--_, html code.shiki .ss--_{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8;--shiki-sepia:#F8F8F2}html pre.shiki code .sD0ED, html code.shiki .sD0ED{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0;--shiki-sepia:#A6E22E}html pre.shiki code .sYThS, html code.shiki .sYThS{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .siCPE, html code.shiki .siCPE{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sLACW, html code.shiki .sLACW{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF;--shiki-sepia:#E6DB74}html pre.shiki code .sMTiH, html code.shiki .sMTiH{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF;--shiki-sepia:#AE81FF}html pre.shiki code .ss7Ak, html code.shiki .ss7Ak{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit;--shiki-sepia:#88846F;--shiki-sepia-font-style:inherit}html pre.shiki code .sRxSC, html code.shiki .sRxSC{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit;--shiki-sepia:#F92672;--shiki-sepia-font-style:inherit}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}html.sepia .shiki span {color: var(--shiki-sepia);background: var(--shiki-sepia-bg);font-style: var(--shiki-sepia-font-style);font-weight: var(--shiki-sepia-font-weight);text-decoration: var(--shiki-sepia-text-decoration);}",{"title":265,"searchDepth":272,"depth":328,"links":2237},[2238,2239,2242,2243,2244],{"id":249,"depth":328,"text":250},{"id":882,"depth":328,"text":883,"children":2240},[2241],{"id":1356,"depth":361,"text":1357},{"id":1589,"depth":328,"text":1590},{"id":1699,"depth":328,"text":1700},{"id":1734,"depth":328,"text":1735},"Try limits in shadow mode, read each limiter's decision in handlers, export metrics, and reset or change individual keys.","md",{},{"icon":81},{"title":137,"description":2245},"x8nADKGEi1Akfkze4zi-vtvuY24Bn5X4GXgoU1HUWgM",[2252,2254],{"title":132,"path":133,"stem":134,"description":2253,"icon":135,"children":-1},"The headers admitted and rejected responses carry, and how to customize the rejection body and status.",{"title":141,"path":142,"stem":143,"description":2255,"icon":144,"children":-1},"What actix-trypema adds to each request, compared with actix-governor, and how it was measured.",1791663192738]