[{"data":1,"prerenderedAt":1142},["ShallowReactive",2],{"navigation_docs":3,"-guide-lifetimes":93,"-guide-lifetimes-surround":1137},[4,71],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":70},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,18,22,26,30,34,38,42,46,50,54,58,62,66],{"title":11,"path":12,"stem":13},"Getting started","\u002Fguide\u002Fgetting-started","1.guide\u002F01.getting-started",{"title":15,"path":16,"stem":17},"Adoption paths","\u002Fguide\u002Fadoption","1.guide\u002F02.adoption",{"title":19,"path":20,"stem":21},"Routes and typed $fetch","\u002Fguide\u002Froutes","1.guide\u002F02.routes",{"title":23,"path":24,"stem":25},"Kyo handlers","\u002Fguide\u002Fkyo","1.guide\u002F03.kyo",{"title":27,"path":28,"stem":29},"ZIO handlers","\u002Fguide\u002Fzio","1.guide\u002F04.zio",{"title":31,"path":32,"stem":33},"Configuration and secrets","\u002Fguide\u002Fconfiguration","1.guide\u002F05.configuration",{"title":35,"path":36,"stem":37},"Application and request lifetimes","\u002Fguide\u002Flifetimes","1.guide\u002F06.lifetimes",{"title":39,"path":40,"stem":41},"Schemas","\u002Fguide\u002Fschema","1.guide\u002F07.schema",{"title":43,"path":44,"stem":45},"PostgreSQL","\u002Fguide\u002Fdatabase","1.guide\u002F08.database",{"title":47,"path":48,"stem":49},"Streaming and cancellation","\u002Fguide\u002Fstreaming","1.guide\u002F09.streaming",{"title":51,"path":52,"stem":53},"Testing","\u002Fguide\u002Ftesting","1.guide\u002F10.testing",{"title":55,"path":56,"stem":57},"Nitro storage and NuxtHub KV","\u002Fguide\u002Fstorage","1.guide\u002F11.storage",{"title":59,"path":60,"stem":61},"Debug Scala handlers","\u002Fguide\u002Fdebugging","1.guide\u002F12.debugging",{"title":63,"path":64,"stem":65},"npm build tooling","\u002Fguide\u002Fnpm-tooling","1.guide\u002F13.npm-tooling",{"title":67,"path":68,"stem":69},"Set up h34s with a coding assistant","\u002Fguide\u002Fagent-setup","1.guide\u002F14.agent-setup",false,{"title":72,"icon":73,"path":74,"stem":75,"children":76,"page":70},"Reference","i-lucide-library","\u002Freference","2.reference",[77,81,85,89],{"title":78,"path":79,"stem":80},"Architecture","\u002Freference\u002Farchitecture","2.reference\u002F1.architecture",{"title":82,"path":83,"stem":84},"Releases","\u002Freference\u002Freleases","2.reference\u002F2.releases",{"title":86,"path":87,"stem":88},"Compatibility","\u002Freference\u002Fcompatibility","2.reference\u002F3.compatibility",{"title":90,"path":91,"stem":92},"Migration guide","\u002Freference\u002Fmigration","2.reference\u002F4.migration",{"id":94,"title":35,"body":95,"description":1131,"extension":1132,"links":1133,"meta":1134,"navigation":839,"path":36,"seo":1135,"stem":37,"__hash__":1136},"docs\u002F1.guide\u002F06.lifetimes.md",{"type":96,"value":97,"toc":1123},"minimark",[98,102,172,175,192,197,200,228,231,251,281,298,467,473,483,486,493,537,548,551,572,600,615,621,624,628,636,679,688,698,760,778,785,937,947,982,995,1012,1016,1021,1025,1036,1065,1077,1083,1087,1119],[99,100,101],"p",{},"Every resource has an owner and a lifetime. h34s gives you two scopes:",[103,104,105,124],"table",{},[106,107,108],"thead",{},[109,110,111,115,118,121],"tr",{},[112,113,114],"th",{},"Lifetime",[112,116,117],{},"Use it for",[112,119,120],{},"Kyo",[112,122,123],{},"ZIO",[125,126,127,154],"tbody",{},[109,128,129,133,136,147],{},[130,131,132],"td",{},"One request",[130,134,135],{},"A pooled connection, a transaction, a temporary file, a stream's source",[130,137,138,139,143,144],{},"The request ",[140,141,142],"code",{},"Scope"," in ",[140,145,146],{},"HandlerEffects",[130,148,138,149,143,151],{},[140,150,142],{},[140,152,153],{},"HandlerEnv",[109,155,156,159,162,167],{},[130,157,158],{},"The whole application",[130,160,161],{},"A connection pool, an HTTP client, a cache handle",[130,163,164],{},[140,165,166],{},"Shared",[130,168,169],{},[140,170,171],{},"ZShared",[99,173,174],{},"Choose the shortest lifetime that works. Open request resources inside the handler; open application resources once.",[99,176,177,181,182,184,185,187,188,191],{},[178,179,180],"strong",{},"Status."," ",[140,183,166],{}," and ",[140,186,171],{}," are new in ",[140,189,190],{},"0.2.0-alpha.1",".",[193,194,196],"h2",{"id":195},"request-resources","Request resources",[99,198,199],{},"The core runs every handler in a request scope. Acquire a resource in that scope, and h34s releases it when the request is done:",[201,202,203,213],"ul",{},[204,205,206,207,184,210,191],"li",{},"Kyo: ",[140,208,209],{},"Scope.acquireRelease(acquire)(release)",[140,211,212],{},"Scope.ensure(finalizer)",[204,214,215,216,219,220,223,224,227],{},"ZIO: ",[140,217,218],{},"ZIO.acquireRelease(acquire)(release)",", ",[140,221,222],{},"ZIO.addFinalizer",", or a scoped ",[140,225,226],{},"ZLayer"," you provide inside the handler.",[99,229,230],{},"\"Done\" means:",[201,232,233,240,243],{},[204,234,235,236,239],{},"For a value or ",[140,237,238],{},"Unit"," body: after your program finishes, before h34s writes the response. Asynchronous finalizers finish before the response settles.",[204,241,242],{},"For a streamed body: after the stream ends, fails, or is cancelled.",[204,244,245,246,191],{},"When the client disconnects: h34s interrupts the program, waits for the finalizers, and writes nothing. See ",[247,248,250],"a",{"href":249},"#when-the-client-disconnects","When the client disconnects",[99,252,253,254,256,257,260,261,264,265,268,269,272,273,276,277,191],{},"A finalizer that checks the outcome, to commit or roll back, needs a scope that sees it. In ZIO, the request ",[140,255,142],{}," closes with your program's ",[140,258,259],{},"Exit",", so ",[140,262,263],{},"ZIO.addFinalizerExit"," there sees a failure. In Kyo, h34s closes the request scope after your program, without its outcome: a ",[140,266,267],{},"Scope.ensure"," finalizer there always gets ",[140,270,271],{},"Absent",". Write a ",[140,274,275],{},"Scope.run"," inside your handler around the steps whose outcome you need; see ",[247,278,280],{"href":279},"\u002Fguide\u002Fstreaming#roll-back-when-a-stream-fails","roll back when a stream fails",[99,282,283,284,287,288,290,291,293,294,297],{},"The demo's ZIO handlers take at most one pooled Skunk session per request this way. ",[140,285,286],{},"NotesLive.layer"," reads the request ",[140,289,142],{}," from ",[140,292,153],{}," and takes the session on first use (",[140,295,296],{},"memoize","), so a request that fails validation never touches the pool, and the session returns to the pool when the request ends:",[299,300,305],"pre",{"className":301,"code":302,"language":303,"meta":304,"style":304},"language-scala shiki shiki-themes github-light github-light github-dark","\u002F** Notes over at most one pooled session per request. The session is taken on first use, so a\n  * handler that rejects its input never touches the pool, and it returns to the pool when the\n  * request scope closes.\n  *\u002F\nval layer: ZLayer[SessionPool & Scope, Nothing, Notes] =\n  ZLayer.fromZIO(\n    for\n      pool    \u003C- ZIO.service[SessionPool]\n      scope   \u003C- ZIO.service[Scope]\n      session \u003C- pool.session.provideEnvironment(ZEnvironment(scope)).memoize\n    yield NotesLive(session),\n  )\n","scala","",[140,306,307,316,322,328,334,381,390,396,416,432,449,461],{"__ignoreMap":304},[308,309,312],"span",{"class":310,"line":311},"line",1,[308,313,315],{"class":314},"sCsY4","\u002F** Notes over at most one pooled session per request. The session is taken on first use, so a\n",[308,317,319],{"class":310,"line":318},2,[308,320,321],{"class":314},"  * handler that rejects its input never touches the pool, and it returns to the pool when the\n",[308,323,325],{"class":310,"line":324},3,[308,326,327],{"class":314},"  * request scope closes.\n",[308,329,331],{"class":310,"line":330},4,[308,332,333],{"class":314},"  *\u002F\n",[308,335,337,341,345,348,352,356,359,362,365,367,370,372,375,378],{"class":310,"line":336},5,[308,338,340],{"class":339},"s8jYJ","val",[308,342,344],{"class":343},"sP4rz"," layer",[308,346,347],{"class":339},":",[308,349,351],{"class":350},"snPdu"," ZLayer",[308,353,355],{"class":354},"sxrX7","[",[308,357,358],{"class":350},"SessionPool",[308,360,361],{"class":339}," &",[308,363,364],{"class":350}," Scope",[308,366,219],{"class":354},[308,368,369],{"class":350},"Nothing",[308,371,219],{"class":354},[308,373,374],{"class":350},"Notes",[308,376,377],{"class":354},"] ",[308,379,380],{"class":339},"=\n",[308,382,384,387],{"class":310,"line":383},6,[308,385,386],{"class":350},"  ZLayer",[308,388,389],{"class":354},".fromZIO(\n",[308,391,393],{"class":310,"line":392},7,[308,394,395],{"class":339},"    for\n",[308,397,399,402,405,408,411,413],{"class":310,"line":398},8,[308,400,401],{"class":354},"      pool    ",[308,403,404],{"class":339},"\u003C-",[308,406,407],{"class":350}," ZIO",[308,409,410],{"class":354},".service[",[308,412,358],{"class":350},[308,414,415],{"class":354},"]\n",[308,417,419,422,424,426,428,430],{"class":310,"line":418},9,[308,420,421],{"class":354},"      scope   ",[308,423,404],{"class":339},[308,425,407],{"class":350},[308,427,410],{"class":354},[308,429,142],{"class":350},[308,431,415],{"class":354},[308,433,435,438,440,443,446],{"class":310,"line":434},10,[308,436,437],{"class":354},"      session ",[308,439,404],{"class":339},[308,441,442],{"class":354}," pool.session.provideEnvironment(",[308,444,445],{"class":350},"ZEnvironment",[308,447,448],{"class":354},"(scope)).memoize\n",[308,450,452,455,458],{"class":310,"line":451},11,[308,453,454],{"class":339},"    yield",[308,456,457],{"class":350}," NotesLive",[308,459,460],{"class":354},"(session),\n",[308,462,464],{"class":310,"line":463},12,[308,465,466],{"class":354},"  )\n",[99,468,469,472],{},[140,470,471],{},"NotesHandlerSpec"," checks this with a pool whose database is down: invalid input takes no session and is a 422; valid input takes one session and fails.",[99,474,475,476,478,479,482],{},"A failing finalizer is logged on the server and does not change the response, in both runtimes. Kyo 1.0.0-RC7 logs a failing ",[140,477,142],{}," finalizer. The ZIO adapter logs a dying ZIO finalizer as ",[140,480,481],{},"h34s: a ZIO finalizer failed",". Do work that must affect the response in the program, not in a finalizer: the client never learns that a finalizer failed.",[193,484,250],{"id":485},"when-the-client-disconnects",[99,487,488,489,492],{},"A client can leave before your handler finishes: the user closes the tab, or the frontend aborts its ",[140,490,491],{},"fetch",". Kyo and ZIO handlers behave the same way:",[494,495,496,499,514,534],"ol",{},[204,497,498],{},"h34s interrupts your program. In ZIO, the handler's fiber is interrupted.",[204,500,501,502,184,505,507,508,219,511,513],{},"Your finalizers run: ",[140,503,504],{},"Scope.acquireRelease",[140,506,267],{}," in Kyo, ",[140,509,510],{},"ZIO.acquireRelease",[140,512,222],{}," and scoped layers in ZIO.",[204,515,516,517,219,520,219,523,219,526,529,530,533],{},"h34s waits for those finalizers, including asynchronous ones, before it tells h3 and Nitro that the request is over. This includes work that your handler forks with Kyo's structured combinators (",[140,518,519],{},"Async.timeout",[140,521,522],{},"Async.race",[140,524,525],{},"Async.gather",[140,527,528],{},"Async.zip",", a concurrent ",[140,531,532],{},"Async.foreach",") and ZIO child fibers: they are interrupted, and their cleanup finishes first.",[204,535,536],{},"h34s writes nothing to the closed connection.",[99,538,539,540,543,544,547],{},"The exception is work on a fiber that nothing owns: Kyo's ",[140,541,542],{},"Fiber.initUnscoped",", and the fiber that Kyo's ",[140,545,546],{},"Async.uninterruptible"," starts. h34s cannot wait for it, so do not use request resources there.",[99,549,550],{},"Interruption can stop work that you expected to finish. If the client leaves during a database transaction, the transaction can roll back instead of committing. For a step that must complete even when the client leaves, make that step uninterruptible:",[201,552,553,562],{},[204,554,206,555,558,559,561],{},[140,556,557],{},"KHandler.uninterruptible(step)",". The step runs on its own fiber that the interrupt cannot reach, and the request scope waits for it before it releases resources acquired earlier (such as the connection the step uses). Do not use Kyo's ",[140,560,546],{}," alone in a handler: it protects the step, but the request settles and releases its resources while the step still runs.",[204,563,215,564,567,568,571],{},[140,565,566],{},"step.uninterruptible",", or ",[140,569,570],{},"ZIO.uninterruptibleMask"," when only part of the step must be protected. ZIO delays the interrupt until the step ends, and h34s waits for the fiber.",[299,573,575],{"className":301,"code":574,"language":303,"meta":304,"style":304},"\u002F\u002F Kyo, with the kyo-sql service from the database guide: the insert and its commit finish even if\n\u002F\u002F the client leaves; then earlier request resources are released; then the request settles.\nnote \u003C- KHandler.uninterruptible(notes.create(input.text))\n",[140,576,577,582,587],{"__ignoreMap":304},[308,578,579],{"class":310,"line":311},[308,580,581],{"class":314},"\u002F\u002F Kyo, with the kyo-sql service from the database guide: the insert and its commit finish even if\n",[308,583,584],{"class":310,"line":318},[308,585,586],{"class":314},"\u002F\u002F the client leaves; then earlier request resources are released; then the request settles.\n",[308,588,589,592,594,597],{"class":310,"line":324},[308,590,591],{"class":354},"note ",[308,593,404],{"class":339},[308,595,596],{"class":350}," KHandler",[308,598,599],{"class":354},".uninterruptible(notes.create(input.text))\n",[99,601,602,603,606,607,610,611,614],{},"The step needs only ",[140,604,605],{},"Async & Abort[Throwable]",": provide its other effects inside it (kyo-sql's ",[140,608,609],{},"DB.run(client)"," does). This line compiles against kyo-sql-postgres 1.0.0-RC7 (see ",[247,612,613],{"href":44},"database","); the order is tested with a sleeping step, not with a database.",[99,616,617,618,620],{},"Keep uninterruptible regions small. A client disconnect cannot stop them, so h34s waits for them to finish before it settles the request. Tests in both runtimes disconnect during such a step and check the order: the step ends, then the request finalizers run, then the request settles. A Kyo test also documents that ",[140,619,546],{}," alone does not wait.",[99,622,623],{},"Interruption does not cancel JavaScript work that has already started, for example a storage Promise. h34s stops waiting for it; the work itself finishes or fails on its own.",[193,625,627],{"id":626},"application-resources","Application resources",[99,629,630,632,633,635],{},[140,631,166],{}," (Kyo) and ",[140,634,171],{}," (ZIO) hold one resource for all requests:",[201,637,638,645,651,654,657,666],{},[204,639,640,641,644],{},"The first ",[140,642,643],{},"get"," acquires it. Concurrent first calls share one acquisition.",[204,646,647,648,650],{},"A failed acquisition is not cached. The next ",[140,649,643],{}," tries again.",[204,652,653],{},"The acquisition runs on its own fiber. A request that is cancelled while it waits does not cancel the acquisition for the others.",[204,655,656],{},"When the acquisition succeeds, h34s registers the resource with the Nitro close hook.",[204,658,659,662,663,665],{},[140,660,661],{},"close"," releases it and waits for its finalizers. A later ",[140,664,643],{}," acquires it again.",[204,667,668,669,671,672,674,675,678],{},"A ",[140,670,661],{}," during the first acquisition releases the value as soon as it is acquired. The ",[140,673,643],{}," calls that waited for it fail with ",[140,676,677],{},"IllegalStateException","; none receives a released value.",[99,680,681,682,685,686,191],{},"Declare a shared resource once, as a member of an ",[140,683,684],{},"object",". Nothing runs until the first ",[140,687,643],{},[99,689,690,691,694,695,697],{},"Kyo, with any ",[140,692,693],{},"A \u003C (Async & Scope & Abort[Throwable])"," acquisition. The ",[140,696,142],{}," here is the resource's own scope, not a request's:",[299,699,701],{"className":301,"code":700,"language":303,"meta":304,"style":304},"object Resources:\n    val pool: Shared[Pool] = Shared(\n      Scope.acquireRelease(openPool)(pool => closePool(pool)),\n    )\n",[140,702,703,713,741,755],{"__ignoreMap":304},[308,704,705,707,710],{"class":310,"line":311},[308,706,684],{"class":339},[308,708,709],{"class":350}," Resources",[308,711,712],{"class":339},":\n",[308,714,715,718,721,723,726,728,731,733,736,738],{"class":310,"line":318},[308,716,717],{"class":339},"    val",[308,719,720],{"class":343}," pool",[308,722,347],{"class":339},[308,724,725],{"class":350}," Shared",[308,727,355],{"class":354},[308,729,730],{"class":350},"Pool",[308,732,377],{"class":354},[308,734,735],{"class":339},"=",[308,737,725],{"class":350},[308,739,740],{"class":354},"(\n",[308,742,743,746,749,752],{"class":310,"line":324},[308,744,745],{"class":350},"      Scope",[308,747,748],{"class":354},".acquireRelease(openPool)(pool ",[308,750,751],{"class":339},"=>",[308,753,754],{"class":354}," closePool(pool)),\n",[308,756,757],{"class":310,"line":330},[308,758,759],{"class":354},"    )\n",[99,761,762,219,765,184,768,770,771,774,775,191],{},[140,763,764],{},"openPool",[140,766,767],{},"closePool",[140,769,730],{}," stand for your own code. Use it in a handler with ",[140,772,773],{},"Resources.pool.get",", which is ",[140,776,777],{},"Pool \u003C (Async & Abort[Throwable])",[99,779,780,781,784],{},"The Kyo demo (",[140,782,783],{},"AppHandler.scala",") builds its greeting service this way, from the startup config, and provides it to every handler:",[299,786,788],{"className":301,"code":787,"language":303,"meta":304,"style":304},"val greetings: Shared[Greetings] = Shared(RuntimeConfig.load[KyoConfig].map(config => Greetings.live(config.greeting)))\n\ndef define[B: ResponseBody](program: Request => B \u003C (HandlerEffects & Env[Greetings]))(using Frame): EventHandler =\n  KHandler.define(options)(request => Services.greetings.get.map(greetings => Env.run(greetings)(program(request))))\n",[140,789,790,835,841,914],{"__ignoreMap":304},[308,791,792,794,797,799,801,803,806,808,810,812,815,818,821,824,827,829,832],{"class":310,"line":311},[308,793,340],{"class":339},[308,795,796],{"class":343}," greetings",[308,798,347],{"class":339},[308,800,725],{"class":350},[308,802,355],{"class":354},[308,804,805],{"class":350},"Greetings",[308,807,377],{"class":354},[308,809,735],{"class":339},[308,811,725],{"class":350},[308,813,814],{"class":354},"(",[308,816,817],{"class":350},"RuntimeConfig",[308,819,820],{"class":354},".load[",[308,822,823],{"class":350},"KyoConfig",[308,825,826],{"class":354},"].map(config ",[308,828,751],{"class":339},[308,830,831],{"class":350}," Greetings",[308,833,834],{"class":354},".live(config.greeting)))\n",[308,836,837],{"class":310,"line":318},[308,838,840],{"emptyLinePlaceholder":839},true,"\n",[308,842,843,846,849,851,854,856,859,862,865,868,871,874,877,880,883,885,887,890,892,894,897,900,903,906,908,911],{"class":310,"line":324},[308,844,845],{"class":339},"def",[308,847,848],{"class":350}," define",[308,850,355],{"class":354},[308,852,853],{"class":350},"B",[308,855,347],{"class":339},[308,857,858],{"class":350}," ResponseBody",[308,860,861],{"class":354},"](",[308,863,864],{"class":343},"program",[308,866,867],{"class":354},": ",[308,869,870],{"class":350},"Request",[308,872,873],{"class":339}," =>",[308,875,876],{"class":350}," B",[308,878,879],{"class":339}," \u003C",[308,881,882],{"class":354}," (",[308,884,146],{"class":350},[308,886,361],{"class":339},[308,888,889],{"class":350}," Env",[308,891,355],{"class":354},[308,893,805],{"class":350},[308,895,896],{"class":354},"]))(",[308,898,899],{"class":339},"using",[308,901,902],{"class":350}," Frame",[308,904,905],{"class":354},")",[308,907,347],{"class":339},[308,909,910],{"class":350}," EventHandler",[308,912,913],{"class":339}," =\n",[308,915,916,919,922,924,927,930,932,934],{"class":310,"line":330},[308,917,918],{"class":350},"  KHandler",[308,920,921],{"class":354},".define(options)(request ",[308,923,751],{"class":339},[308,925,926],{"class":350}," Services",[308,928,929],{"class":354},".greetings.get.map(greetings ",[308,931,751],{"class":339},[308,933,889],{"class":350},[308,935,936],{"class":354},".run(greetings)(program(request))))\n",[99,938,939,940,943,944,946],{},"ZIO, with any ",[140,941,942],{},"ZLayer[Any, E, R]",". This is the demo's (",[140,945,783],{},"):",[299,948,950],{"className":301,"code":949,"language":303,"meta":304,"style":304},"\u002F** One Skunk pool for all requests: built on first use, released when Nitro closes. *\u002F\nprivate val database = ZShared.layer(SessionPool.layer)\n",[140,951,952,957],{"__ignoreMap":304},[308,953,954],{"class":310,"line":311},[308,955,956],{"class":314},"\u002F** One Skunk pool for all requests: built on first use, released when Nitro closes. *\u002F\n",[308,958,959,962,965,968,971,974,977,979],{"class":310,"line":318},[308,960,961],{"class":339},"private",[308,963,964],{"class":339}," val",[308,966,967],{"class":343}," database",[308,969,970],{"class":339}," =",[308,972,973],{"class":350}," ZShared",[308,975,976],{"class":354},".layer(",[308,978,358],{"class":350},[308,980,981],{"class":354},".layer)\n",[99,983,984,985,988,989,992,993,191],{},"Then ",[140,986,987],{},"database.provide(program)"," supplies the shared environment to a program, and ",[140,990,991],{},"database.get"," returns the ",[140,994,445],{},[99,996,997,998,1001,1002,1005,1006,1008,1009,191],{},"Load configuration inside the acquisition with ",[140,999,1000],{},"RuntimeConfig.load"," or ",[140,1003,1004],{},"ZRuntimeConfig.load",", not ",[140,1007,643],{},". There is no request at startup. See ",[247,1010,1011],{"href":32},"configuration",[193,1013,1015],{"id":1014},"one-copy-per-linked-project","One copy per linked project",[99,1017,668,1018,1020],{},[140,1019,166],{}," value is a normal Scala value. Every handler that the same sbt project links shares one copy, because Scala.js puts shared code in one internal module. Two Scala.js projects linked separately have two copies, and each opens its own pool.",[193,1022,1024],{"id":1023},"when-nitro-closes","When Nitro closes",[99,1026,1027,1028,1030,1031,184,1033,1035],{},"The h34s Nitro plugin listens to Nitro's ",[140,1029,661],{}," hook and releases every registered ",[140,1032,166],{},[140,1034,171],{}," value. One failing release does not stop the others. In Nitro 2.13:",[201,1037,1038,1059],{},[204,1039,1040,1041,1044,1045,1001,1048,1051,1052,184,1055,1058],{},"The ",[140,1042,1043],{},"node-server"," preset calls the hook on ",[140,1046,1047],{},"SIGTERM",[140,1049,1050],{},"SIGINT"," (graceful shutdown, 30 seconds by default; see ",[140,1053,1054],{},"NITRO_SHUTDOWN_TIMEOUT",[140,1056,1057],{},"NITRO_SHUTDOWN_DISABLED",").",[204,1060,1061,1064],{},[140,1062,1063],{},"nuxt dev"," calls it when it replaces the development worker, for example after relinking.",[99,1066,1067,1068,1070,1071,1073,1074,1076],{},"These facts come from Nitro's source. h34s tests the release path with a fake plugin record. In a production build of the demo, ",[140,1069,1047],{}," released the ",[140,1072,171],{}," pool registered by the first Notes request, and the server exited with status 0. A ",[140,1075,1063],{}," worker replacement has not been checked.",[99,1078,1079,1080,1082],{},"Without the h34s plugin (for example in unit tests), nothing is registered. Call ",[140,1081,661],{}," yourself in that case.",[193,1084,1086],{"id":1085},"what-is-tested","What is tested",[99,1088,1089,632,1092,1095,1096,1098,1099,1101,1102,1104,1105,219,1107,219,1110,219,1113,184,1116,191],{},[140,1090,1091],{},"SharedSuite",[140,1093,1094],{},"ZSharedSpec"," (ZIO): one acquisition for concurrent first calls, an interrupted waiter does not cancel the acquisition, failures are not cached, a ",[140,1097,661],{}," during the first acquisition never hands out a released value, ",[140,1100,661],{}," releases once and a later ",[140,1103,643],{}," acquires again, and the close hook releases every registered value. Request-scope tests in both runtimes cover finalizers on success, safe failure and defect, asynchronous finalizers, client disconnects, uninterruptible steps, and (Kyo) cleanup in work forked by ",[140,1106,519],{},[140,1108,1109],{},"race",[140,1111,1112],{},"gather",[140,1114,1115],{},"zip",[140,1117,1118],{},"foreach",[1120,1121,1122],"style",{},"html pre.shiki code .sCsY4, html code.shiki .sCsY4{--shiki-light:#6A737D;--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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);}",{"title":304,"searchDepth":318,"depth":318,"links":1124},[1125,1126,1127,1128,1129,1130],{"id":195,"depth":318,"text":196},{"id":485,"depth":318,"text":250},{"id":626,"depth":318,"text":627},{"id":1014,"depth":318,"text":1015},{"id":1023,"depth":318,"text":1024},{"id":1085,"depth":318,"text":1086},"Open request resources in the request scope and application resources once, with Shared or ZShared and the Nitro close hook.","md",null,{},{"title":35,"description":1131},"zV2xN5jwbKMhiV5BfRgeZbHRNK3zj23W-uzW5Yjc_Bc",[1138,1140],{"title":31,"path":32,"stem":33,"description":1139,"children":-1},"Decode Nuxt runtimeConfig into a Scala case class, override it with NUXT_* variables, and keep secrets out of logs.",{"title":39,"path":40,"stem":41,"description":1141,"children":-1},"Derive the native value, JSON, YAML and validation from one schema per model, with Kyo Schema or ZIO Schema.",1792533383165]