[{"data":1,"prerenderedAt":1640},["ShallowReactive",2],{"navigation_docs":3,"-guides-performance":172,"-guides-performance-surround":1635},[4,26,67,98,124,140,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting Started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-play",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Core","i-lucide-box","\u002Fcore","2.core",[32,37,42,47,52,57,62],{"title":33,"path":34,"stem":35,"icon":36},"Routing","\u002Fcore\u002Frouting","2.core\u002F1.routing","i-lucide-route",{"title":38,"path":39,"stem":40,"icon":41},"Handlers","\u002Fcore\u002Fhandlers","2.core\u002F2.handlers","i-lucide-braces",{"title":43,"path":44,"stem":45,"icon":46},"Request Binding","\u002Fcore\u002Frequest-binding","2.core\u002F3.request-binding","i-lucide-tags",{"title":48,"path":49,"stem":50,"icon":51},"Validation","\u002Fcore\u002Fvalidation","2.core\u002F4.validation","i-lucide-check-check",{"title":53,"path":54,"stem":55,"icon":56},"Context","\u002Fcore\u002Fcontext","2.core\u002F5.context","i-lucide-file-input",{"title":58,"path":59,"stem":60,"icon":61},"Errors","\u002Fcore\u002Ferrors","2.core\u002F6.errors","i-lucide-triangle-alert",{"title":63,"path":64,"stem":65,"icon":66},"Middleware","\u002Fcore\u002Fmiddleware","2.core\u002F7.middleware","i-lucide-layers",{"title":68,"icon":69,"path":70,"stem":71,"children":72,"page":25},"Auth","i-lucide-shield-check","\u002Fauth","3.auth",[73,78,83,88,93],{"title":74,"path":75,"stem":76,"icon":77},"Overview","\u002Fauth\u002Foverview","3.auth\u002F1.overview","i-lucide-shield",{"title":79,"path":80,"stem":81,"icon":82},"Auth Rules","\u002Fauth\u002Fauth-rules","3.auth\u002F2.auth-rules","i-lucide-lock",{"title":84,"path":85,"stem":86,"icon":87},"JWT Providers","\u002Fauth\u002Fjwt-providers","3.auth\u002F3.jwt-providers","i-lucide-key",{"title":89,"path":90,"stem":91,"icon":92},"Roles & Permissions","\u002Fauth\u002Froles-and-permissions","3.auth\u002F4.roles-and-permissions","i-lucide-users",{"title":94,"path":95,"stem":96,"icon":97},"Audit Logging","\u002Fauth\u002Faudit-logging","3.auth\u002F5.audit-logging","i-lucide-scroll-text",{"title":99,"icon":100,"path":101,"stem":102,"children":103,"page":25},"GoTrue","i-lucide-key-round","\u002Fgotrue","4.gotrue",[104,109,114,119],{"title":105,"path":106,"stem":107,"icon":108},"Proxy","\u002Fgotrue\u002Fproxy","4.gotrue\u002F1.proxy","i-lucide-shuffle",{"title":110,"path":111,"stem":112,"icon":113},"Endpoints","\u002Fgotrue\u002Fendpoints","4.gotrue\u002F2.endpoints","i-lucide-list",{"title":115,"path":116,"stem":117,"icon":118},"Client IP & Rate Limits","\u002Fgotrue\u002Fclient-ip-and-rate-limits","4.gotrue\u002F3.client-ip-and-rate-limits","i-lucide-network",{"title":120,"path":121,"stem":122,"icon":123},"Deployment","\u002Fgotrue\u002Fdeployment","4.gotrue\u002F4.deployment","i-lucide-server",{"title":125,"icon":126,"path":127,"stem":128,"children":129,"page":25},"API Docs","i-lucide-file-text","\u002Fapi-docs","5.api-docs",[130,135],{"title":131,"path":132,"stem":133,"icon":134},"OpenAPI","\u002Fapi-docs\u002Fopenapi","5.api-docs\u002F1.openapi","i-lucide-file-json",{"title":136,"path":137,"stem":138,"icon":139},"Scalar UI","\u002Fapi-docs\u002Fscalar","5.api-docs\u002F2.scalar","i-lucide-book-open-text",{"title":141,"icon":142,"path":143,"stem":144,"children":145,"page":25},"Guides","i-lucide-compass","\u002Fguides","6.guides",[146,151,156],{"title":147,"path":148,"stem":149,"icon":150},"Testing","\u002Fguides\u002Ftesting","6.guides\u002F1.testing","i-lucide-flask-conical",{"title":152,"path":153,"stem":154,"icon":155},"Performance","\u002Fguides\u002Fperformance","6.guides\u002F2.performance","i-lucide-gauge",{"title":157,"path":158,"stem":159,"icon":160},"Releasing","\u002Fguides\u002Freleasing","6.guides\u002F3.releasing","i-lucide-tag",{"title":162,"icon":163,"path":164,"stem":165,"children":166,"page":25},"Reference","i-lucide-code","\u002Freference","7.reference",[167],{"title":168,"path":169,"stem":170,"icon":171},"API Reference","\u002Freference\u002Fapi-reference","7.reference\u002F1.api-reference","i-lucide-list-tree",{"id":173,"title":152,"body":174,"description":1628,"extension":1629,"links":1630,"meta":1631,"navigation":1632,"path":153,"seo":1633,"stem":154,"__hash__":1634},"docs\u002F6.guides\u002F2.performance.md",{"type":175,"value":176,"toc":1620},"minimark",[177,181,186,251,254,258,338,341,353,367,371,374,385,562,568,626,636,642,646,649,704,707,1103,1112,1115,1153,1162,1166,1176,1590,1597,1601,1616],[178,179,180],"p",{},"ezz moves work out of the request path wherever it can. Most of it happens when you register a route, which is why registration order matters in a few places.",[182,183,185],"h2",{"id":184},"what-happens-at-registration","What happens at registration",[187,188,189,202],"table",{},[190,191,192],"thead",{},[193,194,195,199],"tr",{},[196,197,198],"th",{},"Work",[196,200,201],{},"When",[203,204,205,218,226,234,244],"tbody",{},[193,206,207,211],{},[208,209,210],"td",{},"Request binder and validator built",[208,212,213,217],{},[214,215,216],"code",{},"ezz.H(...)"," is called",[193,219,220,223],{},[208,221,222],{},"Struct field metadata cached",[208,224,225],{},"First time a type is bound or validated",[193,227,228,231],{},[208,229,230],{},"Middleware chain composed",[208,232,233],{},"Route registration",[193,235,236,242],{},[208,237,238,239],{},"Route pattern registered on ",[214,240,241],{},"ServeMux",[208,243,233],{},[193,245,246,249],{},[208,247,248],{},"Request and response types recorded",[208,250,233],{},[178,252,253],{},"By the time a request arrives, a typed handler already knows which fields to fill and which rules to run. The binding pass walks a cached field list rather than reflecting over the struct.",[182,255,257],{"id":256},"what-happens-per-request","What happens per request",[187,259,260,270],{},[190,261,262],{},[193,263,264,267],{},[196,265,266],{},"Allocation",[196,268,269],{},"Handling",[203,271,272,286,294,302,310,322,330],{},[193,273,274,279],{},[208,275,276],{},[214,277,278],{},"*ezz.Context",[208,280,281,282,285],{},"Taken from a ",[214,283,284],{},"sync.Pool",", reset, returned when the handler ends",[193,287,288,291],{},[208,289,290],{},"Response writer wrapper",[208,292,293],{},"Pooled the same way",[193,295,296,299],{},[208,297,298],{},"Query values",[208,300,301],{},"Parsed on first access, then cached for the request",[193,303,304,307],{},[208,305,306],{},"Request metadata",[208,308,309],{},"Extracted once at context creation",[193,311,312,315],{},[208,313,314],{},"Request ID bytes",[208,316,317,318,321],{},"Pooled buffer, ",[214,319,320],{},"crypto\u002Frand",", hex encoded",[193,323,324,327],{},[208,325,326],{},"Validated JWT",[208,328,329],{},"Cached by token string in the HMAC provider",[193,331,332,335],{},[208,333,334],{},"Resolved authorization",[208,336,337],{},"Computed at most once per request, optionally cached across requests",[178,339,340],{},"Two rules follow from the pooling:",[342,343,344,345,347,348,352],"warning",{},"Do not keep an ",[214,346,278],{}," past the end of your handler. It is reset and reused, so a goroutine holding one will read another request's data. Copy the values you need first. See ",[349,350,53],"a",{"href":351},"\u002Fcore\u002Fcontext#respect-the-context-lifetime",".",[342,354,355,356,359,360,363,364,352],{},"Register middleware before routes. Each route captures the chain that exists when it is registered, so ",[214,357,358],{},"Use"," afterwards has no effect on it, and ",[214,361,362],{},"Logger"," rebuilds the default chain from scratch. See ",[349,365,63],{"href":366},"\u002Fcore\u002Fmiddleware#understand-the-order",[182,368,370],{"id":369},"choices-that-cost-you","Choices that cost you",[178,372,373],{},"A few habits undo the work above.",[178,375,376,380,381,384],{},[377,378,379],"strong",{},"Building handlers per request."," ",[214,382,383],{},"ezz.H"," compiles a binder and a validator each time it is called. Call it once, at registration.",[386,387,392],"pre",{"className":388,"code":389,"language":390,"meta":391,"style":391},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F good\napp.POST(\"\u002Fusers\", ezz.H(createUser))\n\n\u002F\u002F bad: rebuilds the binder on every request\napp.POST(\"\u002Fusers\", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    ezz.H(createUser).ServeHTTP(w, r)\n}))\n","go","",[214,393,394,403,448,455,461,525,556],{"__ignoreMap":391},[395,396,399],"span",{"class":397,"line":398},"line",1,[395,400,402],{"class":401},"sHwdD","\u002F\u002F good\n",[395,404,406,410,413,417,420,423,427,429,432,435,437,440,442,445],{"class":397,"line":405},2,[395,407,409],{"class":408},"sTEyZ","app",[395,411,352],{"class":412},"sMK4o",[395,414,416],{"class":415},"s2Zo4","POST",[395,418,419],{"class":412},"(",[395,421,422],{"class":412},"\"",[395,424,426],{"class":425},"sfazB","\u002Fusers",[395,428,422],{"class":412},[395,430,431],{"class":412},",",[395,433,434],{"class":408}," ezz",[395,436,352],{"class":412},[395,438,439],{"class":415},"H",[395,441,419],{"class":412},[395,443,444],{"class":408},"createUser",[395,446,447],{"class":412},"))\n",[395,449,451],{"class":397,"line":450},3,[395,452,454],{"emptyLinePlaceholder":453},true,"\n",[395,456,458],{"class":397,"line":457},4,[395,459,460],{"class":401},"\u002F\u002F bad: rebuilds the binder on every request\n",[395,462,464,466,468,470,472,474,476,478,480,483,485,488,491,495,498,500,503,505,508,511,514,516,519,522],{"class":397,"line":463},5,[395,465,409],{"class":408},[395,467,352],{"class":412},[395,469,416],{"class":415},[395,471,419],{"class":412},[395,473,422],{"class":412},[395,475,426],{"class":425},[395,477,422],{"class":412},[395,479,431],{"class":412},[395,481,482],{"class":408}," http",[395,484,352],{"class":412},[395,486,487],{"class":415},"HandlerFunc",[395,489,490],{"class":412},"(func(",[395,492,494],{"class":493},"sHdIc","w",[395,496,482],{"class":497},"sBMFI",[395,499,352],{"class":412},[395,501,502],{"class":497},"ResponseWriter",[395,504,431],{"class":412},[395,506,507],{"class":493}," r",[395,509,510],{"class":412}," *",[395,512,513],{"class":497},"http",[395,515,352],{"class":412},[395,517,518],{"class":497},"Request",[395,520,521],{"class":412},")",[395,523,524],{"class":412}," {\n",[395,526,528,531,533,535,537,539,542,545,547,549,551,553],{"class":397,"line":527},6,[395,529,530],{"class":408},"    ezz",[395,532,352],{"class":412},[395,534,439],{"class":415},[395,536,419],{"class":412},[395,538,444],{"class":408},[395,540,541],{"class":412},").",[395,543,544],{"class":415},"ServeHTTP",[395,546,419],{"class":412},[395,548,494],{"class":408},[395,550,431],{"class":412},[395,552,507],{"class":408},[395,554,555],{"class":412},")\n",[395,557,559],{"class":397,"line":558},7,[395,560,561],{"class":412},"}))\n",[178,563,564,567],{},[377,565,566],{},"Resolving authorization on every request."," A resolver that queries the database runs on each request that checks a role. Wrap it:",[386,569,571],{"className":388,"code":570,"language":390,"meta":391,"style":391},"authz := auth.Cached(resolver{db: db}, 5*time.Minute)\n",[214,572,573],{"__ignoreMap":391},[395,574,575,578,581,584,586,589,591,594,597,600,603,606,609,613,616,619,621,624],{"class":397,"line":398},[395,576,577],{"class":408},"authz ",[395,579,580],{"class":412},":=",[395,582,583],{"class":408}," auth",[395,585,352],{"class":412},[395,587,588],{"class":415},"Cached",[395,590,419],{"class":412},[395,592,593],{"class":497},"resolver",[395,595,596],{"class":412},"{",[395,598,599],{"class":408},"db",[395,601,602],{"class":412},":",[395,604,605],{"class":408}," db",[395,607,608],{"class":412},"},",[395,610,612],{"class":611},"sbssI"," 5",[395,614,615],{"class":412},"*",[395,617,618],{"class":408},"time",[395,620,352],{"class":412},[395,622,623],{"class":408},"Minute",[395,625,555],{"class":412},[178,627,628,631,632,635],{},[377,629,630],{},"Compressing tiny responses."," Gzip has a 1 KB floor by default for a reason. Raising ",[214,633,634],{},"MinLength"," costs nothing; lowering it burns CPU on payloads that will not shrink.",[178,637,638,641],{},[377,639,640],{},"Rate limiting with an unbounded key space."," The in-memory limiters keep a bucket per key with a periodic sweep. Keying by something high-cardinality, such as a full URL, grows the map faster than the sweep clears it. Key by client, tenant, or route.",[182,643,645],{"id":644},"benchmark-your-own-routes","Benchmark your own routes",[178,647,648],{},"The framework's own benchmarks live next to the code and run with the standard tooling:",[386,650,655],{"className":651,"code":652,"filename":653,"language":654,"meta":391,"style":391},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go test -bench=. -benchmem .\u002F...\nmake bench                          # writes results under the benchmark directory\nmake bench-quick                    # a shorter run\nmake bench-compare                  # compare against a stored baseline\n","Terminal","bash",[214,656,657,673,684,694],{"__ignoreMap":391},[395,658,659,661,664,667,670],{"class":397,"line":398},[395,660,390],{"class":497},[395,662,663],{"class":425}," test",[395,665,666],{"class":425}," -bench=.",[395,668,669],{"class":425}," -benchmem",[395,671,672],{"class":425}," .\u002F...\n",[395,674,675,678,681],{"class":397,"line":405},[395,676,677],{"class":497},"make",[395,679,680],{"class":425}," bench",[395,682,683],{"class":401},"                          # writes results under the benchmark directory\n",[395,685,686,688,691],{"class":397,"line":450},[395,687,677],{"class":497},[395,689,690],{"class":425}," bench-quick",[395,692,693],{"class":401},"                    # a shorter run\n",[395,695,696,698,701],{"class":397,"line":457},[395,697,677],{"class":497},[395,699,700],{"class":425}," bench-compare",[395,702,703],{"class":401},"                  # compare against a stored baseline\n",[178,705,706],{},"For your service, benchmark through the app so binding, validation, and auth are included:",[386,708,710],{"className":388,"code":709,"language":390,"meta":391,"style":391},"func BenchmarkCreateUser(b *testing.B) {\n    app := buildApp(memStore())\n    body := []byte(`{\"name\":\"Ada\",\"email\":\"ada@example.com\"}`)\n    token := \"Bearer \" + benchToken()\n\n    b.ReportAllocs()\n    b.ResetTimer()\n\n    for range b.N {\n        req := httptest.NewRequest(\"POST\", \"\u002Fapi\u002Fv1\u002Fusers\", bytes.NewReader(body))\n        req.Header.Set(\"Content-Type\", \"application\u002Fjson\")\n        req.Header.Set(\"Authorization\", token)\n\n        rec := httptest.NewRecorder()\n        app.ServeHTTP(rec, req)\n\n        if rec.Code != http.StatusOK {\n            b.Fatalf(\"unexpected status %d\", rec.Code)\n        }\n    }\n}\n",[214,711,712,739,757,783,807,811,823,834,839,860,910,946,975,980,997,1019,1024,1050,1085,1091,1097],{"__ignoreMap":391},[395,713,714,717,720,722,725,727,730,732,735,737],{"class":397,"line":398},[395,715,716],{"class":412},"func",[395,718,719],{"class":415}," BenchmarkCreateUser",[395,721,419],{"class":412},[395,723,724],{"class":493},"b",[395,726,510],{"class":412},[395,728,729],{"class":497},"testing",[395,731,352],{"class":412},[395,733,734],{"class":497},"B",[395,736,521],{"class":412},[395,738,524],{"class":412},[395,740,741,744,746,749,751,754],{"class":397,"line":405},[395,742,743],{"class":408},"    app ",[395,745,580],{"class":412},[395,747,748],{"class":415}," buildApp",[395,750,419],{"class":412},[395,752,753],{"class":415},"memStore",[395,755,756],{"class":412},"())\n",[395,758,759,762,764,767,771,773,776,779,781],{"class":397,"line":450},[395,760,761],{"class":408},"    body ",[395,763,580],{"class":412},[395,765,766],{"class":412}," []",[395,768,770],{"class":769},"spNyl","byte",[395,772,419],{"class":412},[395,774,775],{"class":412},"`",[395,777,778],{"class":425},"{\"name\":\"Ada\",\"email\":\"ada@example.com\"}",[395,780,775],{"class":412},[395,782,555],{"class":412},[395,784,785,788,790,793,796,798,801,804],{"class":397,"line":457},[395,786,787],{"class":408},"    token ",[395,789,580],{"class":412},[395,791,792],{"class":412}," \"",[395,794,795],{"class":425},"Bearer ",[395,797,422],{"class":412},[395,799,800],{"class":412}," +",[395,802,803],{"class":415}," benchToken",[395,805,806],{"class":412},"()\n",[395,808,809],{"class":397,"line":463},[395,810,454],{"emptyLinePlaceholder":453},[395,812,813,816,818,821],{"class":397,"line":527},[395,814,815],{"class":408},"    b",[395,817,352],{"class":412},[395,819,820],{"class":415},"ReportAllocs",[395,822,806],{"class":412},[395,824,825,827,829,832],{"class":397,"line":558},[395,826,815],{"class":408},[395,828,352],{"class":412},[395,830,831],{"class":415},"ResetTimer",[395,833,806],{"class":412},[395,835,837],{"class":397,"line":836},8,[395,838,454],{"emptyLinePlaceholder":453},[395,840,842,846,849,852,854,857],{"class":397,"line":841},9,[395,843,845],{"class":844},"s7zQu","    for",[395,847,848],{"class":844}," range",[395,850,851],{"class":408}," b",[395,853,352],{"class":412},[395,855,856],{"class":408},"N ",[395,858,859],{"class":412},"{\n",[395,861,863,866,868,871,873,876,878,880,882,884,886,888,891,893,895,898,900,903,905,908],{"class":397,"line":862},10,[395,864,865],{"class":408},"        req ",[395,867,580],{"class":412},[395,869,870],{"class":408}," httptest",[395,872,352],{"class":412},[395,874,875],{"class":415},"NewRequest",[395,877,419],{"class":412},[395,879,422],{"class":412},[395,881,416],{"class":425},[395,883,422],{"class":412},[395,885,431],{"class":412},[395,887,792],{"class":412},[395,889,890],{"class":425},"\u002Fapi\u002Fv1\u002Fusers",[395,892,422],{"class":412},[395,894,431],{"class":412},[395,896,897],{"class":408}," bytes",[395,899,352],{"class":412},[395,901,902],{"class":415},"NewReader",[395,904,419],{"class":412},[395,906,907],{"class":408},"body",[395,909,447],{"class":412},[395,911,913,916,918,921,923,926,928,930,933,935,937,939,942,944],{"class":397,"line":912},11,[395,914,915],{"class":408},"        req",[395,917,352],{"class":412},[395,919,920],{"class":408},"Header",[395,922,352],{"class":412},[395,924,925],{"class":415},"Set",[395,927,419],{"class":412},[395,929,422],{"class":412},[395,931,932],{"class":425},"Content-Type",[395,934,422],{"class":412},[395,936,431],{"class":412},[395,938,792],{"class":412},[395,940,941],{"class":425},"application\u002Fjson",[395,943,422],{"class":412},[395,945,555],{"class":412},[395,947,949,951,953,955,957,959,961,963,966,968,970,973],{"class":397,"line":948},12,[395,950,915],{"class":408},[395,952,352],{"class":412},[395,954,920],{"class":408},[395,956,352],{"class":412},[395,958,925],{"class":415},[395,960,419],{"class":412},[395,962,422],{"class":412},[395,964,965],{"class":425},"Authorization",[395,967,422],{"class":412},[395,969,431],{"class":412},[395,971,972],{"class":408}," token",[395,974,555],{"class":412},[395,976,978],{"class":397,"line":977},13,[395,979,454],{"emptyLinePlaceholder":453},[395,981,983,986,988,990,992,995],{"class":397,"line":982},14,[395,984,985],{"class":408},"        rec ",[395,987,580],{"class":412},[395,989,870],{"class":408},[395,991,352],{"class":412},[395,993,994],{"class":415},"NewRecorder",[395,996,806],{"class":412},[395,998,1000,1003,1005,1007,1009,1012,1014,1017],{"class":397,"line":999},15,[395,1001,1002],{"class":408},"        app",[395,1004,352],{"class":412},[395,1006,544],{"class":415},[395,1008,419],{"class":412},[395,1010,1011],{"class":408},"rec",[395,1013,431],{"class":412},[395,1015,1016],{"class":408}," req",[395,1018,555],{"class":412},[395,1020,1022],{"class":397,"line":1021},16,[395,1023,454],{"emptyLinePlaceholder":453},[395,1025,1027,1030,1033,1035,1038,1041,1043,1045,1048],{"class":397,"line":1026},17,[395,1028,1029],{"class":844},"        if",[395,1031,1032],{"class":408}," rec",[395,1034,352],{"class":412},[395,1036,1037],{"class":408},"Code ",[395,1039,1040],{"class":412},"!=",[395,1042,482],{"class":408},[395,1044,352],{"class":412},[395,1046,1047],{"class":408},"StatusOK ",[395,1049,859],{"class":412},[395,1051,1053,1056,1058,1061,1063,1065,1068,1072,1074,1076,1078,1080,1083],{"class":397,"line":1052},18,[395,1054,1055],{"class":408},"            b",[395,1057,352],{"class":412},[395,1059,1060],{"class":415},"Fatalf",[395,1062,419],{"class":412},[395,1064,422],{"class":412},[395,1066,1067],{"class":425},"unexpected status ",[395,1069,1071],{"class":1070},"swJcz","%d",[395,1073,422],{"class":412},[395,1075,431],{"class":412},[395,1077,1032],{"class":408},[395,1079,352],{"class":412},[395,1081,1082],{"class":408},"Code",[395,1084,555],{"class":412},[395,1086,1088],{"class":397,"line":1087},19,[395,1089,1090],{"class":412},"        }\n",[395,1092,1094],{"class":397,"line":1093},20,[395,1095,1096],{"class":412},"    }\n",[395,1098,1100],{"class":397,"line":1099},21,[395,1101,1102],{"class":412},"}\n",[178,1104,1105,1108,1109,1111],{},[214,1106,1107],{},"httptest.NewRequest"," and ",[214,1110,994],{}," allocate on every iteration, so treat the numbers as a relative measure across changes rather than an absolute throughput figure.",[178,1113,1114],{},"To profile a hot path:",[386,1116,1118],{"className":651,"code":1117,"filename":653,"language":654,"meta":391,"style":391},"go test -bench=BenchmarkCreateUser -cpuprofile cpu.out .\u002F...\ngo tool pprof -http=:8081 cpu.out\n",[214,1119,1120,1137],{"__ignoreMap":391},[395,1121,1122,1124,1126,1129,1132,1135],{"class":397,"line":398},[395,1123,390],{"class":497},[395,1125,663],{"class":425},[395,1127,1128],{"class":425}," -bench=BenchmarkCreateUser",[395,1130,1131],{"class":425}," -cpuprofile",[395,1133,1134],{"class":425}," cpu.out",[395,1136,672],{"class":425},[395,1138,1139,1141,1144,1147,1150],{"class":397,"line":405},[395,1140,390],{"class":497},[395,1142,1143],{"class":425}," tool",[395,1145,1146],{"class":425}," pprof",[395,1148,1149],{"class":425}," -http=:8081",[395,1151,1152],{"class":425}," cpu.out\n",[178,1154,1155,1108,1158,1161],{},[214,1156,1157],{},"make bench-cpu",[214,1159,1160],{},"make bench-mem"," wrap the same thing for the framework's own suite.",[182,1163,1165],{"id":1164},"configure-the-server-for-production","Configure the server for production",[178,1167,1168,1171,1172,1175],{},[214,1169,1170],{},"app.Listen(addr)"," calls ",[214,1173,1174],{},"http.ListenAndServe"," with no timeouts, which leaves you exposed to slow clients. In production, build the server yourself:",[386,1177,1179],{"className":388,"code":1178,"language":390,"meta":391,"style":391},"srv := &http.Server{\n    Addr:              \":8080\",\n    Handler:           app,\n    ReadHeaderTimeout: 5 * time.Second,\n    ReadTimeout:       15 * time.Second,\n    WriteTimeout:      30 * time.Second,\n    IdleTimeout:       60 * time.Second,\n    MaxHeaderBytes:    1 \u003C\u003C 20,\n}\n\ngo func() {\n    if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {\n        log.Fatal(err)\n    }\n}()\n\nstop := make(chan os.Signal, 1)\nsignal.Notify(stop, os.Interrupt, syscall.SIGTERM)\n\u003C-stop\n\nctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\ndefer cancel()\n_ = srv.Shutdown(ctx)\n",[214,1180,1181,1200,1218,1230,1251,1271,1291,1311,1329,1333,1337,1346,1406,1422,1426,1431,1435,1463,1499,1507,1511,1557,1568],{"__ignoreMap":391},[395,1182,1183,1186,1188,1191,1193,1195,1198],{"class":397,"line":398},[395,1184,1185],{"class":408},"srv ",[395,1187,580],{"class":412},[395,1189,1190],{"class":412}," &",[395,1192,513],{"class":497},[395,1194,352],{"class":412},[395,1196,1197],{"class":497},"Server",[395,1199,859],{"class":412},[395,1201,1202,1205,1207,1210,1213,1215],{"class":397,"line":405},[395,1203,1204],{"class":408},"    Addr",[395,1206,602],{"class":412},[395,1208,1209],{"class":412},"              \"",[395,1211,1212],{"class":425},":8080",[395,1214,422],{"class":412},[395,1216,1217],{"class":412},",\n",[395,1219,1220,1223,1225,1228],{"class":397,"line":450},[395,1221,1222],{"class":408},"    Handler",[395,1224,602],{"class":412},[395,1226,1227],{"class":408},"           app",[395,1229,1217],{"class":412},[395,1231,1232,1235,1237,1239,1241,1244,1246,1249],{"class":397,"line":457},[395,1233,1234],{"class":408},"    ReadHeaderTimeout",[395,1236,602],{"class":412},[395,1238,612],{"class":611},[395,1240,510],{"class":412},[395,1242,1243],{"class":408}," time",[395,1245,352],{"class":412},[395,1247,1248],{"class":408},"Second",[395,1250,1217],{"class":412},[395,1252,1253,1256,1258,1261,1263,1265,1267,1269],{"class":397,"line":463},[395,1254,1255],{"class":408},"    ReadTimeout",[395,1257,602],{"class":412},[395,1259,1260],{"class":611},"       15",[395,1262,510],{"class":412},[395,1264,1243],{"class":408},[395,1266,352],{"class":412},[395,1268,1248],{"class":408},[395,1270,1217],{"class":412},[395,1272,1273,1276,1278,1281,1283,1285,1287,1289],{"class":397,"line":527},[395,1274,1275],{"class":408},"    WriteTimeout",[395,1277,602],{"class":412},[395,1279,1280],{"class":611},"      30",[395,1282,510],{"class":412},[395,1284,1243],{"class":408},[395,1286,352],{"class":412},[395,1288,1248],{"class":408},[395,1290,1217],{"class":412},[395,1292,1293,1296,1298,1301,1303,1305,1307,1309],{"class":397,"line":558},[395,1294,1295],{"class":408},"    IdleTimeout",[395,1297,602],{"class":412},[395,1299,1300],{"class":611},"       60",[395,1302,510],{"class":412},[395,1304,1243],{"class":408},[395,1306,352],{"class":412},[395,1308,1248],{"class":408},[395,1310,1217],{"class":412},[395,1312,1313,1316,1318,1321,1324,1327],{"class":397,"line":836},[395,1314,1315],{"class":408},"    MaxHeaderBytes",[395,1317,602],{"class":412},[395,1319,1320],{"class":611},"    1",[395,1322,1323],{"class":412}," \u003C\u003C",[395,1325,1326],{"class":611}," 20",[395,1328,1217],{"class":412},[395,1330,1331],{"class":397,"line":841},[395,1332,1102],{"class":412},[395,1334,1335],{"class":397,"line":862},[395,1336,454],{"emptyLinePlaceholder":453},[395,1338,1339,1341,1344],{"class":397,"line":912},[395,1340,390],{"class":844},[395,1342,1343],{"class":412}," func()",[395,1345,524],{"class":412},[395,1347,1348,1351,1354,1356,1359,1361,1364,1367,1369,1371,1374,1377,1380,1383,1385,1388,1390,1393,1395,1397,1399,1402,1404],{"class":397,"line":948},[395,1349,1350],{"class":844},"    if",[395,1352,1353],{"class":408}," err ",[395,1355,580],{"class":412},[395,1357,1358],{"class":408}," srv",[395,1360,352],{"class":412},[395,1362,1363],{"class":415},"ListenAndServe",[395,1365,1366],{"class":412},"();",[395,1368,1353],{"class":408},[395,1370,1040],{"class":412},[395,1372,1373],{"class":412}," nil",[395,1375,1376],{"class":412}," &&",[395,1378,1379],{"class":412}," !",[395,1381,1382],{"class":408},"errors",[395,1384,352],{"class":412},[395,1386,1387],{"class":415},"Is",[395,1389,419],{"class":412},[395,1391,1392],{"class":408},"err",[395,1394,431],{"class":412},[395,1396,482],{"class":408},[395,1398,352],{"class":412},[395,1400,1401],{"class":408},"ErrServerClosed",[395,1403,521],{"class":412},[395,1405,524],{"class":412},[395,1407,1408,1411,1413,1416,1418,1420],{"class":397,"line":977},[395,1409,1410],{"class":408},"        log",[395,1412,352],{"class":412},[395,1414,1415],{"class":415},"Fatal",[395,1417,419],{"class":412},[395,1419,1392],{"class":408},[395,1421,555],{"class":412},[395,1423,1424],{"class":397,"line":982},[395,1425,1096],{"class":412},[395,1427,1428],{"class":397,"line":999},[395,1429,1430],{"class":412},"}()\n",[395,1432,1433],{"class":397,"line":1021},[395,1434,454],{"emptyLinePlaceholder":453},[395,1436,1437,1440,1442,1445,1448,1451,1453,1456,1458,1461],{"class":397,"line":1026},[395,1438,1439],{"class":408},"stop ",[395,1441,580],{"class":412},[395,1443,1444],{"class":415}," make",[395,1446,1447],{"class":412},"(chan",[395,1449,1450],{"class":497}," os",[395,1452,352],{"class":412},[395,1454,1455],{"class":497},"Signal",[395,1457,431],{"class":412},[395,1459,1460],{"class":611}," 1",[395,1462,555],{"class":412},[395,1464,1465,1468,1470,1473,1475,1478,1480,1482,1484,1487,1489,1492,1494,1497],{"class":397,"line":1052},[395,1466,1467],{"class":408},"signal",[395,1469,352],{"class":412},[395,1471,1472],{"class":415},"Notify",[395,1474,419],{"class":412},[395,1476,1477],{"class":408},"stop",[395,1479,431],{"class":412},[395,1481,1450],{"class":408},[395,1483,352],{"class":412},[395,1485,1486],{"class":408},"Interrupt",[395,1488,431],{"class":412},[395,1490,1491],{"class":408}," syscall",[395,1493,352],{"class":412},[395,1495,1496],{"class":408},"SIGTERM",[395,1498,555],{"class":412},[395,1500,1501,1504],{"class":397,"line":1087},[395,1502,1503],{"class":412},"\u003C-",[395,1505,1506],{"class":408},"stop\n",[395,1508,1509],{"class":397,"line":1093},[395,1510,454],{"emptyLinePlaceholder":453},[395,1512,1513,1516,1518,1521,1523,1526,1528,1531,1533,1536,1538,1541,1544,1547,1549,1551,1553,1555],{"class":397,"line":1099},[395,1514,1515],{"class":408},"ctx",[395,1517,431],{"class":412},[395,1519,1520],{"class":408}," cancel ",[395,1522,580],{"class":412},[395,1524,1525],{"class":408}," context",[395,1527,352],{"class":412},[395,1529,1530],{"class":415},"WithTimeout",[395,1532,419],{"class":412},[395,1534,1535],{"class":408},"context",[395,1537,352],{"class":412},[395,1539,1540],{"class":415},"Background",[395,1542,1543],{"class":412},"(),",[395,1545,1546],{"class":611}," 10",[395,1548,615],{"class":412},[395,1550,618],{"class":408},[395,1552,352],{"class":412},[395,1554,1248],{"class":408},[395,1556,555],{"class":412},[395,1558,1560,1563,1566],{"class":397,"line":1559},22,[395,1561,1562],{"class":844},"defer",[395,1564,1565],{"class":415}," cancel",[395,1567,806],{"class":412},[395,1569,1571,1574,1577,1579,1581,1584,1586,1588],{"class":397,"line":1570},23,[395,1572,1573],{"class":408},"_ ",[395,1575,1576],{"class":412},"=",[395,1578,1358],{"class":408},[395,1580,352],{"class":412},[395,1582,1583],{"class":415},"Shutdown",[395,1585,419],{"class":412},[395,1587,1515],{"class":408},[395,1589,555],{"class":412},[178,1591,1592,1593,1596],{},"Long-lived streaming routes need a ",[214,1594,1595],{},"WriteTimeout"," of zero, or their own server, since the timeout applies to the whole response.",[182,1598,1600],{"id":1599},"next-steps","Next steps",[1602,1603,1604,1610],"ul",{},[1605,1606,1607,1609],"li",{},[349,1608,63],{"href":64}," for what runs on every request.",[1605,1611,1612,1615],{},[349,1613,1614],{"href":90},"Roles and permissions"," for caching authorization lookups.",[1617,1618,1619],"style",{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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 pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":391,"searchDepth":405,"depth":405,"links":1621},[1622,1623,1624,1625,1626,1627],{"id":184,"depth":405,"text":185},{"id":256,"depth":405,"text":257},{"id":369,"depth":405,"text":370},{"id":644,"depth":405,"text":645},{"id":1164,"depth":405,"text":1165},{"id":1599,"depth":405,"text":1600},"What ezz precomputes and pools, the rules that keeps, and how to benchmark your own service.","md",null,{},{"icon":155},{"title":152,"description":1628},"JVJrzU6mmxkEH-6gDrCErqik_3Pjh8L9M0Qd6ynQ33Y",[1636,1638],{"title":147,"path":148,"stem":149,"description":1637,"icon":150,"children":-1},"Test handlers, routes, and auth with httptest or the built-in test helpers.",{"title":157,"path":158,"stem":159,"description":1639,"icon":160,"children":-1},"Cut a version of ezz that consuming services can actually resolve, and know when a change forces a major version.",1784970045270]