[{"data":1,"prerenderedAt":426},["ShallowReactive",2],{"navigation":3,"\u002Fapi\u002Ffollow-ups":155,"\u002Fapi\u002Ffollow-ups-surround":421},[4,36,57,113,144],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":35},"Getting Started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,25,30],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Install","\u002Fgetting-started\u002Finstall","1.getting-started\u002F2.install","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F3.quickstart","i-lucide-zap",{"title":26,"path":27,"stem":28,"icon":29},"Testing","\u002Fgetting-started\u002Ftesting","1.getting-started\u002F4.testing","i-lucide-flask-conical",{"title":31,"path":32,"stem":33,"icon":34},"CLI","\u002Fgetting-started\u002Fcli","1.getting-started\u002F5.cli","i-lucide-terminal",false,{"title":37,"icon":38,"path":39,"stem":40,"children":41,"page":35},"Concepts","i-lucide-boxes","\u002Fconcepts","2.concepts",[42,47,52],{"title":43,"path":44,"stem":45,"icon":46},"SQL-first contract","\u002Fconcepts\u002Fsql-first-contract","2.concepts\u002F1.sql-first-contract","i-lucide-database",{"title":48,"path":49,"stem":50,"icon":51},"Jobs and status","\u002Fconcepts\u002Fjobs-and-status","2.concepts\u002F2.jobs-and-status","i-lucide-list-checks",{"title":53,"path":54,"stem":55,"icon":56},"Fencing and settles","\u002Fconcepts\u002Ffencing-and-settles","2.concepts\u002F3.fencing-and-settles","i-lucide-shield",{"title":58,"icon":59,"path":60,"stem":61,"children":62,"page":35},"API","i-lucide-code-2","\u002Fapi","3.api",[63,68,73,78,83,88,93,98,103,108],{"title":64,"path":65,"stem":66,"icon":67},"Enqueue","\u002Fapi\u002Fenqueue","3.api\u002F1.enqueue","i-lucide-plus-circle",{"title":69,"path":70,"stem":71,"icon":72},"Trusted Effects","\u002Fapi\u002Ftrusted-effects","3.api\u002F10.trusted-effects","i-lucide-lock-keyhole",{"title":74,"path":75,"stem":76,"icon":77},"Claim and heartbeat","\u002Fapi\u002Fclaim-and-heartbeat","3.api\u002F2.claim-and-heartbeat","i-lucide-hand",{"title":79,"path":80,"stem":81,"icon":82},"Worker and handlers","\u002Fapi\u002Fworker-and-handlers","3.api\u002F3.worker-and-handlers","i-lucide-cpu",{"title":84,"path":85,"stem":86,"icon":87},"HTTP facade","\u002Fapi\u002Fhttp-facade","3.api\u002F4.http-facade","i-lucide-globe",{"title":89,"path":90,"stem":91,"icon":92},"Authorization","\u002Fapi\u002Fauthorization","3.api\u002F5.authorization","i-lucide-key-round",{"title":94,"path":95,"stem":96,"icon":97},"Follow-ups","\u002Fapi\u002Ffollow-ups","3.api\u002F6.follow-ups","i-lucide-git-branch",{"title":99,"path":100,"stem":101,"icon":102},"Workflows and schedules","\u002Fapi\u002Fworkflows-and-schedules","3.api\u002F7.workflows-and-schedules","i-lucide-workflow",{"title":104,"path":105,"stem":106,"icon":107},"Durable admission","\u002Fapi\u002Fdurable-admission","3.api\u002F8.durable-admission","i-lucide-ticket",{"title":109,"path":110,"stem":111,"icon":112},"Workflow Continuations","\u002Fapi\u002Fworkflow-continuations","3.api\u002F9.workflow-continuations","i-lucide-git-fork",{"title":114,"icon":115,"path":116,"stem":117,"children":118,"page":35},"Operations","i-lucide-activity","\u002Foperations","4.operations",[119,124,129,134,139],{"title":120,"path":121,"stem":122,"icon":123},"Standalone Scheduler","\u002Foperations\u002Fstandalone-scheduler","4.operations\u002F0.standalone-scheduler","i-lucide-calendar-clock",{"title":125,"path":126,"stem":127,"icon":128},"Housekeeping","\u002Foperations\u002Fhousekeeping","4.operations\u002F1.housekeeping","i-lucide-timer",{"title":130,"path":131,"stem":132,"icon":133},"Redrive and dead letters","\u002Foperations\u002Fredrive-and-dlq","4.operations\u002F2.redrive-and-dlq","i-lucide-rotate-ccw",{"title":135,"path":136,"stem":137,"icon":138},"Flow control","\u002Foperations\u002Fflow-control","4.operations\u002F3.flow-control","i-lucide-gauge",{"title":140,"path":141,"stem":142,"icon":143},"Queue Boundaries","\u002Foperations\u002Fqueue-boundaries","4.operations\u002F4.queue-boundaries","i-lucide-panels-top-left",{"title":145,"icon":146,"path":147,"stem":148,"children":149,"page":35},"Reference","i-lucide-book-marked","\u002Freference","5.reference",[150],{"title":151,"path":152,"stem":153,"icon":154},"Configuration","\u002Freference\u002Fconfiguration","5.reference\u002F1.configuration","i-lucide-settings",{"id":156,"title":94,"body":157,"description":414,"extension":415,"links":416,"meta":417,"navigation":418,"path":95,"seo":419,"stem":96,"__hash__":420},"docs\u002F3.api\u002F6.follow-ups.md",{"type":158,"value":159,"toc":411},"minimark",[160,164,371,376,400,407],[161,162,163],"p",{},"A handler declares its finite child graph in the registry and returns typed children with its successful result. The parent settlement and every child insert commit together; the worker never receives a generic producer client.",[165,166,171],"pre",{"className":167,"code":168,"language":169,"meta":170,"style":170},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","from taskq import Complete, Followup, FollowupTarget, Task, TaskRegistry\n\nchild = Task(\n    name=\"listing.enrich\",\n    queue=\"enrichment\",\n    input_model=EnrichInput,\n    output_model=EnrichOutput,\n    handler=enrich,\n)\n\nasync def discover(payload: DiscoverInput) -> Complete:\n    return Complete(\n        result={\"accepted\": True},\n        followups=(\n            Followup(\n                step=\"enrich\",\n                job_type=child.name,\n                queue=child.queue,\n                payload={\"listing_id\": payload.listing_id},\n            ),\n        ),\n    )\n\nparent = Task(\n    name=\"listing.discover\",\n    queue=\"discovery\",\n    input_model=DiscoverInput,\n    output_model=DiscoverOutput,\n    followup_targets=(FollowupTarget(queue=child.queue, job_type=child.name),),\n    handler=discover,\n)\n\nregistry = TaskRegistry((parent, child))\n","python","",[172,173,174,182,189,195,201,207,213,219,225,231,236,242,248,254,260,266,272,278,284,290,296,302,308,313,319,325,331,337,343,349,355,360,365],"code",{"__ignoreMap":170},[175,176,179],"span",{"class":177,"line":178},"line",1,[175,180,181],{},"from taskq import Complete, Followup, FollowupTarget, Task, TaskRegistry\n",[175,183,185],{"class":177,"line":184},2,[175,186,188],{"emptyLinePlaceholder":187},true,"\n",[175,190,192],{"class":177,"line":191},3,[175,193,194],{},"child = Task(\n",[175,196,198],{"class":177,"line":197},4,[175,199,200],{},"    name=\"listing.enrich\",\n",[175,202,204],{"class":177,"line":203},5,[175,205,206],{},"    queue=\"enrichment\",\n",[175,208,210],{"class":177,"line":209},6,[175,211,212],{},"    input_model=EnrichInput,\n",[175,214,216],{"class":177,"line":215},7,[175,217,218],{},"    output_model=EnrichOutput,\n",[175,220,222],{"class":177,"line":221},8,[175,223,224],{},"    handler=enrich,\n",[175,226,228],{"class":177,"line":227},9,[175,229,230],{},")\n",[175,232,234],{"class":177,"line":233},10,[175,235,188],{"emptyLinePlaceholder":187},[175,237,239],{"class":177,"line":238},11,[175,240,241],{},"async def discover(payload: DiscoverInput) -> Complete:\n",[175,243,245],{"class":177,"line":244},12,[175,246,247],{},"    return Complete(\n",[175,249,251],{"class":177,"line":250},13,[175,252,253],{},"        result={\"accepted\": True},\n",[175,255,257],{"class":177,"line":256},14,[175,258,259],{},"        followups=(\n",[175,261,263],{"class":177,"line":262},15,[175,264,265],{},"            Followup(\n",[175,267,269],{"class":177,"line":268},16,[175,270,271],{},"                step=\"enrich\",\n",[175,273,275],{"class":177,"line":274},17,[175,276,277],{},"                job_type=child.name,\n",[175,279,281],{"class":177,"line":280},18,[175,282,283],{},"                queue=child.queue,\n",[175,285,287],{"class":177,"line":286},19,[175,288,289],{},"                payload={\"listing_id\": payload.listing_id},\n",[175,291,293],{"class":177,"line":292},20,[175,294,295],{},"            ),\n",[175,297,299],{"class":177,"line":298},21,[175,300,301],{},"        ),\n",[175,303,305],{"class":177,"line":304},22,[175,306,307],{},"    )\n",[175,309,311],{"class":177,"line":310},23,[175,312,188],{"emptyLinePlaceholder":187},[175,314,316],{"class":177,"line":315},24,[175,317,318],{},"parent = Task(\n",[175,320,322],{"class":177,"line":321},25,[175,323,324],{},"    name=\"listing.discover\",\n",[175,326,328],{"class":177,"line":327},26,[175,329,330],{},"    queue=\"discovery\",\n",[175,332,334],{"class":177,"line":333},27,[175,335,336],{},"    input_model=DiscoverInput,\n",[175,338,340],{"class":177,"line":339},28,[175,341,342],{},"    output_model=DiscoverOutput,\n",[175,344,346],{"class":177,"line":345},29,[175,347,348],{},"    followup_targets=(FollowupTarget(queue=child.queue, job_type=child.name),),\n",[175,350,352],{"class":177,"line":351},30,[175,353,354],{},"    handler=discover,\n",[175,356,358],{"class":177,"line":357},31,[175,359,230],{},[175,361,363],{"class":177,"line":362},32,[175,364,188],{"emptyLinePlaceholder":187},[175,366,368],{"class":177,"line":367},33,[175,369,370],{},"registry = TaskRegistry((parent, child))\n",[372,373,375],"h2",{"id":374},"rules","Rules",[377,378,379,391,394,397],"ul",{},[380,381,382,383,386,387,390],"li",{},"Declare every child ",[172,384,385],{},"(queue, job_type)"," on ",[172,388,389],{},"followup_targets"," before the worker starts.",[380,392,393],{},"Worker construction rejects missing or queue-mismatched targets.",[380,395,396],{},"HTTP completion authorizes the parent queue, then every distinct child queue, before SQL.",[380,398,399],{},"Direct SQL retains the trusted runner-role boundary.",[161,401,402,403,406],{},"Shipped in migrations ",[172,404,405],{},"0008_followups.sql"," (ADR-024 \u002F ADR-025).",[408,409,410],"style",{},"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":170,"searchDepth":178,"depth":184,"links":412},[413],{"id":374,"depth":184,"text":375},"Atomic child jobs declared on the parent Task and returned with Complete.","md",null,{},{"icon":97},{"title":94,"description":414},"lzekxZQEfyjQ73ux67uXRyfbbUz4Acp4sYlGjG3MH8s",[422,424],{"title":89,"path":90,"stem":91,"description":423,"icon":92,"children":-1},"QueueAuthorizer, built-ins, and the OutLabs adapter.",{"title":99,"path":100,"stem":101,"description":425,"icon":102,"children":-1},"Sealed workflows with dependency edges, plus database-time recurring schedules.",1787515776866]