[{"data":1,"prerenderedAt":1701},["ShallowReactive",2],{"navigation":3,"\u002Foperations\u002Fstandalone-scheduler":155,"\u002Foperations\u002Fstandalone-scheduler-surround":1696},[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":120,"body":157,"description":1689,"extension":1690,"links":1691,"meta":1692,"navigation":1693,"path":121,"seo":1694,"stem":122,"__hash__":1695},"docs\u002F4.operations\u002F0.standalone-scheduler.md",{"type":158,"value":159,"toc":1673},"minimark",[160,169,180,247,253,258,261,314,420,447,551,558,563,566,634,637,641,644,684,687,722,732,735,739,742,894,1002,1018,1049,1053,1060,1142,1152,1192,1198,1202,1205,1208,1296,1299,1321,1343,1347,1350,1412,1418,1429,1432,1436,1486,1490,1511,1514,1539,1542,1549,1553,1574,1577,1581,1608,1626,1637,1641,1669],[161,162,163,164,168],"p",{},"TaskQ ",[165,166,167],"code",{},"0.1.0a36"," separates recurring-work ownership from FastAPI. The\nstandalone scheduler is a clock: it evaluates recurrence and durably enqueues\nordinary TaskQ jobs. It never imports an application registry or executes task\nhandlers.",[170,171,178],"pre",{"className":172,"code":174,"filename":175,"language":176,"meta":177},[173],"language-text","one scheduler clock -> queued jobs -> one or more application workers -> handlers\n","production topology","text","",[165,179,174],{"__ignoreMap":177},[181,182,183,199],"table",{},[184,185,186],"thead",{},[187,188,189,193,196],"tr",{},[190,191,192],"th",{},"Process",[190,194,195],{},"Needs",[190,197,198],{},"Does not need",[200,201,202,214,225,236],"tbody",{},[187,203,204,208,211],{},[205,206,207],"td",{},"Scheduler",[205,209,210],{},"Restricted housekeeper DSN, static target expectations",[205,212,213],{},"Application imports or handler secrets",[187,215,216,219,222],{},[205,217,218],{},"Manifest operator",[205,220,221],{},"Restricted operator DSN, reviewed YAML",[205,223,224],{},"Runner or migration-owner rights",[187,226,227,230,233],{},[205,228,229],{},"Worker",[205,231,232],{},"Runner DSN or HTTP credentials, task registry, handler dependencies",[205,234,235],{},"Scheduler or operator rights",[187,237,238,241,244],{},[205,239,240],{},"API \u002F facade",[205,242,243],{},"Producer and optional facade credentials",[205,245,246],{},"A recurring scheduler loop",[248,249,250],"note",{},[161,251,252],{},"Run one logical scheduler per database\u002Fenvironment. Worker placement is an\nindependent application decision: a supervised local worker, a consolidated\nmulti-queue process, or a cloud worker are all valid when their dependencies,\nsecrets, availability, and failure boundaries support that choice.",[254,255,257],"h2",{"id":256},"_1-install-and-bind-the-target","1. Install and bind the target",[161,259,260],{},"Use a dedicated owner\u002Fmigration credential for this section only. Put only its\nenvironment-variable name in a secret-free CLI context:",[170,262,267],{"className":263,"code":264,"filename":265,"language":266,"meta":177,"style":177},"language-toml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","version = 1\n\n[contexts.staging]\ntransport = \"sql\"\ndsn_env = \"TASKQ_STAGING_DSN\"\nexpected_environment = \"staging\"\nactor = \"operator:release-agent\"\n","~\u002F.config\u002Ftaskq\u002Fconfig.toml","toml",[165,268,269,277,284,290,296,302,308],{"__ignoreMap":177},[270,271,274],"span",{"class":272,"line":273},"line",1,[270,275,276],{},"version = 1\n",[270,278,280],{"class":272,"line":279},2,[270,281,283],{"emptyLinePlaceholder":282},true,"\n",[270,285,287],{"class":272,"line":286},3,[270,288,289],{},"[contexts.staging]\n",[270,291,293],{"class":272,"line":292},4,[270,294,295],{},"transport = \"sql\"\n",[270,297,299],{"class":272,"line":298},5,[270,300,301],{},"dsn_env = \"TASKQ_STAGING_DSN\"\n",[270,303,305],{"class":272,"line":304},6,[270,306,307],{},"expected_environment = \"staging\"\n",[270,309,311],{"class":272,"line":310},7,[270,312,313],{},"actor = \"operator:release-agent\"\n",[170,315,320],{"className":316,"code":317,"filename":318,"language":319,"meta":177,"style":177},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export TASKQ_STAGING_DSN='postgresql:\u002F\u002Ftaskq_migration:...@db-host\u002Fapp'\n\ntaskq --context staging db plan -o json\ntaskq --context staging --yes db migrate --plan-digest \"$PLAN_DIGEST\"\ntaskq --context staging target show -o json\n","Terminal","bash",[165,321,322,346,350,374,402],{"__ignoreMap":177},[270,323,324,328,332,336,339,343],{"class":272,"line":273},[270,325,327],{"class":326},"spNyl","export",[270,329,331],{"class":330},"sTEyZ"," TASKQ_STAGING_DSN",[270,333,335],{"class":334},"sMK4o","=",[270,337,338],{"class":334},"'",[270,340,342],{"class":341},"sfazB","postgresql:\u002F\u002Ftaskq_migration:...@db-host\u002Fapp",[270,344,345],{"class":334},"'\n",[270,347,348],{"class":272,"line":279},[270,349,283],{"emptyLinePlaceholder":282},[270,351,352,356,359,362,365,368,371],{"class":272,"line":286},[270,353,355],{"class":354},"sBMFI","taskq",[270,357,358],{"class":341}," --context",[270,360,361],{"class":341}," staging",[270,363,364],{"class":341}," db",[270,366,367],{"class":341}," plan",[270,369,370],{"class":341}," -o",[270,372,373],{"class":341}," json\n",[270,375,376,378,380,382,385,387,390,393,396,399],{"class":272,"line":292},[270,377,355],{"class":354},[270,379,358],{"class":341},[270,381,361],{"class":341},[270,383,384],{"class":341}," --yes",[270,386,364],{"class":341},[270,388,389],{"class":341}," migrate",[270,391,392],{"class":341}," --plan-digest",[270,394,395],{"class":334}," \"",[270,397,398],{"class":330},"$PLAN_DIGEST",[270,400,401],{"class":334},"\"\n",[270,403,404,406,408,410,413,416,418],{"class":272,"line":298},[270,405,355],{"class":354},[270,407,358],{"class":341},[270,409,361],{"class":341},[270,411,412],{"class":341}," target",[270,414,415],{"class":341}," show",[270,417,370],{"class":341},[270,419,373],{"class":341},[161,421,422,423,426,427,430,431,434,435,438,439,442,443,446],{},"On a fresh scheduler installation, migration ",[165,424,425],{},"0019"," commits and ",[165,428,429],{},"0020"," refuses\nto activate while the target is ",[165,432,433],{},"unbound",". The first migrate exits ",[165,436,437],{},"2"," with\nstable code ",[165,440,441],{},"CLI_TARGET_BINDING_REQUIRED","; it is not a retryable outage.\n",[165,444,445],{},"target show"," intentionally permits this unbound bootstrap state even though\nthe context declares the future environment. Record the returned installation\nUUID outside the target database configuration, then bind the reviewed\nenvironment:",[170,448,450],{"className":316,"code":449,"filename":318,"language":319,"meta":177,"style":177},"taskq --context staging --yes target bind staging \\\n  --expected-installation-id '\u003Cinstallation-uuid>' \\\n  --expected-binding-version 0\n\ntaskq --context staging db plan -o json\ntaskq --context staging --yes db migrate --plan-digest \"$PLAN_DIGEST\"\ntaskq --context staging db verify\n",[165,451,452,472,487,496,500,516,538],{"__ignoreMap":177},[270,453,454,456,458,460,462,464,467,469],{"class":272,"line":273},[270,455,355],{"class":354},[270,457,358],{"class":341},[270,459,361],{"class":341},[270,461,384],{"class":341},[270,463,412],{"class":341},[270,465,466],{"class":341}," bind",[270,468,361],{"class":341},[270,470,471],{"class":330}," \\\n",[270,473,474,477,480,483,485],{"class":272,"line":279},[270,475,476],{"class":341},"  --expected-installation-id",[270,478,479],{"class":334}," '",[270,481,482],{"class":341},"\u003Cinstallation-uuid>",[270,484,338],{"class":334},[270,486,471],{"class":330},[270,488,489,492],{"class":272,"line":286},[270,490,491],{"class":341},"  --expected-binding-version",[270,493,495],{"class":494},"sbssI"," 0\n",[270,497,498],{"class":272,"line":292},[270,499,283],{"emptyLinePlaceholder":282},[270,501,502,504,506,508,510,512,514],{"class":272,"line":298},[270,503,355],{"class":354},[270,505,358],{"class":341},[270,507,361],{"class":341},[270,509,364],{"class":341},[270,511,367],{"class":341},[270,513,370],{"class":341},[270,515,373],{"class":341},[270,517,518,520,522,524,526,528,530,532,534,536],{"class":272,"line":304},[270,519,355],{"class":354},[270,521,358],{"class":341},[270,523,361],{"class":341},[270,525,384],{"class":341},[270,527,364],{"class":341},[270,529,389],{"class":341},[270,531,392],{"class":341},[270,533,395],{"class":334},[270,535,398],{"class":330},[270,537,401],{"class":334},[270,539,540,542,544,546,548],{"class":272,"line":310},[270,541,355],{"class":354},[270,543,358],{"class":341},[270,545,361],{"class":341},[270,547,364],{"class":341},[270,549,550],{"class":341}," verify\n",[161,552,553,554,557],{},"Binding production additionally requires ",[165,555,556],{},"--allow-production",". After\nmigrate\u002Fbind\u002Fverify, remove the owner credential from process scope and use\nseparate restricted scheduler, operator, and worker credentials.",[559,560,562],"h3",{"id":561},"restores-and-clones","Restores and clones",[161,564,565],{},"A same-environment disaster-recovery restore retains its installation identity\nand deployment pin. A clone used for another environment must rotate identity\nexplicitly:",[170,567,569],{"className":316,"code":568,"filename":318,"language":319,"meta":177,"style":177},"taskq --context staging --yes target bind staging \\\n  --expected-installation-id '\u003Ccurrent-installation-uuid>' \\\n  --expected-binding-version '\u003Ccurrent-version>' \\\n  --rotate \\\n  --reason 'production clone promoted to staging'\n",[165,570,571,589,602,615,622],{"__ignoreMap":177},[270,572,573,575,577,579,581,583,585,587],{"class":272,"line":273},[270,574,355],{"class":354},[270,576,358],{"class":341},[270,578,361],{"class":341},[270,580,384],{"class":341},[270,582,412],{"class":341},[270,584,466],{"class":341},[270,586,361],{"class":341},[270,588,471],{"class":330},[270,590,591,593,595,598,600],{"class":272,"line":279},[270,592,476],{"class":341},[270,594,479],{"class":334},[270,596,597],{"class":341},"\u003Ccurrent-installation-uuid>",[270,599,338],{"class":334},[270,601,471],{"class":330},[270,603,604,606,608,611,613],{"class":272,"line":286},[270,605,491],{"class":341},[270,607,479],{"class":334},[270,609,610],{"class":341},"\u003Ccurrent-version>",[270,612,338],{"class":334},[270,614,471],{"class":330},[270,616,617,620],{"class":272,"line":292},[270,618,619],{"class":341},"  --rotate",[270,621,471],{"class":330},[270,623,624,627,629,632],{"class":272,"line":298},[270,625,626],{"class":341},"  --reason",[270,628,479],{"class":334},[270,630,631],{"class":341},"production clone promoted to staging",[270,633,345],{"class":334},[161,635,636],{},"Rotation invalidates prior scheduler and worker pins.",[254,638,640],{"id":639},"_2-pin-runtime-identity","2. Pin runtime identity",[161,642,643],{},"Target expectations come from static deployment configuration, never from a\ndatabase read performed during startup:",[170,645,648],{"className":316,"code":646,"filename":647,"language":319,"meta":177,"style":177},"TASKQ_DSN=postgresql:\u002F\u002Ftaskq_scheduler:...@db-host\u002Fapp\nTASKQ_EXPECTED_ENV=staging\nTASKQ_EXPECTED_INSTALLATION_ID=\u003Cstaging-installation-uuid>\n","Environment",[165,649,650,660,670],{"__ignoreMap":177},[270,651,652,655,657],{"class":272,"line":273},[270,653,654],{"class":330},"TASKQ_DSN",[270,656,335],{"class":334},[270,658,659],{"class":341},"postgresql:\u002F\u002Ftaskq_scheduler:...@db-host\u002Fapp\n",[270,661,662,665,667],{"class":272,"line":279},[270,663,664],{"class":330},"TASKQ_EXPECTED_ENV",[270,666,335],{"class":334},[270,668,669],{"class":341},"staging\n",[270,671,672,675,678,681],{"class":272,"line":286},[270,673,674],{"class":330},"TASKQ_EXPECTED_INSTALLATION_ID",[270,676,677],{"class":334},"=\u003C",[270,679,680],{"class":341},"staging-installation-uuid",[270,682,683],{"class":334},">\n",[161,685,686],{},"The installation UUID pin is optional outside production but strongly useful\nfor catching restored or copied databases. Production requires both the pin and\nexplicit opt-in:",[170,688,690],{"className":316,"code":689,"filename":647,"language":319,"meta":177,"style":177},"TASKQ_EXPECTED_ENV=production\nTASKQ_EXPECTED_INSTALLATION_ID=\u003Cproduction-installation-uuid>\nTASKQ_ALLOW_PRODUCTION=true\n",[165,691,692,701,712],{"__ignoreMap":177},[270,693,694,696,698],{"class":272,"line":273},[270,695,664],{"class":330},[270,697,335],{"class":334},[270,699,700],{"class":341},"production\n",[270,702,703,705,707,710],{"class":272,"line":279},[270,704,674],{"class":330},[270,706,677],{"class":334},[270,708,709],{"class":341},"production-installation-uuid",[270,711,683],{"class":334},[270,713,714,717,719],{"class":272,"line":286},[270,715,716],{"class":330},"TASKQ_ALLOW_PRODUCTION",[270,718,335],{"class":334},[270,720,721],{"class":341},"true\n",[723,724,725],"caution",{},[161,726,727,728,731],{},"A process cannot make a production DSN safe by labeling itself\n",[165,729,730],{},"development",". Schedule mutation, scheduler runtime, housekeeping, and direct\nworker claims establish database-attested expectations inside each protected\ntransaction.",[161,733,734],{},"Use distinct DSNs, task namespaces, queues, and supervisor configuration for\ndevelopment, staging, and production. Never fall back to a production DSN when\nlocal configuration is missing.",[254,736,738],{"id":737},"_3-create-a-paused-manifest","3. Create a paused manifest",[161,740,741],{},"Manifests are versioned, source-owned desired state:",[170,743,748],{"className":744,"code":745,"filename":746,"language":747,"meta":177,"style":177},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","version: 1\nnamespace: myapp\nsource: api-deployment\nschedules:\n  maintenance:\n    display_name: Application maintenance\n    task: myapp.maintenance\n    queue: maintenance\n    interval_seconds: 300\n    catchup: fire_once\n    overlap: forbid\n    max_lateness_seconds: 900\n    state: paused\n    payload: {}\n","schedules.yaml","yaml",[165,749,750,762,772,782,790,797,807,817,828,839,850,861,872,883],{"__ignoreMap":177},[270,751,752,756,759],{"class":272,"line":273},[270,753,755],{"class":754},"swJcz","version",[270,757,758],{"class":334},":",[270,760,761],{"class":494}," 1\n",[270,763,764,767,769],{"class":272,"line":279},[270,765,766],{"class":754},"namespace",[270,768,758],{"class":334},[270,770,771],{"class":341}," myapp\n",[270,773,774,777,779],{"class":272,"line":286},[270,775,776],{"class":754},"source",[270,778,758],{"class":334},[270,780,781],{"class":341}," api-deployment\n",[270,783,784,787],{"class":272,"line":292},[270,785,786],{"class":754},"schedules",[270,788,789],{"class":334},":\n",[270,791,792,795],{"class":272,"line":298},[270,793,794],{"class":754},"  maintenance",[270,796,789],{"class":334},[270,798,799,802,804],{"class":272,"line":304},[270,800,801],{"class":754},"    display_name",[270,803,758],{"class":334},[270,805,806],{"class":341}," Application maintenance\n",[270,808,809,812,814],{"class":272,"line":310},[270,810,811],{"class":754},"    task",[270,813,758],{"class":334},[270,815,816],{"class":341}," myapp.maintenance\n",[270,818,820,823,825],{"class":272,"line":819},8,[270,821,822],{"class":754},"    queue",[270,824,758],{"class":334},[270,826,827],{"class":341}," maintenance\n",[270,829,831,834,836],{"class":272,"line":830},9,[270,832,833],{"class":754},"    interval_seconds",[270,835,758],{"class":334},[270,837,838],{"class":494}," 300\n",[270,840,842,845,847],{"class":272,"line":841},10,[270,843,844],{"class":754},"    catchup",[270,846,758],{"class":334},[270,848,849],{"class":341}," fire_once\n",[270,851,853,856,858],{"class":272,"line":852},11,[270,854,855],{"class":754},"    overlap",[270,857,758],{"class":334},[270,859,860],{"class":341}," forbid\n",[270,862,864,867,869],{"class":272,"line":863},12,[270,865,866],{"class":754},"    max_lateness_seconds",[270,868,758],{"class":334},[270,870,871],{"class":494}," 900\n",[270,873,875,878,880],{"class":272,"line":874},13,[270,876,877],{"class":754},"    state",[270,879,758],{"class":334},[270,881,882],{"class":341}," paused\n",[270,884,886,889,891],{"class":272,"line":885},14,[270,887,888],{"class":754},"    payload",[270,890,758],{"class":334},[270,892,893],{"class":334}," {}\n",[181,895,896,906],{},[184,897,898],{},[187,899,900,903],{},[190,901,902],{},"Field",[190,904,905],{},"Production guidance",[200,907,908,922,931,949,967,977,991],{},[187,909,910,915],{},[205,911,912,914],{},[165,913,766],{}," + key",[205,916,917,918,921],{},"Stable schedule identity (",[165,919,920],{},"myapp.maintenance",")",[187,923,924,928],{},[205,925,926],{},[165,927,776],{},[205,929,930],{},"Stable owner of this desired state",[187,932,933,938],{},[205,934,935],{},[165,936,937],{},"catchup",[205,939,940,941,944,945,948],{},"Explicit ",[165,942,943],{},"fire_once"," or ",[165,946,947],{},"fire_all"," in the current release",[187,950,951,956],{},[205,952,953],{},[165,954,955],{},"overlap",[205,957,958,959,962,963,966],{},"Start with ",[165,960,961],{},"forbid","; use ",[165,964,965],{},"allow"," only when every occurrence must enqueue",[187,968,969,974],{},[205,970,971],{},[165,972,973],{},"max_lateness_seconds",[205,975,976],{},"Drop work that is too stale to remain useful",[187,978,979,984],{},[205,980,981],{},[165,982,983],{},"state",[205,985,986,987,990],{},"Start ",[165,988,989],{},"paused","; activation is a separate reviewed change",[187,992,993,999],{},[205,994,995,998],{},[165,996,997],{},"payload"," \u002F headers",[205,1000,1001],{},"Never place credentials or other secrets here",[1003,1004,1005],"warning",{},[161,1006,1007,1008,1011,1012,1014,1015,1017],{},"Do not use ",[165,1009,1010],{},"catchup: skip"," for recurring application work in the current SQL\ncontract. The\nreleased SQL contract advances the schedule without selecting an\noccurrence, including during ordinary polling. Use explicit ",[165,1013,943],{}," or\n",[165,1016,947],{}," until a later SQL contract ships corrected skip-missed semantics.",[161,1019,1020,1022,1023,1025,1026,1029,1030,1032,1033,1036,1037,1040,1041,1044,1045,1048],{},[165,1021,943],{}," coalesces backlog to the latest due instant. ",[165,1024,947],{}," selects\noldest-first up to ",[165,1027,1028],{},"max_catchup",". With ",[165,1031,947],{}," plus ",[165,1034,1035],{},"overlap: forbid",", the\nfirst selected occurrence can enqueue and later occurrences in the same batch\nrecord ",[165,1038,1039],{},"overlap_skipped",". Use ",[165,1042,1043],{},"overlap: allow"," plus an execution\n",[165,1046,1047],{},"concurrency_key"," when every occurrence must queue but handlers must serialize.",[254,1050,1052],{"id":1051},"_4-plan-and-apply-without-firing","4. Plan and apply without firing",[161,1054,1055,1056,1059],{},"Use a restricted operator credential through the same target-pinned context\nshape (with ",[165,1057,1058],{},"dsn_env"," pointing at the operator credential):",[170,1061,1063],{"className":316,"code":1062,"filename":318,"language":319,"meta":177,"style":177},"export TASKQ_STAGING_DSN='postgresql:\u002F\u002Ftaskq_operator:...@db-host\u002Fapp'\n\ntaskq --context staging schedule manifest plan schedules.yaml -o json\ntaskq --context staging schedule manifest apply schedules.yaml \\\n  --plan-digest \"$PLAN_DIGEST\" -o json\n",[165,1064,1065,1080,1084,1107,1126],{"__ignoreMap":177},[270,1066,1067,1069,1071,1073,1075,1078],{"class":272,"line":273},[270,1068,327],{"class":326},[270,1070,331],{"class":330},[270,1072,335],{"class":334},[270,1074,338],{"class":334},[270,1076,1077],{"class":341},"postgresql:\u002F\u002Ftaskq_operator:...@db-host\u002Fapp",[270,1079,345],{"class":334},[270,1081,1082],{"class":272,"line":279},[270,1083,283],{"emptyLinePlaceholder":282},[270,1085,1086,1088,1090,1092,1095,1098,1100,1103,1105],{"class":272,"line":286},[270,1087,355],{"class":354},[270,1089,358],{"class":341},[270,1091,361],{"class":341},[270,1093,1094],{"class":341}," schedule",[270,1096,1097],{"class":341}," manifest",[270,1099,367],{"class":341},[270,1101,1102],{"class":341}," schedules.yaml",[270,1104,370],{"class":341},[270,1106,373],{"class":341},[270,1108,1109,1111,1113,1115,1117,1119,1122,1124],{"class":272,"line":292},[270,1110,355],{"class":354},[270,1112,358],{"class":341},[270,1114,361],{"class":341},[270,1116,1094],{"class":341},[270,1118,1097],{"class":341},[270,1120,1121],{"class":341}," apply",[270,1123,1102],{"class":341},[270,1125,471],{"class":330},[270,1127,1128,1131,1133,1135,1138,1140],{"class":272,"line":298},[270,1129,1130],{"class":341},"  --plan-digest",[270,1132,395],{"class":334},[270,1134,398],{"class":330},[270,1136,1137],{"class":334},"\"",[270,1139,370],{"class":341},[270,1141,373],{"class":341},[161,1143,1144,1147,1148,1151],{},[165,1145,1146],{},"plan"," never mutates. ",[165,1149,1150],{},"apply"," uses compare-and-swap versions and can create,\nupdate, or report unchanged\u002Fdrift. Missing keys are not pruned. Retire one owned\nkey explicitly:",[170,1153,1155],{"className":316,"code":1154,"filename":318,"language":319,"meta":177,"style":177},"taskq --context staging --yes schedule manifest retire schedules.yaml maintenance \\\n  --reason 'maintenance moved to another owner'\n",[165,1156,1157,1181],{"__ignoreMap":177},[270,1158,1159,1161,1163,1165,1167,1169,1171,1174,1176,1179],{"class":272,"line":273},[270,1160,355],{"class":354},[270,1162,358],{"class":341},[270,1164,361],{"class":341},[270,1166,384],{"class":341},[270,1168,1094],{"class":341},[270,1170,1097],{"class":341},[270,1172,1173],{"class":341}," retire",[270,1175,1102],{"class":341},[270,1177,1178],{"class":341}," maintenance",[270,1180,471],{"class":330},[270,1182,1183,1185,1187,1190],{"class":272,"line":279},[270,1184,626],{"class":341},[270,1186,479],{"class":334},[270,1188,1189],{"class":341},"maintenance moved to another owner",[270,1191,345],{"class":334},[161,1193,1194,1195,1197],{},"Production apply\u002Fretire requires the static production installation pin and an\nexplicit ",[165,1196,556],{}," flag.",[254,1199,1201],{"id":1200},"_5-start-the-executor-and-clock","5. Start the executor and clock",[161,1203,1204],{},"Start the application worker first, while the manifest is still paused. One\nhost-native worker can subscribe to several compatible queues through a\ncombined registry; TaskQ does not require a container per task, queue, or\nschedule.",[161,1206,1207],{},"Then validate and start the clock:",[170,1209,1211],{"className":316,"code":1210,"filename":318,"language":319,"meta":177,"style":177},"export TASKQ_DSN='postgresql:\u002F\u002Ftaskq_scheduler:...@db-host\u002Fapp'\nexport TASKQ_EXPECTED_ENV='staging'\nexport TASKQ_EXPECTED_INSTALLATION_ID='\u003Cstaging-installation-uuid>'\n\ntaskq --context staging scheduler doctor -o json\ntaskq --context staging scheduler run\n",[165,1212,1213,1229,1245,1261,1265,1283],{"__ignoreMap":177},[270,1214,1215,1217,1220,1222,1224,1227],{"class":272,"line":273},[270,1216,327],{"class":326},[270,1218,1219],{"class":330}," TASKQ_DSN",[270,1221,335],{"class":334},[270,1223,338],{"class":334},[270,1225,1226],{"class":341},"postgresql:\u002F\u002Ftaskq_scheduler:...@db-host\u002Fapp",[270,1228,345],{"class":334},[270,1230,1231,1233,1236,1238,1240,1243],{"class":272,"line":279},[270,1232,327],{"class":326},[270,1234,1235],{"class":330}," TASKQ_EXPECTED_ENV",[270,1237,335],{"class":334},[270,1239,338],{"class":334},[270,1241,1242],{"class":341},"staging",[270,1244,345],{"class":334},[270,1246,1247,1249,1252,1254,1256,1259],{"class":272,"line":286},[270,1248,327],{"class":326},[270,1250,1251],{"class":330}," TASKQ_EXPECTED_INSTALLATION_ID",[270,1253,335],{"class":334},[270,1255,338],{"class":334},[270,1257,1258],{"class":341},"\u003Cstaging-installation-uuid>",[270,1260,345],{"class":334},[270,1262,1263],{"class":272,"line":292},[270,1264,283],{"emptyLinePlaceholder":282},[270,1266,1267,1269,1271,1273,1276,1279,1281],{"class":272,"line":298},[270,1268,355],{"class":354},[270,1270,358],{"class":341},[270,1272,361],{"class":341},[270,1274,1275],{"class":341}," scheduler",[270,1277,1278],{"class":341}," doctor",[270,1280,370],{"class":341},[270,1282,373],{"class":341},[270,1284,1285,1287,1289,1291,1293],{"class":272,"line":304},[270,1286,355],{"class":354},[270,1288,358],{"class":341},[270,1290,361],{"class":341},[270,1292,1275],{"class":341},[270,1294,1295],{"class":341}," run\n",[161,1297,1298],{},"For scale-to-zero databases or platform timers, use bounded mode:",[170,1300,1302],{"className":316,"code":1301,"filename":318,"language":319,"meta":177,"style":177},"taskq --context staging scheduler once -o json\n",[165,1303,1304],{"__ignoreMap":177},[270,1305,1306,1308,1310,1312,1314,1317,1319],{"class":272,"line":273},[270,1307,355],{"class":354},[270,1309,358],{"class":341},[270,1311,361],{"class":341},[270,1313,1275],{"class":341},[270,1315,1316],{"class":341}," once",[270,1318,370],{"class":341},[270,1320,373],{"class":341},[161,1322,1323,1324,1327,1328,1331,1332,1334,1335,1338,1339,1342],{},"Bounded mode exits ",[165,1325,1326],{},"0"," for ",[165,1329,1330],{},"nothing_due"," or successful firing, ",[165,1333,437],{}," for target\nor configuration refusal, ",[165,1336,1337],{},"3"," for unavailable\u002Fversion\u002Fcapability failures or a\nbudget-exhausted pass, and ",[165,1340,1341],{},"1"," for an unexpected internal failure.",[559,1344,1346],{"id":1345},"bounded-worker-pulse","Bounded worker pulse",[161,1348,1349],{},"Workers normally remain supervised on an existing local worker host. When a\nhandler must reach dependencies available only on the API host's private\nnetwork, a platform timer may start a bounded worker from the existing\napplication image instead of adding one permanently running container.",[170,1351,1354],{"className":316,"code":1352,"filename":1353,"language":319,"meta":177,"style":177},"timeout --signal=INT --kill-after=30s 50s taskq --context staging worker run \\\n  --registry myapp.tasks:registry \\\n  --queue maintenance \\\n  --environment staging\n","Coolify scheduled task",[165,1355,1356,1385,1395,1404],{"__ignoreMap":177},[270,1357,1358,1361,1364,1367,1370,1373,1375,1377,1380,1383],{"class":272,"line":273},[270,1359,1360],{"class":354},"timeout",[270,1362,1363],{"class":341}," --signal=INT",[270,1365,1366],{"class":341}," --kill-after=30s",[270,1368,1369],{"class":341}," 50s",[270,1371,1372],{"class":341}," taskq",[270,1374,358],{"class":341},[270,1376,361],{"class":341},[270,1378,1379],{"class":341}," worker",[270,1381,1382],{"class":341}," run",[270,1384,471],{"class":330},[270,1386,1387,1390,1393],{"class":272,"line":279},[270,1388,1389],{"class":341},"  --registry",[270,1391,1392],{"class":341}," myapp.tasks:registry",[270,1394,471],{"class":330},[270,1396,1397,1400,1402],{"class":272,"line":286},[270,1398,1399],{"class":341},"  --queue",[270,1401,1178],{"class":341},[270,1403,471],{"class":330},[270,1405,1406,1409],{"class":272,"line":292},[270,1407,1408],{"class":341},"  --environment",[270,1410,1411],{"class":341}," staging\n",[161,1413,1414,1415,1417],{},"Run the pulse more frequently than the task's acceptable claim latency, keep\nits bounded runtime below the timer cadence, and give the platform a slightly\nlonger outer timeout. Treat intentional ",[165,1416,1360],{},"\u002FSIGINT shutdown as success\nonly after confirming the worker received a graceful stop. Durable queued work\nsurvives the gap between pulses, but this topology is unsuitable for queues\nthat require continuously low claim latency.",[161,1419,1420,1421,1424,1425,1428],{},"Each bounded invocation normally has a distinct worker identity and therefore\nleaves a historical presence row. Monitor recent ",[165,1422,1423],{},"online"," workers and\n",[165,1426,1427],{},"last_seen_at",", not the raw number of presence rows. Do not infer multiple live\nworkers merely because several completed pulses remain observable.",[161,1430,1431],{},"This is a documented dependency-placement exception, not the default. Do not\nmove ordinary workers into containers simply because the scheduler clock runs\nthere, and do not create one worker container per task or queue.",[254,1433,1435],{"id":1434},"_6-canary-and-activate","6. Canary and activate",[1437,1438,1439,1443,1446,1450,1453,1457,1467,1471,1479,1483],"steps",{"level":1337},[559,1440,1442],{"id":1441},"verify-isolation","Verify isolation",[161,1444,1445],{},"Confirm the expected target fingerprint, the paused manifest, one scheduler\nclock, the intended worker registry\u002Fqueues, and no stale jobs waiting in the\ntarget queue.",[559,1447,1449],{"id":1448},"run-an-immediate-canary","Run an immediate canary",[161,1451,1452],{},"Enqueue one ordinary job through the host producer path. Do not activate a\nrecurring schedule merely to get an immediate test.",[559,1454,1456],{"id":1455},"activate-desired-state","Activate desired state",[161,1458,1459,1460,1463,1464,1466],{},"Change the manifest to ",[165,1461,1462],{},"state: active",", run ",[165,1465,1146],{},", review the diff, and apply.",[559,1468,1470],{"id":1469},"wait-one-complete-interval","Wait one complete interval",[161,1472,1473,1474,1478],{},"Activation and resume are ",[1475,1476,1477],"strong",{},"from now",". The first scheduler pass anchors an\ninterval schedule; the first job becomes due after one full interval. Activation\ndoes not enqueue immediately.",[559,1480,1482],{"id":1481},"observe-the-whole-path","Observe the whole path",[161,1484,1485],{},"Verify the schedule decision, occurrence, queued job, worker claim, and handler\nresult before ending the attended pilot.",[254,1487,1489],{"id":1488},"monitor-independently-of-the-api","Monitor independently of the API",[170,1491,1493],{"className":316,"code":1492,"filename":318,"language":319,"meta":177,"style":177},"taskq --context staging scheduler doctor -o json\n",[165,1494,1495],{"__ignoreMap":177},[270,1496,1497,1499,1501,1503,1505,1507,1509],{"class":272,"line":273},[270,1498,355],{"class":354},[270,1500,358],{"class":341},[270,1502,361],{"class":341},[270,1504,1275],{"class":341},[270,1506,1278],{"class":341},[270,1508,370],{"class":341},[270,1510,373],{"class":341},[161,1512,1513],{},"Monitor:",[1515,1516,1517,1521,1527,1530,1533,1536],"ul",{},[1518,1519,1520],"li",{},"scheduler process presence and restart rate;",[1518,1522,1523,1526],{},[165,1524,1525],{},"last_decision_at"," advancement and oldest due time;",[1518,1528,1529],{},"due-schedule count and due lag;",[1518,1531,1532],{},"jobs enqueued, evaluation errors, and bounded-mode exhaustion;",[1518,1534,1535],{},"auto-paused schedules and overlap\u002Flateness skips;",[1518,1537,1538],{},"application worker presence and job outcomes.",[161,1540,1541],{},"Health totals can include TaskQ package-owned schedules such as the janitor.\nFilter decisions and jobs by the application namespace\u002Fqueue before asserting\nthat exactly one application schedule fired.",[161,1543,1544,1545,1548],{},"The host API ",[165,1546,1547],{},"\u002Fhealth"," endpoint does not prove that the scheduler clock or\napplication worker is healthy. Three consecutive deterministic definition or\ncalendar errors auto-pause a schedule; transient infrastructure errors do not\nincrement that counter.",[254,1550,1552],{"id":1551},"roll-back-stop-first","Roll back stop-first",[1554,1555,1556,1559,1565,1568,1571],"ol",{},[1518,1557,1558],{},"Stop the scheduler process or platform timer.",[1518,1560,1459,1561,1564],{},[165,1562,1563],{},"state: paused",", then plan and apply it.",[1518,1566,1567],{},"Allow an in-flight handler to finish or drain it, then stop the worker.",[1518,1569,1570],{},"Inspect queued jobs and durable schedule decisions before changing topology.",[1518,1572,1573],{},"Restore an embedded API loop only as a temporary, explicitly single-owner\ncompatibility measure.",[161,1575,1576],{},"Stopping the scheduler does not cancel queued or running jobs. Pausing a\nmanifest does not fix an incorrectly configured worker DSN, so environment\nidentity and worker supervision remain separate safety controls.",[254,1578,1580],{"id":1579},"outlabsauth-maintenance-recipe","OutlabsAuth maintenance recipe",[161,1582,1583,1584,1587,1588,1591,1592,1595,1596,1599,1600,1603,1604,1607],{},"OutlabsAuth ",[165,1585,1586],{},"0.1.0a29+"," exposes typed ",[165,1589,1590],{},"run_maintenance_once()"," while retaining\nthe raw ",[165,1593,1594],{},"run_background_jobs_once()"," compatibility method. Keep\n",[165,1597,1598],{},"background_job_mode=\"disabled\""," in every API replica, register a host task\nsuch as ",[165,1601,1602],{},"myapp.auth.maintenance",", and let its worker call the typed one-shot\nAPI. Translate ",[165,1605,1606],{},"report.ok=false"," into a retry outcome.",[161,1609,1610,1611,1614,1615,1617,1618,1621,1622,1625],{},"Use a paused manifest with ",[165,1612,1613],{},"catchup: fire_once",", ",[165,1616,1035],{},", and a queue\nconcurrency of one. The executor needs the host auth Postgres\u002FRedis access; the\nTaskQ scheduler does not. Persist only secret-free aggregate report fields and\nrequire empty ",[165,1619,1620],{},"missing_steps",", zero ",[165,1623,1624],{},"reported_errors",", and a successful TaskQ\njob outcome.",[161,1627,1628,1629,1636],{},"See the complete ",[1630,1631,1635],"a",{"href":1632,"rel":1633},"https:\u002F\u002Fauth.outlabs.io\u002Fgetting-started\u002Fbackground-maintenance",[1634],"nofollow","OutlabsAuth Background Maintenance guide",".",[254,1638,1640],{"id":1639},"related","Related",[1515,1642,1643,1647,1652,1656,1660,1664],{},[1518,1644,1645],{},[1630,1646,140],{"href":141},[1518,1648,1649],{},[1630,1650,1651],{"href":100},"Workflows & Schedules",[1518,1653,1654],{},[1630,1655,125],{"href":126},[1518,1657,1658],{},[1630,1659,31],{"href":32},[1518,1661,1662],{},[1630,1663,151],{"href":152},[1518,1665,1666],{},[1630,1667,1668],{"href":80},"Workers & Handlers",[1670,1671,1672],"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);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":177,"searchDepth":273,"depth":279,"links":1674},[1675,1678,1679,1680,1681,1684,1685,1686,1687,1688],{"id":256,"depth":279,"text":257,"children":1676},[1677],{"id":561,"depth":286,"text":562},{"id":639,"depth":279,"text":640},{"id":737,"depth":279,"text":738},{"id":1051,"depth":279,"text":1052},{"id":1200,"depth":279,"text":1201,"children":1682},[1683],{"id":1345,"depth":286,"text":1346},{"id":1434,"depth":279,"text":1435},{"id":1488,"depth":279,"text":1489},{"id":1551,"depth":279,"text":1552},{"id":1579,"depth":279,"text":1580},{"id":1639,"depth":279,"text":1640},"Bind the database target, apply paused manifests, and run one safe scheduler clock.","md",null,{},{"icon":123},{"title":120,"description":1689},"HLM4Nd_QBz9qNs1fD-Km0uFhV4pU2owNhdkNV5FsxRY",[1697,1699],{"title":109,"path":110,"stem":111,"description":1698,"icon":112,"children":-1},"Grow sealed workflows through compiled, hash-pinned member policies.",{"title":125,"path":126,"stem":127,"description":1700,"icon":128,"children":-1},"Tick, lease reaping, schedule firing, and wake behavior.",1787515777647]