[{"data":1,"prerenderedAt":1049},["ShallowReactive",2],{"docs-nav:fr":3,"docs:\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle":189},[4],{"title":5,"path":6,"stem":7,"children":8,"page":52},"Fr","\u002Ffr","fr",[9],{"title":10,"path":11,"stem":12,"children":13},"Qu'est-ce que Fougere","\u002Ffr\u002Fdocs","fr\u002Fdocs\u002Findex",[14,15,19,23,27,31,53,78,123,148],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Démarrer","\u002Ffr\u002Fdocs\u002Fgetting-started","fr\u002Fdocs\u002F01.getting-started",{"title":20,"path":21,"stem":22},"Une app que vous avez déjà","\u002Ffr\u002Fdocs\u002Fexisting-app","fr\u002Fdocs\u002F02.existing-app",{"title":24,"path":25,"stem":26},"Apportez votre schéma","\u002Ffr\u002Fdocs\u002Fbring-your-schema","fr\u002Fdocs\u002F03.bring-your-schema",{"title":28,"path":29,"stem":30},"La CLI","\u002Ffr\u002Fdocs\u002Fcli","fr\u002Fdocs\u002F04.cli",{"title":32,"path":33,"stem":34,"children":35,"page":52},"Concepts","\u002Ffr\u002Fdocs\u002Fconcepts","fr\u002Fdocs\u002F2.concepts",[36,40,44,48],{"title":37,"path":38,"stem":39},"Philosophie","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fphilosophy","fr\u002Fdocs\u002F2.concepts\u002F1.philosophy",{"title":41,"path":42,"stem":43},"La Frond","\u002Ffr\u002Fdocs\u002Fconcepts\u002Ffrond","fr\u002Fdocs\u002F2.concepts\u002F2.frond",{"title":45,"path":46,"stem":47},"Le chemin le plus court","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fshortest-path","fr\u002Fdocs\u002F2.concepts\u002F3.shortest-path",{"title":49,"path":50,"stem":51},"Le socle","\u002Ffr\u002Fdocs\u002Fconcepts\u002Fthe-base","fr\u002Fdocs\u002F2.concepts\u002F4.the-base",false,{"title":54,"path":55,"stem":56,"children":57,"page":52},"Schéma","\u002Ffr\u002Fdocs\u002Fschema","fr\u002Fdocs\u002F3.schema",[58,62,66,70,74],{"title":59,"path":60,"stem":61},"Entités","\u002Ffr\u002Fdocs\u002Fschema\u002Fentities","fr\u002Fdocs\u002F3.schema\u002F1.entities",{"title":63,"path":64,"stem":65},"Vues","\u002Ffr\u002Fdocs\u002Fschema\u002Fviews","fr\u002Fdocs\u002F3.schema\u002F2.views",{"title":67,"path":68,"stem":69},"La carte d'identité","\u002Ffr\u002Fdocs\u002Fschema\u002Fcard","fr\u002Fdocs\u002F3.schema\u002F3.card",{"title":71,"path":72,"stem":73},"Standard Schema","\u002Ffr\u002Fdocs\u002Fschema\u002Fstandard-schema","fr\u002Fdocs\u002F3.schema\u002F4.standard-schema",{"title":75,"path":76,"stem":77},"Comment un schéma bouge","\u002Ffr\u002Fdocs\u002Fschema\u002Fevolution","fr\u002Fdocs\u002F3.schema\u002F5.evolution",{"title":79,"path":80,"stem":81,"children":82,"page":52},"Métier","\u002Ffr\u002Fdocs\u002Fbusiness","fr\u002Fdocs\u002F4.business",[83,87,91,95,99,103,107,111,115,119],{"title":84,"path":85,"stem":86},"Handlers","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fhandlers","fr\u002Fdocs\u002F4.business\u002F1.handlers",{"title":88,"path":89,"stem":90},"Les ports","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fports","fr\u002Fdocs\u002F4.business\u002F10.ports",{"title":92,"path":93,"stem":94},"Presenters","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fpresenters","fr\u002Fdocs\u002F4.business\u002F2.presenters",{"title":96,"path":97,"stem":98},"Collectors","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fcollectors","fr\u002Fdocs\u002F4.business\u002F3.collectors",{"title":100,"path":101,"stem":102},"Erreurs","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ferrors","fr\u002Fdocs\u002F4.business\u002F4.errors",{"title":104,"path":105,"stem":106},"Seeds","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fseeds","fr\u002Fdocs\u002F4.business\u002F5.seeds",{"title":108,"path":109,"stem":110},"Les faits","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ffacts","fr\u002Fdocs\u002F4.business\u002F6.facts",{"title":112,"path":113,"stem":114},"Le port Storage","\u002Ffr\u002Fdocs\u002Fbusiness\u002Fstorage","fr\u002Fdocs\u002F4.business\u002F7.storage",{"title":116,"path":117,"stem":118},"Des écritures qui tiennent ou tombent ensemble","\u002Ffr\u002Fdocs\u002Fbusiness\u002Ftogether","fr\u002Fdocs\u002F4.business\u002F8.together",{"title":120,"path":121,"stem":122},"Les repositories","\u002Ffr\u002Fdocs\u002Fbusiness\u002Frepositories","fr\u002Fdocs\u002F4.business\u002F9.repositories",{"title":124,"path":125,"stem":126,"children":127,"page":52},"Client","\u002Ffr\u002Fdocs\u002Fclient","fr\u002Fdocs\u002F5.client",[128,132,136,140,144],{"title":129,"path":130,"stem":131},"Queries & commands","\u002Ffr\u002Fdocs\u002Fclient\u002Fqueries-commands","fr\u002Fdocs\u002F5.client\u002F1.queries-commands",{"title":133,"path":134,"stem":135},"Formulaires","\u002Ffr\u002Fdocs\u002Fclient\u002Fforms","fr\u002Fdocs\u002F5.client\u002F2.forms",{"title":137,"path":138,"stem":139},"Session","\u002Ffr\u002Fdocs\u002Fclient\u002Fsession","fr\u002Fdocs\u002F5.client\u002F3.session",{"title":141,"path":142,"stem":143},"invoke","\u002Ffr\u002Fdocs\u002Fclient\u002Finvoke","fr\u002Fdocs\u002F5.client\u002F4.invoke",{"title":145,"path":146,"stem":147},"Back-office","\u002Ffr\u002Fdocs\u002Fclient\u002Fadmin","fr\u002Fdocs\u002F5.client\u002F5.admin",{"title":149,"path":150,"stem":151,"children":152,"page":52},"Infrastructure","\u002Ffr\u002Fdocs\u002Finfra","fr\u002Fdocs\u002F6.infra",[153,157,161,165,169,173,177,181,185],{"title":154,"path":155,"stem":156},"Le gradient","\u002Ffr\u002Fdocs\u002Finfra\u002Fgradient","fr\u002Fdocs\u002F6.infra\u002F1.gradient",{"title":158,"path":159,"stem":160},"Surfaces — REST & GraphQL","\u002Ffr\u002Fdocs\u002Finfra\u002Fsurfaces","fr\u002Fdocs\u002F6.infra\u002F2.surfaces",{"title":162,"path":163,"stem":164},"Déploiement","\u002Ffr\u002Fdocs\u002Finfra\u002Fdeployment","fr\u002Fdocs\u002F6.infra\u002F3.deployment",{"title":166,"path":167,"stem":168},"Hôtes","\u002Ffr\u002Fdocs\u002Finfra\u002Fhosts","fr\u002Fdocs\u002F6.infra\u002F4.hosts",{"title":170,"path":171,"stem":172},"Les sources","\u002Ffr\u002Fdocs\u002Finfra\u002Fsources","fr\u002Fdocs\u002F6.infra\u002F5.sources",{"title":174,"path":175,"stem":176},"Le cycle de vie","\u002Ffr\u002Fdocs\u002Finfra\u002Flifecycle","fr\u002Fdocs\u002F6.infra\u002F6.lifecycle",{"title":178,"path":179,"stem":180},"L'identité entre Fronds","\u002Ffr\u002Fdocs\u002Finfra\u002Fidentity","fr\u002Fdocs\u002F6.infra\u002F7.identity",{"title":182,"path":183,"stem":184},"Observabilité","\u002Ffr\u002Fdocs\u002Finfra\u002Fobservability","fr\u002Fdocs\u002F6.infra\u002F8.observability",{"title":186,"path":187,"stem":188},"Tests","\u002Ffr\u002Fdocs\u002Finfra\u002Ftesting","fr\u002Fdocs\u002F6.infra\u002F9.testing",{"id":190,"title":174,"body":191,"description":1043,"extension":1044,"meta":1045,"navigation":1046,"path":175,"seo":1047,"stem":176,"__hash__":1048},"docs_fr\u002Ffr\u002Fdocs\u002F6.infra\u002F6.lifecycle.md",{"type":192,"value":193,"toc":1035},"minimark",[194,198,202,211,226,231,241,248,340,361,364,408,419,521,524,548,563,567,577,727,733,746,750,753,775,786,790,793,834,840,843,864,867,871,878,988,999,1005,1009,1016,1031],[195,196,174],"h1",{"id":197},"le-cycle-de-vie",[199,200,201],"p",{},"Une valeur de configuration est de l'une ou l'autre sorte, et tout ce qui suit en découle :",[203,204,205],"blockquote",{},[199,206,207],{},[208,209,210],"strong",{},"Une valeur CONSULTÉE peut changer sous une app qui tourne. Une valeur CONSOMMÉE pour\nconstruire quelque chose ne le peut pas, sans reconstruire ce qu'elle a construit.",[199,212,213,217,218,221,222,225],{},[214,215,216],"code",{},"logLevel"," est consulté à chaque émission. ",[214,219,220],{},"db"," a ouvert une connexion, ",[214,223,224],{},"ports:"," a\nenregistré une classe, les entités ont construit des façades — ceux-là ont été consommés.",[227,228,230],"h2",{"id":229},"la-montée","La montée",[199,232,233,236,237,240],{},[214,234,235],{},"dispose()"," a toujours eu une forme : ordre inverse, uniquement ce qu'il a construit. La\nmontée n'en avait aucune — elle vivait à quatre endroits sous le nom ",[214,238,239],{},"afterBoot",", avec deux\nsens différents, et un hôte qui voulait son propre seeding devait s'approprier TOUT\nl'après-boot pour l'obtenir.",[199,242,243,244,247],{},"La paire est donc une seule valeur. Une ",[208,245,246],{},"extension"," énonce ce qu'elle fait à une app et ce\nqu'elle défait :",[249,250,255],"pre",{"className":251,"code":252,"language":253,"meta":254,"style":254},"language-ts shiki shiki-themes material-theme-lighter github-light github-dark","const app = await createApp({\n  root,\n  createContainer,\n  extensions: [observability()],\n});\n","ts","",[214,256,257,290,299,307,328],{"__ignoreMap":254},[258,259,262,266,270,274,278,282,286],"span",{"class":260,"line":261},"line",1,[258,263,265],{"class":264},"sbsja","const",[258,267,269],{"class":268},"s_hVV"," app",[258,271,273],{"class":272},"smGrS"," =",[258,275,277],{"class":276},"sVHd0"," await",[258,279,281],{"class":280},"sGLFI"," createApp",[258,283,285],{"class":284},"su5hD","(",[258,287,289],{"class":288},"sP7_E","{\n",[258,291,293,296],{"class":260,"line":292},2,[258,294,295],{"class":284},"  root",[258,297,298],{"class":288},",\n",[258,300,302,305],{"class":260,"line":301},3,[258,303,304],{"class":284},"  createContainer",[258,306,298],{"class":288},[258,308,310,314,317,320,323,326],{"class":260,"line":309},4,[258,311,313],{"class":312},"skxfh","  extensions",[258,315,316],{"class":288},":",[258,318,319],{"class":284}," [",[258,321,322],{"class":280},"observability",[258,324,325],{"class":284},"()]",[258,327,298],{"class":288},[258,329,331,334,337],{"class":260,"line":330},5,[258,332,333],{"class":288},"}",[258,335,336],{"class":284},")",[258,338,339],{"class":288},";\n",[199,341,342,345,346,349,350,353,354,356,357,360],{},[214,343,344],{},"up"," tourne avant que ",[214,347,348],{},"createApp"," ne rende la main, dans l'ordre déclaré ; ",[214,351,352],{},"down"," tourne\ndans ",[214,355,235],{},", en ordre inverse. C'est aussi le seul point du boot qui peut ",[208,358,359],{},"attendre",",\net c'est là qu'appartient un provider qui doit ouvrir quelque chose — un constructeur ne\npeut pas.",[199,362,363],{},"Deux membres sont ceux du framework, et ce sont des membres ordinaires :",[365,366,367,380],"table",{},[368,369,370],"thead",{},[371,372,373,377],"tr",{},[374,375,376],"th",{},"nom",[374,378,379],{},"ce qu'il fait",[381,382,383,394],"tbody",{},[371,384,385,391],{},[386,387,388],"td",{},[214,389,390],{},"migrate",[386,392,393],{},"met le schéma à jour — les tables avant les lignes. Le créneau est déclaré même quand rien ne migre, pour qu'un hôte qui le remplit REMPLACE ce membre au lieu d'atterrir après les seeds",[371,395,396,401],{},[386,397,398],{},[214,399,400],{},"seeds",[386,402,403,404,407],{},"plante ce que ",[214,405,406],{},"seeds\u002F"," déclare, dans l'ordre des dépendances",[199,409,410,413,414,418],{},[208,411,412],{},"Un nom déjà déclaré est remplacé, pas refusé."," C'est ainsi qu'un hôte dit ",[415,416,417],"em",{},"le seeding,\nmais le mien"," :",[249,420,422],{"className":251,"code":421,"language":253,"meta":254,"style":254},"\u002F\u002F ce que @fougere\u002Fnuxt génère : un bundler veut ses modules de seed en imports statiques\nextensions: [\n  migrating(storage.migrate),\n  { name: 'seeds', up: (app) => runSeeds(app, [\u002F* importés au-dessus *\u002F]) },\n]\n",[214,423,424,430,441,457,516],{"__ignoreMap":254},[258,425,426],{"class":260,"line":261},[258,427,429],{"class":428},"sutJx","\u002F\u002F ce que @fougere\u002Fnuxt génère : un bundler veut ses modules de seed en imports statiques\n",[258,431,432,436,438],{"class":260,"line":292},[258,433,435],{"class":434},"sbgvK","extensions",[258,437,316],{"class":288},[258,439,440],{"class":284}," [\n",[258,442,443,446,449,452,455],{"class":260,"line":301},[258,444,445],{"class":280},"  migrating",[258,447,448],{"class":284},"(storage",[258,450,451],{"class":288},".",[258,453,454],{"class":284},"migrate)",[258,456,298],{"class":288},[258,458,459,462,465,467,471,474,477,480,483,485,488,492,494,497,500,503,505,507,510,513],{"class":260,"line":309},[258,460,461],{"class":288},"  {",[258,463,464],{"class":312}," name",[258,466,316],{"class":288},[258,468,470],{"class":469},"sjJ54"," '",[258,472,400],{"class":473},"s_sjI",[258,475,476],{"class":469},"'",[258,478,479],{"class":288},",",[258,481,482],{"class":280}," up",[258,484,316],{"class":288},[258,486,487],{"class":288}," (",[258,489,491],{"class":490},"s99_P","app",[258,493,336],{"class":288},[258,495,496],{"class":264}," =>",[258,498,499],{"class":280}," runSeeds",[258,501,502],{"class":284},"(app",[258,504,479],{"class":288},[258,506,319],{"class":284},[258,508,509],{"class":428},"\u002F* importés au-dessus *\u002F",[258,511,512],{"class":284},"]) ",[258,514,515],{"class":288},"},\n",[258,517,518],{"class":260,"line":330},[258,519,520],{"class":284},"]\n",[199,522,523],{},"La montée et la descente refusent de façons opposées, exprès :",[525,526,527,536],"ul",{},[528,529,530,535],"li",{},[208,531,532,534],{},[214,533,344],{}," s'arrête au premier refus."," Un seed qui suppose qu'une migration a tourné ne doit\npas tourner quand elle n'a pas tourné, et une app à moitié démarrée ne doit pas être rendue.",[528,537,538,543,544,547],{},[208,539,540,542],{},[214,541,352],{}," relâche chaque membre même si l'un jette",", et les refus partent ensemble dans un\n",[214,545,546],{},"AggregateError"," — un relâchement qui abandonne au premier échec fuit tout ce qui suit.",[199,549,550,551,554,555,558,559,562],{},"Une extension n'est pas un Frond et ne peut pas en devenir un : un Frond a des entités et\npeut partir derrière ",[214,552,553],{},"remotes:",", alors qu'une extension appartient au ",[208,556,557],{},"processus"," qui les\nhéberge. ",[214,560,561],{},"observability()"," est le cas qui le prouve — déplacée, elle rapporterait\nl'observateur au lieu de l'observé.",[227,564,566],{"id":565},"relire-la-configuration","Relire la configuration",[199,568,569,572,573,576],{},[214,570,571],{},"applyConfig"," est le seul endroit qui répond à ",[415,574,575],{},"ce qu'une relecture change dans une app qui\ntourne",". Il applique ce qui est consulté et signale le reste plutôt que de l'ignorer :",[249,578,580],{"className":251,"code":579,"language":253,"meta":254,"style":254},"\u002F\u002F l'hôte possède le process, donc l'hôte possède le signal — Fougere n'en attrape aucun\nprocess.on('SIGHUP', async () => {\n  const next = await loadConfig(root, { fresh: true });\n  const { applied, pending } = applyConfig(next, inForce);\n  inForce = next;\n  \u002F\u002F applied : ['logLevel: warn → debug']\n  \u002F\u002F pending : ['db']  — changé dans le fichier, et il a ouvert une connexion\n});\n",[214,581,582,587,619,660,695,706,712,718],{"__ignoreMap":254},[258,583,584],{"class":260,"line":261},[258,585,586],{"class":428},"\u002F\u002F l'hôte possède le process, donc l'hôte possède le signal — Fougere n'en attrape aucun\n",[258,588,589,592,594,597,599,601,604,606,608,611,614,616],{"class":260,"line":292},[258,590,591],{"class":284},"process",[258,593,451],{"class":288},[258,595,596],{"class":280},"on",[258,598,285],{"class":284},[258,600,476],{"class":469},[258,602,603],{"class":473},"SIGHUP",[258,605,476],{"class":469},[258,607,479],{"class":288},[258,609,610],{"class":264}," async",[258,612,613],{"class":288}," ()",[258,615,496],{"class":264},[258,617,618],{"class":288}," {\n",[258,620,621,624,627,629,631,634,636,639,641,644,647,649,653,656,658],{"class":260,"line":301},[258,622,623],{"class":264},"  const",[258,625,626],{"class":268}," next",[258,628,273],{"class":272},[258,630,277],{"class":276},[258,632,633],{"class":280}," loadConfig",[258,635,285],{"class":312},[258,637,638],{"class":284},"root",[258,640,479],{"class":288},[258,642,643],{"class":288}," {",[258,645,646],{"class":312}," fresh",[258,648,316],{"class":288},[258,650,652],{"class":651},"syTEX"," true",[258,654,655],{"class":288}," }",[258,657,336],{"class":312},[258,659,339],{"class":288},[258,661,662,664,666,669,671,674,676,678,681,683,686,688,691,693],{"class":260,"line":309},[258,663,623],{"class":264},[258,665,643],{"class":288},[258,667,668],{"class":268}," applied",[258,670,479],{"class":288},[258,672,673],{"class":268}," pending",[258,675,655],{"class":288},[258,677,273],{"class":272},[258,679,680],{"class":280}," applyConfig",[258,682,285],{"class":312},[258,684,685],{"class":284},"next",[258,687,479],{"class":288},[258,689,690],{"class":284}," inForce",[258,692,336],{"class":312},[258,694,339],{"class":288},[258,696,697,700,702,704],{"class":260,"line":330},[258,698,699],{"class":284},"  inForce",[258,701,273],{"class":272},[258,703,626],{"class":284},[258,705,339],{"class":288},[258,707,709],{"class":260,"line":708},6,[258,710,711],{"class":428},"  \u002F\u002F applied : ['logLevel: warn → debug']\n",[258,713,715],{"class":260,"line":714},7,[258,716,717],{"class":428},"  \u002F\u002F pending : ['db']  — changé dans le fichier, et il a ouvert une connexion\n",[258,719,721,723,725],{"class":260,"line":720},8,[258,722,333],{"class":288},[258,724,336],{"class":284},[258,726,339],{"class":288},[199,728,729,732],{},[214,730,731],{},"{ fresh: true }"," n'est pas décoratif : un module est mis en cache par son specifier, donc\nune deuxième lecture d'un fichier modifié rend la première.",[199,734,735,736,742,743,745],{},"La liste des clés consultées n'est déclarée nulle part — ",[208,737,738,739,741],{},"une clé est consultée quand\n",[214,740,571],{}," en fait quelque chose",", la seule définition qui ne peut pas devenir périmée.\nAujourd'hui c'est ",[214,744,216],{},", et un logger construit avant le changement l'applique,\nenfants compris : le niveau est tenu une fois pour le process au lieu d'être recopié dans\nchaque instance.",[227,747,749],{"id":748},"tourner-lanneau","Tourner l'anneau",[199,751,752],{},"Pour tout le reste, la valeur ne peut pas bouger sous ce qu'elle a construit — donc la\nchose est reconstruite. Une app est instanciée, la précédente laissée partir :",[249,754,756],{"className":251,"code":755,"language":253,"meta":254,"style":254},"await reloadFougere();     \u002F\u002F instancier, drainer l'ancienne, la relâcher\n",[214,757,758],{"__ignoreMap":254},[258,759,760,763,766,769,772],{"class":260,"line":261},[258,761,762],{"class":276},"await",[258,764,765],{"class":280}," reloadFougere",[258,767,768],{"class":284},"()",[258,770,771],{"class":288},";",[258,773,774],{"class":428},"     \u002F\u002F instancier, drainer l'ancienne, la relâcher\n",[199,776,777,778,781,782,785],{},"Ça marche parce que chaque porte atteint l'app par ",[214,779,780],{},"useFougereApp()"," ",[208,783,784],{},"à l'intérieur de la\nrequête qu'elle sert",", et qu'aucune ne la garde d'une requête à l'autre. La nouvelle est\ndebout avant que l'ancienne soit relâchée, donc un boot raté laisse la précédente servir.",[227,787,789],{"id":788},"drainer","Drainer",[199,791,792],{},"Relâcher une app ferme sa connexion de stockage et tous les scopes de Frond — c'est-à-dire\nce sur quoi les appels en cours reposent. Donc on les attend :",[249,794,796],{"className":251,"code":795,"language":253,"meta":254,"style":254},"await app.drain();      \u002F\u002F fermer la porte, attendre les appels en cours\nawait app.dispose();    \u002F\u002F puis fermer les scopes et la connexion\n",[214,797,798,816],{"__ignoreMap":254},[258,799,800,802,804,806,809,811,813],{"class":260,"line":261},[258,801,762],{"class":276},[258,803,269],{"class":284},[258,805,451],{"class":288},[258,807,808],{"class":280},"drain",[258,810,768],{"class":284},[258,812,771],{"class":288},[258,814,815],{"class":428},"      \u002F\u002F fermer la porte, attendre les appels en cours\n",[258,817,818,820,822,824,827,829,831],{"class":260,"line":292},[258,819,762],{"class":276},[258,821,269],{"class":284},[258,823,451],{"class":288},[258,825,826],{"class":280},"dispose",[258,828,768],{"class":284},[258,830,771],{"class":288},[258,832,833],{"class":428},"    \u002F\u002F puis fermer les scopes et la connexion\n",[199,835,836,839],{},[214,837,838],{},"app.inFlight()"," en est le compte, pris au seul chemin que les trois portes et le fil\npartagent, donc un seul nombre les couvre. Un appel imbriqué compte deux fois — l'app n'est\npas au repos tant qu'une op interne tourne.",[199,841,842],{},"Deux refus, tous deux délibérés :",[525,844,845,854],{},[528,846,847,853],{},[208,848,849,852],{},[214,850,851],{},"drain(timeoutMs)"," refuse à son échéance",", en nommant combien d'appels restent, plutôt\nque de répondre comme si ça avait marché. Son appelant s'apprête à fermer une connexion\nsous ce qui reste : la décision lui revient.",[528,855,856,859,860,863],{},[208,857,858],{},"Un appel qui arrive après la fermeture de la porte est refusé"," en\n",[214,861,862],{},"SERVICE_UNAVAILABLE",". La poignée pointe déjà sur la nouvelle app, donc cet appelant avait\ngardé une référence à travers le tour.",[199,865,866],{},"Attendre et relâcher restent deux gestes : un script relâche tout de suite, un hôte qui\ntourne l'anneau draine d'abord.",[227,868,870],{"id":869},"sarrêter","S'arrêter",[199,872,873,874,877],{},"Les deux mêmes gestes répondent à ",[214,875,876],{},"SIGTERM",", et rien d'autre n'est nécessaire :",[249,879,881],{"className":251,"code":880,"language":253,"meta":254,"style":254},"process.on('SIGTERM', async () => {\n  const app = await useFougereApp();\n  await app.drain(10_000);\n  await app.dispose();\n  process.exit(0);\n});\n",[214,882,883,909,926,947,961,980],{"__ignoreMap":254},[258,884,885,887,889,891,893,895,897,899,901,903,905,907],{"class":260,"line":261},[258,886,591],{"class":284},[258,888,451],{"class":288},[258,890,596],{"class":280},[258,892,285],{"class":284},[258,894,476],{"class":469},[258,896,876],{"class":473},[258,898,476],{"class":469},[258,900,479],{"class":288},[258,902,610],{"class":264},[258,904,613],{"class":288},[258,906,496],{"class":264},[258,908,618],{"class":288},[258,910,911,913,915,917,919,922,924],{"class":260,"line":292},[258,912,623],{"class":264},[258,914,269],{"class":268},[258,916,273],{"class":272},[258,918,277],{"class":276},[258,920,921],{"class":280}," useFougereApp",[258,923,768],{"class":312},[258,925,339],{"class":288},[258,927,928,931,933,935,937,939,943,945],{"class":260,"line":301},[258,929,930],{"class":276},"  await",[258,932,269],{"class":284},[258,934,451],{"class":288},[258,936,808],{"class":280},[258,938,285],{"class":312},[258,940,942],{"class":941},"srdBf","10_000",[258,944,336],{"class":312},[258,946,339],{"class":288},[258,948,949,951,953,955,957,959],{"class":260,"line":309},[258,950,930],{"class":276},[258,952,269],{"class":284},[258,954,451],{"class":288},[258,956,826],{"class":280},[258,958,768],{"class":312},[258,960,339],{"class":288},[258,962,963,966,968,971,973,976,978],{"class":260,"line":330},[258,964,965],{"class":284},"  process",[258,967,451],{"class":288},[258,969,970],{"class":280},"exit",[258,972,285],{"class":312},[258,974,975],{"class":941},"0",[258,977,336],{"class":312},[258,979,339],{"class":288},[258,981,982,984,986],{"class":260,"line":708},[258,983,333],{"class":288},[258,985,336],{"class":284},[258,987,339],{"class":288},[199,989,990,992,993,995,996,998],{},[214,991,235],{}," relâche en ordre inverse de la construction, à trois niveaux : le ",[214,994,352],{}," de\nchaque extension (construite en dernier), puis le conteneur — chaque scope jetant les scopes\nqu'il a ouverts, du plus profond d'abord, puis ce qu'il a construit lui-même — puis la\nconnexion de stockage qu'on lui avait remise, ouverte avant que tout cela existe. Un provider qui tient quelque chose le dit en\nayant une méthode ",[214,997,235],{}," — rien ne le déclare, le conteneur cherche la méthode.",[199,1000,1001,1002,1004],{},"Les échecs voyagent ensemble dans un ",[214,1003,546],{}," plutôt que le premier ne fasse taire\nles autres : tout est prévenu de se fermer.",[227,1006,1008],{"id":1007},"ce-qui-nest-pas-ici","Ce qui n'est pas ici",[199,1010,1011,1012,1015],{},"Fougere n'attrape aucun signal. Un process appartient à son hôte, et le logger qu'il livre\ntourne sur Cloudflare Workers, où ",[214,1013,1014],{},"process.on"," n'existe pas.",[199,1017,1018,1019,1023,1024,1027,1028,1030],{},"Retour aux ",[1020,1021,1022],"a",{"href":171},"sources",", ou aux ",[1020,1025,1026],{"href":89},"ports","\nqu'une ligne ",[214,1029,224],{}," départage.",[1032,1033,1034],"style",{},"html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--shiki-dark-font-style:inherit}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--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);}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":254,"searchDepth":292,"depth":292,"links":1036},[1037,1038,1039,1040,1041,1042],{"id":229,"depth":292,"text":230},{"id":565,"depth":292,"text":566},{"id":748,"depth":292,"text":749},{"id":788,"depth":292,"text":789},{"id":869,"depth":292,"text":870},{"id":1007,"depth":292,"text":1008},"Ce qu'une app qui tourne peut changer sans être reconstruite, ce qui demande un tour d'anneau, et comment un appel en cours n'est pas coupé en deux.","md",{},true,{"title":174,"description":1043},"914LrZRqntFXYu8cM3vuzuQ6I9XuibOuCfx4TtTguH8",1788598419886]