[{"data":1,"prerenderedAt":2226},["ShallowReactive",2],{"navigation_docs_en":3,"-en-async-worker":342,"-en-async-worker-surround":2221},[4,45,61,96,132,166,196,217,241,265],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F10.reference",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F10.reference\u002F1.configuration","i-lucide-settings",{"title":57,"path":58,"stem":59,"icon":60},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F10.reference\u002F2.dependencies","i-lucide-package",{"title":62,"icon":63,"path":64,"stem":65,"children":66,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[67,72,77,82,86,91],{"title":68,"path":69,"stem":70,"icon":71},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture","i-lucide-layers",{"title":73,"path":74,"stem":75,"icon":76},"Application lifecycle","\u002Fen\u002Fconcepts\u002Fapplication-lifecycle","en\u002F2.concepts\u002F2.application-lifecycle","i-lucide-power",{"title":78,"path":79,"stem":80,"icon":81},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F3.error-model","i-lucide-shield-alert",{"title":52,"path":83,"stem":84,"icon":85},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F4.configuration","i-lucide-settings-2",{"title":87,"path":88,"stem":89,"icon":90},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F5.codegen-pipeline","i-lucide-file-json",{"title":92,"path":93,"stem":94,"icon":95},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F6.design-patterns","i-lucide-puzzle",{"title":97,"icon":98,"path":99,"stem":100,"children":101,"page":44},"HTTP & Routing","i-lucide-globe","\u002Fen\u002Fhttp","en\u002F3.http",[102,107,112,117,122,127],{"title":103,"path":104,"stem":105,"icon":106},"The server core","\u002Fen\u002Fhttp\u002Fserver","en\u002F3.http\u002F1.server","i-lucide-server",{"title":108,"path":109,"stem":110,"icon":111},"The Fiber engine","\u002Fen\u002Fhttp\u002Ffiber","en\u002F3.http\u002F2.fiber","i-lucide-zap",{"title":113,"path":114,"stem":115,"icon":116},"The chi engine","\u002Fen\u002Fhttp\u002Fchi","en\u002F3.http\u002F3.chi","i-lucide-route",{"title":118,"path":119,"stem":120,"icon":121},"Error responses","\u002Fen\u002Fhttp\u002Ferror-responses","en\u002F3.http\u002F4.error-responses","i-lucide-octagon-alert",{"title":123,"path":124,"stem":125,"icon":126},"Validation","\u002Fen\u002Fhttp\u002Fvalidation","en\u002F3.http\u002F5.validation","i-lucide-badge-check",{"title":128,"path":129,"stem":130,"icon":131},"Pagination","\u002Fen\u002Fhttp\u002Fpagination","en\u002F3.http\u002F6.pagination","i-lucide-list-ordered",{"title":133,"icon":134,"path":135,"stem":136,"children":137,"page":44},"Database","i-lucide-database","\u002Fen\u002Fdatabase","en\u002F4.database",[138,142,147,151,156,161],{"title":139,"path":140,"stem":141,"icon":134},"Overview","\u002Fen\u002Fdatabase\u002Foverview","en\u002F4.database\u002F1.overview",{"title":143,"path":144,"stem":145,"icon":146},"pgx","\u002Fen\u002Fdatabase\u002Fpgx","en\u002F4.database\u002F2.pgx","i-lucide-plug",{"title":148,"path":149,"stem":150,"icon":71},"bun","\u002Fen\u002Fdatabase\u002Fbun","en\u002F4.database\u002F3.bun",{"title":152,"path":153,"stem":154,"icon":155},"Transactions","\u002Fen\u002Fdatabase\u002Ftransactions","en\u002F4.database\u002F4.transactions","i-lucide-git-merge",{"title":157,"path":158,"stem":159,"icon":160},"Migrations","\u002Fen\u002Fdatabase\u002Fmigrations","en\u002F4.database\u002F5.migrations","i-lucide-file-stack",{"title":162,"path":163,"stem":164,"icon":165},"Seeders","\u002Fen\u002Fdatabase\u002Fseeding","en\u002F4.database\u002F6.seeding","i-lucide-sprout",{"title":167,"icon":168,"path":169,"stem":170,"children":171,"page":44},"Async & Background","i-lucide-workflow","\u002Fen\u002Fasync","en\u002F5.async",[172,176,181,186,191],{"title":173,"path":174,"stem":175,"icon":131},"Queue","\u002Fen\u002Fasync\u002Fqueue","en\u002F5.async\u002F1.queue",{"title":177,"path":178,"stem":179,"icon":180},"Events","\u002Fen\u002Fasync\u002Fevents","en\u002F5.async\u002F2.events","i-lucide-radio",{"title":182,"path":183,"stem":184,"icon":185},"Outbox","\u002Fen\u002Fasync\u002Foutbox","en\u002F5.async\u002F3.outbox","i-lucide-inbox",{"title":187,"path":188,"stem":189,"icon":190},"Scheduling","\u002Fen\u002Fasync\u002Fscheduler","en\u002F5.async\u002F4.scheduler","i-lucide-calendar-clock",{"title":192,"path":193,"stem":194,"icon":195},"Worker","\u002Fen\u002Fasync\u002Fworker","en\u002F5.async\u002F5.worker","i-lucide-cog",{"title":197,"icon":198,"path":199,"stem":200,"children":201,"page":44},"Security","i-lucide-shield-check","\u002Fen\u002Fsecurity","en\u002F6.security",[202,207,212],{"title":203,"path":204,"stem":205,"icon":206},"Authentication","\u002Fen\u002Fsecurity\u002Fauthentication","en\u002F6.security\u002F1.authentication","i-lucide-key-round",{"title":208,"path":209,"stem":210,"icon":211},"RBAC","\u002Fen\u002Fsecurity\u002Frbac","en\u002F6.security\u002F2.rbac","i-lucide-users",{"title":213,"path":214,"stem":215,"icon":216},"Policies","\u002Fen\u002Fsecurity\u002Fpolicies","en\u002F6.security\u002F3.policies","i-lucide-gavel",{"title":218,"icon":219,"path":220,"stem":221,"children":222,"page":44},"Observability","i-lucide-activity","\u002Fen\u002Fobservability","en\u002F7.observability",[223,226,231,236],{"title":139,"path":224,"stem":225,"icon":219},"\u002Fen\u002Fobservability\u002Foverview","en\u002F7.observability\u002F1.overview",{"title":227,"path":228,"stem":229,"icon":230},"Logging","\u002Fen\u002Fobservability\u002Flogging","en\u002F7.observability\u002F2.logging","i-lucide-scroll-text",{"title":232,"path":233,"stem":234,"icon":235},"OpenTelemetry","\u002Fen\u002Fobservability\u002Fopentelemetry","en\u002F7.observability\u002F3.opentelemetry","i-lucide-radar",{"title":237,"path":238,"stem":239,"icon":240},"Sentry","\u002Fen\u002Fobservability\u002Fsentry","en\u002F7.observability\u002F4.sentry","i-lucide-bug",{"title":242,"icon":243,"path":244,"stem":245,"children":246,"page":44},"Storage & Mail","i-lucide-hard-drive","\u002Fen\u002Fstorage-mail","en\u002F8.storage-mail",[247,251,256,261],{"title":248,"path":249,"stem":250,"icon":243},"Storage","\u002Fen\u002Fstorage-mail\u002Fstorage","en\u002F8.storage-mail\u002F1.storage",{"title":252,"path":253,"stem":254,"icon":255},"Email","\u002Fen\u002Fstorage-mail\u002Fmail","en\u002F8.storage-mail\u002F2.mail","i-lucide-mail",{"title":257,"path":258,"stem":259,"icon":260},"Notifications","\u002Fen\u002Fstorage-mail\u002Fnotifications","en\u002F8.storage-mail\u002F3.notifications","i-lucide-bell",{"title":262,"path":263,"stem":264,"icon":180},"Realtime","\u002Fen\u002Fstorage-mail\u002Frealtime","en\u002F8.storage-mail\u002F4.realtime",{"title":266,"icon":267,"path":268,"stem":269,"children":270,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F9.cli",[271,274,279,284,289,294,299,303,308,313,318,323,328,333,337],{"title":139,"path":272,"stem":273,"icon":267},"\u002Fen\u002Fcli\u002Foverview","en\u002F9.cli\u002F1.overview",{"title":275,"path":276,"stem":277,"icon":278},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F9.cli\u002F10.add-db","i-lucide-database-zap",{"title":280,"path":281,"stem":282,"icon":283},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F9.cli\u002F11.add-compose","i-lucide-container",{"title":285,"path":286,"stem":287,"icon":288},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F9.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":290,"path":291,"stem":292,"icon":293},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F9.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":295,"path":296,"stem":297,"icon":298},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F9.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":300,"path":301,"stem":302,"icon":165},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F9.cli\u002F15.add-seeder",{"title":304,"path":305,"stem":306,"icon":307},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F9.cli\u002F2.new-project","i-lucide-folder-plus",{"title":309,"path":310,"stem":311,"icon":312},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F9.cli\u002F3.new-module","i-lucide-blocks",{"title":314,"path":315,"stem":316,"icon":317},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F9.cli\u002F4.add-surface","i-lucide-layers-2",{"title":319,"path":320,"stem":321,"icon":322},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F9.cli\u002F5.add-core","i-lucide-box",{"title":324,"path":325,"stem":326,"icon":327},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F9.cli\u002F6.add-handler","i-lucide-webhook",{"title":329,"path":330,"stem":331,"icon":332},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F9.cli\u002F7.new-migration","i-lucide-file-plus",{"title":334,"path":335,"stem":336,"icon":195},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F9.cli\u002F8.worker-generators",{"title":338,"path":339,"stem":340,"icon":341},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F9.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"id":343,"title":192,"body":344,"description":2214,"extension":2215,"links":2216,"meta":2217,"navigation":2218,"path":193,"seo":2219,"stem":194,"__hash__":2220},"docs_en\u002Fen\u002F5.async\u002F5.worker.md",{"type":345,"value":346,"toc":2200},"minimark",[347,377,396,430,450,457,474,1183,1217,1220,1312,1339,1344,1350,1419,1434,1438,1452,1486,1493,1497,1566,1573,1721,1725,1751,1767,1785,1788,1799,1871,1967,1975,2025,2030,2033,2040,2081,2092,2096,2099,2128,2135,2139,2172,2196],[348,349,354],"pre",{"className":350,"code":351,"language":352,"meta":353,"style":353},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fgpsystem\u002Fworker\"\n","go","",[355,356,357],"code",{"__ignoreMap":353},[358,359,362,366,370,374],"span",{"class":360,"line":361},"line",1,[358,363,365],{"class":364},"s7zQu","import",[358,367,369],{"class":368},"sMK4o"," \"",[358,371,373],{"class":372},"sBMFI","github.com\u002Fgp-system\u002Fgpsystem\u002Fworker",[358,375,376],{"class":368},"\"\n",[378,379,380,383,384,387,388,395],"p",{},[355,381,382],{},"worker.Run"," is the background-work twin of the HTTP engines' ",[355,385,386],{},"Run",": the same ",[389,390,391,394],"a",{"href":74},[355,392,393],{},"app"," lifecycle"," (signal handling, graceful shutdown, closers, telemetry flush), except that instead of an HTTP server it runs three things in one binary:",[397,398,399,413,422],"ul",{},[400,401,402,403,407,408,412],"li",{},"the ",[404,405,406],"strong",{},"asynq server",": processing the ",[389,409,411],{"href":410},"\u002Fen\u002Fasync\u002Fqueue#task-types","event, listener, scheduled and job tasks",";",[400,414,402,415,421],{},[404,416,417],{},[389,418,420],{"href":419},"\u002Fen\u002Fasync\u002Foutbox#the-relay","outbox relay",": forwarding committed events to the queue;",[400,423,402,424,429],{},[404,425,426],{},[389,427,428],{"href":188},"schedule runner",": firing the cron entries, with leader election.",[378,431,432,433,436,437,440,441,443,444,449],{},"This runs task processing and scheduling ",[404,434,435],{},"in a single process",": instead of separate worker and scheduler deployments, you scale one ",[355,438,439],{},"cmd\u002Fworker"," binary. The binary comes with ",[355,442,304],{}," (for older projects ",[389,445,446],{"href":335},[355,447,448],{},"add worker"," backfills it), and you deploy and scale it independently of the API.",[451,452,454,455],"h2",{"id":453},"the-generated-cmdworker","The generated ",[355,456,439],{},[378,458,459,460,462,463,462,466,469,470,473],{},"The shop's worker binary: every line written by the generator; modules are wired in by ",[355,461,309],{}," \u002F ",[355,464,465],{},"add listener",[355,467,468],{},"add job"," at the ",[355,471,472],{},"\u002F\u002F gpsystem:*"," anchors.",[348,475,478],{"className":350,"code":476,"filename":477,"language":352,"meta":353,"style":353},"package main\n\nimport (\n    \"context\"\n    \"log\"\n\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx\u002Fpg\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fenvconf\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents\u002Foutbox\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fscheduler\"\n    \"github.com\u002Fgp-system\u002Fgpsystem\u002Fworker\"\n\n    \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\"\n    shopjobs \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fjobs\"\n    shoplisteners \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Flisteners\"\n    \"github.com\u002Facme\u002Fshop\u002Finternal\u002Fplatform\u002Fconfig\"\n)\n\nfunc main() {\n    cfg := envconf.MustLoad[config.Config]()\n    ctx := context.Background()\n    pool := pg.MustNewPool(ctx, cfg.DB)\n    relay := outbox.MustNewRelay(ctx, cfg.Outbox, pool, cfg.Worker.Redis)\n\n    err := worker.Run(ctx, cfg.Worker, func(reg *events.Registry, sched *scheduler.Schedule) error {\n        shopDeps := shop.Dependencies{\n            DB:         pg.NewDB(pool),\n            Transactor: pg.NewTransactor(pool),\n            Dispatcher: outbox.NewDispatcher(outbox.NewStore(pg.NewDB(pool))),\n        }\n        shoplisteners.Register(reg, shopDeps)\n        shopjobs.Register(sched, shopDeps)\n        return nil\n    },\n        worker.WithOutboxRelay(relay),\n        worker.WithCloser(\"pgxpool\", func(context.Context) error {\n            pool.Close()\n            return nil\n        }),\n    )\n    if err != nil {\n        log.Fatal(err)\n    }\n}\n","cmd\u002Fworker\u002Fmain.go",[355,479,480,488,495,503,514,524,529,539,549,559,569,579,588,593,603,618,631,641,647,652,668,700,719,754,802,807,878,897,922,943,984,990,1012,1033,1042,1048,1066,1103,1116,1124,1130,1136,1153,1171,1177],{"__ignoreMap":353},[358,481,482,485],{"class":360,"line":361},[358,483,484],{"class":368},"package",[358,486,487],{"class":372}," main\n",[358,489,491],{"class":360,"line":490},2,[358,492,494],{"emptyLinePlaceholder":493},true,"\n",[358,496,498,500],{"class":360,"line":497},3,[358,499,365],{"class":364},[358,501,502],{"class":368}," (\n",[358,504,506,509,512],{"class":360,"line":505},4,[358,507,508],{"class":368},"    \"",[358,510,511],{"class":372},"context",[358,513,376],{"class":368},[358,515,517,519,522],{"class":360,"line":516},5,[358,518,508],{"class":368},[358,520,521],{"class":372},"log",[358,523,376],{"class":368},[358,525,527],{"class":360,"line":526},6,[358,528,494],{"emptyLinePlaceholder":493},[358,530,532,534,537],{"class":360,"line":531},7,[358,533,508],{"class":368},[358,535,536],{"class":372},"github.com\u002Fgp-system\u002Fgpsystem\u002Fdbx\u002Fpg",[358,538,376],{"class":368},[358,540,542,544,547],{"class":360,"line":541},8,[358,543,508],{"class":368},[358,545,546],{"class":372},"github.com\u002Fgp-system\u002Fgpsystem\u002Fenvconf",[358,548,376],{"class":368},[358,550,552,554,557],{"class":360,"line":551},9,[358,553,508],{"class":368},[358,555,556],{"class":372},"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents",[358,558,376],{"class":368},[358,560,562,564,567],{"class":360,"line":561},10,[358,563,508],{"class":368},[358,565,566],{"class":372},"github.com\u002Fgp-system\u002Fgpsystem\u002Fevents\u002Foutbox",[358,568,376],{"class":368},[358,570,572,574,577],{"class":360,"line":571},11,[358,573,508],{"class":368},[358,575,576],{"class":372},"github.com\u002Fgp-system\u002Fgpsystem\u002Fscheduler",[358,578,376],{"class":368},[358,580,582,584,586],{"class":360,"line":581},12,[358,583,508],{"class":368},[358,585,373],{"class":372},[358,587,376],{"class":368},[358,589,591],{"class":360,"line":590},13,[358,592,494],{"emptyLinePlaceholder":493},[358,594,596,598,601],{"class":360,"line":595},14,[358,597,508],{"class":368},[358,599,600],{"class":372},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop",[358,602,376],{"class":368},[358,604,606,610,613,616],{"class":360,"line":605},15,[358,607,609],{"class":608},"sTEyZ","    shopjobs ",[358,611,612],{"class":368},"\"",[358,614,615],{"class":372},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Fjobs",[358,617,376],{"class":368},[358,619,621,624,626,629],{"class":360,"line":620},16,[358,622,623],{"class":608},"    shoplisteners ",[358,625,612],{"class":368},[358,627,628],{"class":372},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fmodules\u002Fshop\u002Flisteners",[358,630,376],{"class":368},[358,632,634,636,639],{"class":360,"line":633},17,[358,635,508],{"class":368},[358,637,638],{"class":372},"github.com\u002Facme\u002Fshop\u002Finternal\u002Fplatform\u002Fconfig",[358,640,376],{"class":368},[358,642,644],{"class":360,"line":643},18,[358,645,646],{"class":368},")\n",[358,648,650],{"class":360,"line":649},19,[358,651,494],{"emptyLinePlaceholder":493},[358,653,655,658,662,665],{"class":360,"line":654},20,[358,656,657],{"class":368},"func",[358,659,661],{"class":660},"s2Zo4"," main",[358,663,664],{"class":368},"()",[358,666,667],{"class":368}," {\n",[358,669,671,674,677,680,683,686,689,692,694,697],{"class":360,"line":670},21,[358,672,673],{"class":608},"    cfg ",[358,675,676],{"class":368},":=",[358,678,679],{"class":608}," envconf",[358,681,682],{"class":368},".",[358,684,685],{"class":660},"MustLoad",[358,687,688],{"class":368},"[",[358,690,691],{"class":372},"config",[358,693,682],{"class":368},[358,695,696],{"class":372},"Config",[358,698,699],{"class":368},"]()\n",[358,701,703,706,708,711,713,716],{"class":360,"line":702},22,[358,704,705],{"class":608},"    ctx ",[358,707,676],{"class":368},[358,709,710],{"class":608}," context",[358,712,682],{"class":368},[358,714,715],{"class":660},"Background",[358,717,718],{"class":368},"()\n",[358,720,722,725,727,730,732,735,738,741,744,747,749,752],{"class":360,"line":721},23,[358,723,724],{"class":608},"    pool ",[358,726,676],{"class":368},[358,728,729],{"class":608}," pg",[358,731,682],{"class":368},[358,733,734],{"class":660},"MustNewPool",[358,736,737],{"class":368},"(",[358,739,740],{"class":608},"ctx",[358,742,743],{"class":368},",",[358,745,746],{"class":608}," cfg",[358,748,682],{"class":368},[358,750,751],{"class":608},"DB",[358,753,646],{"class":368},[358,755,757,760,762,765,767,770,772,774,776,778,780,782,784,787,789,791,793,795,797,800],{"class":360,"line":756},24,[358,758,759],{"class":608},"    relay ",[358,761,676],{"class":368},[358,763,764],{"class":608}," outbox",[358,766,682],{"class":368},[358,768,769],{"class":660},"MustNewRelay",[358,771,737],{"class":368},[358,773,740],{"class":608},[358,775,743],{"class":368},[358,777,746],{"class":608},[358,779,682],{"class":368},[358,781,182],{"class":608},[358,783,743],{"class":368},[358,785,786],{"class":608}," pool",[358,788,743],{"class":368},[358,790,746],{"class":608},[358,792,682],{"class":368},[358,794,192],{"class":608},[358,796,682],{"class":368},[358,798,799],{"class":608},"Redis",[358,801,646],{"class":368},[358,803,805],{"class":360,"line":804},25,[358,806,494],{"emptyLinePlaceholder":493},[358,808,810,813,815,818,820,822,824,826,828,830,832,834,836,839,843,846,849,851,854,856,859,861,864,866,869,872,876],{"class":360,"line":809},26,[358,811,812],{"class":608},"    err ",[358,814,676],{"class":368},[358,816,817],{"class":608}," worker",[358,819,682],{"class":368},[358,821,386],{"class":660},[358,823,737],{"class":368},[358,825,740],{"class":608},[358,827,743],{"class":368},[358,829,746],{"class":608},[358,831,682],{"class":368},[358,833,192],{"class":608},[358,835,743],{"class":368},[358,837,838],{"class":368}," func(",[358,840,842],{"class":841},"sHdIc","reg",[358,844,845],{"class":368}," *",[358,847,848],{"class":372},"events",[358,850,682],{"class":368},[358,852,853],{"class":372},"Registry",[358,855,743],{"class":368},[358,857,858],{"class":841}," sched",[358,860,845],{"class":368},[358,862,863],{"class":372},"scheduler",[358,865,682],{"class":368},[358,867,868],{"class":372},"Schedule",[358,870,871],{"class":368},")",[358,873,875],{"class":874},"spNyl"," error",[358,877,667],{"class":368},[358,879,881,884,886,889,891,894],{"class":360,"line":880},27,[358,882,883],{"class":608},"        shopDeps ",[358,885,676],{"class":368},[358,887,888],{"class":372}," shop",[358,890,682],{"class":368},[358,892,893],{"class":372},"Dependencies",[358,895,896],{"class":368},"{\n",[358,898,900,903,906,909,911,914,916,919],{"class":360,"line":899},28,[358,901,902],{"class":608},"            DB",[358,904,905],{"class":368},":",[358,907,908],{"class":608},"         pg",[358,910,682],{"class":368},[358,912,913],{"class":660},"NewDB",[358,915,737],{"class":368},[358,917,918],{"class":608},"pool",[358,920,921],{"class":368},"),\n",[358,923,925,928,930,932,934,937,939,941],{"class":360,"line":924},29,[358,926,927],{"class":608},"            Transactor",[358,929,905],{"class":368},[358,931,729],{"class":608},[358,933,682],{"class":368},[358,935,936],{"class":660},"NewTransactor",[358,938,737],{"class":368},[358,940,918],{"class":608},[358,942,921],{"class":368},[358,944,946,949,951,953,955,958,960,963,965,968,970,973,975,977,979,981],{"class":360,"line":945},30,[358,947,948],{"class":608},"            Dispatcher",[358,950,905],{"class":368},[358,952,764],{"class":608},[358,954,682],{"class":368},[358,956,957],{"class":660},"NewDispatcher",[358,959,737],{"class":368},[358,961,962],{"class":608},"outbox",[358,964,682],{"class":368},[358,966,967],{"class":660},"NewStore",[358,969,737],{"class":368},[358,971,972],{"class":608},"pg",[358,974,682],{"class":368},[358,976,913],{"class":660},[358,978,737],{"class":368},[358,980,918],{"class":608},[358,982,983],{"class":368},"))),\n",[358,985,987],{"class":360,"line":986},31,[358,988,989],{"class":368},"        }\n",[358,991,993,996,998,1001,1003,1005,1007,1010],{"class":360,"line":992},32,[358,994,995],{"class":608},"        shoplisteners",[358,997,682],{"class":368},[358,999,1000],{"class":660},"Register",[358,1002,737],{"class":368},[358,1004,842],{"class":608},[358,1006,743],{"class":368},[358,1008,1009],{"class":608}," shopDeps",[358,1011,646],{"class":368},[358,1013,1015,1018,1020,1022,1024,1027,1029,1031],{"class":360,"line":1014},33,[358,1016,1017],{"class":608},"        shopjobs",[358,1019,682],{"class":368},[358,1021,1000],{"class":660},[358,1023,737],{"class":368},[358,1025,1026],{"class":608},"sched",[358,1028,743],{"class":368},[358,1030,1009],{"class":608},[358,1032,646],{"class":368},[358,1034,1036,1039],{"class":360,"line":1035},34,[358,1037,1038],{"class":364},"        return",[358,1040,1041],{"class":368}," nil\n",[358,1043,1045],{"class":360,"line":1044},35,[358,1046,1047],{"class":368},"    },\n",[358,1049,1051,1054,1056,1059,1061,1064],{"class":360,"line":1050},36,[358,1052,1053],{"class":608},"        worker",[358,1055,682],{"class":368},[358,1057,1058],{"class":660},"WithOutboxRelay",[358,1060,737],{"class":368},[358,1062,1063],{"class":608},"relay",[358,1065,921],{"class":368},[358,1067,1069,1071,1073,1076,1078,1080,1084,1086,1088,1090,1092,1094,1097,1099,1101],{"class":360,"line":1068},37,[358,1070,1053],{"class":608},[358,1072,682],{"class":368},[358,1074,1075],{"class":660},"WithCloser",[358,1077,737],{"class":368},[358,1079,612],{"class":368},[358,1081,1083],{"class":1082},"sfazB","pgxpool",[358,1085,612],{"class":368},[358,1087,743],{"class":368},[358,1089,838],{"class":368},[358,1091,511],{"class":372},[358,1093,682],{"class":368},[358,1095,1096],{"class":372},"Context",[358,1098,871],{"class":368},[358,1100,875],{"class":874},[358,1102,667],{"class":368},[358,1104,1106,1109,1111,1114],{"class":360,"line":1105},38,[358,1107,1108],{"class":608},"            pool",[358,1110,682],{"class":368},[358,1112,1113],{"class":660},"Close",[358,1115,718],{"class":368},[358,1117,1119,1122],{"class":360,"line":1118},39,[358,1120,1121],{"class":364},"            return",[358,1123,1041],{"class":368},[358,1125,1127],{"class":360,"line":1126},40,[358,1128,1129],{"class":368},"        }),\n",[358,1131,1133],{"class":360,"line":1132},41,[358,1134,1135],{"class":368},"    )\n",[358,1137,1139,1142,1145,1148,1151],{"class":360,"line":1138},42,[358,1140,1141],{"class":364},"    if",[358,1143,1144],{"class":608}," err ",[358,1146,1147],{"class":368},"!=",[358,1149,1150],{"class":368}," nil",[358,1152,667],{"class":368},[358,1154,1156,1159,1161,1164,1166,1169],{"class":360,"line":1155},43,[358,1157,1158],{"class":608},"        log",[358,1160,682],{"class":368},[358,1162,1163],{"class":660},"Fatal",[358,1165,737],{"class":368},[358,1167,1168],{"class":608},"err",[358,1170,646],{"class":368},[358,1172,1174],{"class":360,"line":1173},44,[358,1175,1176],{"class":368},"    }\n",[358,1178,1180],{"class":360,"line":1179},45,[358,1181,1182],{"class":368},"}\n",[378,1184,1185,1186,1189,1190,1192,1193,1195,1196,1198,1199,1201,1202,462,1205,1208,1209,1212,1213,1216],{},"The pattern is the same as on the HTTP side: dependencies travel in an ",[404,1187,1188],{},"explicit"," ",[355,1191,893],{}," struct, and the register callback receives the event ",[355,1194,853],{}," and the ",[355,1197,868],{},", filled by the ",[355,1200,1000],{}," functions of the modules' generated ",[355,1203,1204],{},"listeners",[355,1206,1207],{},"jobs"," subpackages. The worker's ",[355,1210,1211],{},"Dispatcher"," is the ",[389,1214,1215],{"href":183},"outbox one"," too: an event dispatched by a listener gets the same guarantee as one dispatched from an HTTP request.",[451,1218,386],{"id":1219},"run",[348,1221,1223],{"className":350,"code":1222,"language":352,"meta":353,"style":353},"func Run(ctx context.Context, cfg Config, register RegisterFunc, opts ...Option) error\n\ntype RegisterFunc func(reg *events.Registry, sched *scheduler.Schedule) error\n",[355,1224,1225,1273,1277],{"__ignoreMap":353},[358,1226,1227,1229,1232,1234,1236,1238,1240,1242,1244,1246,1249,1251,1254,1257,1259,1262,1265,1268,1270],{"class":360,"line":361},[358,1228,657],{"class":368},[358,1230,1231],{"class":660}," Run",[358,1233,737],{"class":368},[358,1235,740],{"class":841},[358,1237,710],{"class":372},[358,1239,682],{"class":368},[358,1241,1096],{"class":372},[358,1243,743],{"class":368},[358,1245,746],{"class":841},[358,1247,1248],{"class":372}," Config",[358,1250,743],{"class":368},[358,1252,1253],{"class":841}," register",[358,1255,1256],{"class":372}," RegisterFunc",[358,1258,743],{"class":368},[358,1260,1261],{"class":841}," opts",[358,1263,1264],{"class":368}," ...",[358,1266,1267],{"class":372},"Option",[358,1269,871],{"class":368},[358,1271,1272],{"class":874}," error\n",[358,1274,1275],{"class":360,"line":490},[358,1276,494],{"emptyLinePlaceholder":493},[358,1278,1279,1282,1284,1286,1288,1290,1292,1294,1296,1298,1300,1302,1304,1306,1308,1310],{"class":360,"line":497},[358,1280,1281],{"class":368},"type",[358,1283,1256],{"class":372},[358,1285,838],{"class":368},[358,1287,842],{"class":841},[358,1289,845],{"class":368},[358,1291,848],{"class":372},[358,1293,682],{"class":368},[358,1295,853],{"class":372},[358,1297,743],{"class":368},[358,1299,858],{"class":841},[358,1301,845],{"class":368},[358,1303,863],{"class":372},[358,1305,682],{"class":368},[358,1307,868],{"class":372},[358,1309,871],{"class":368},[358,1311,1272],{"class":874},[378,1313,1314,1316,1317,1320,1321,1324,1325,1331,1332,1334,1335,1338],{},[355,1315,386],{},", in order: telemetry bootstrap (",[355,1318,1319],{},"telemetry.Setup",") → ",[355,1322,1323],{},"register"," builds the registry and the schedule → opens a ",[389,1326,1328],{"href":1327},"\u002Fen\u002Fasync\u002Fqueue#client",[355,1329,1330],{},"queue.Client"," (PING) → starts the asynq server, alongside the relay (when you passed ",[355,1333,1058],{},") and the schedule runner (when the schedule is non-empty; an empty schedule means no leader election either) → blocks until SIGINT\u002FSIGTERM. Returns ",[355,1336,1337],{},"nil"," on a clean shutdown.",[1340,1341,1343],"h3",{"id":1342},"what-processes-the-tasks","What processes the tasks",[378,1345,1346,1347,905],{},"The worker registers four built-in handlers on the ",[389,1348,1349],{"href":410},"task-type prefixes",[1351,1352,1353,1366],"table",{},[1354,1355,1356],"thead",{},[1357,1358,1359,1363],"tr",{},[1360,1361,1362],"th",{},"Task",[1360,1364,1365],{},"What the handler does",[1367,1368,1369,1384,1399,1409],"tbody",{},[1357,1370,1371,1377],{},[1372,1373,1374],"td",{},[355,1375,1376],{},"event:\u003Cname>",[1372,1378,1379,1380,1383],{},"fan-out: enqueues one ",[355,1381,1382],{},"listener:"," task per listener, with a deterministic TaskID",[1357,1385,1386,1391],{},[1372,1387,1388],{},[355,1389,1390],{},"listener:\u003Cevent>:\u003Cname>",[1372,1392,1393,1394,1398],{},"decodes the envelope, puts the ",[389,1395,1397],{"href":1396},"\u002Fen\u002Fasync\u002Fevents#the-envelope-and-the-delivery-metadata","Meta"," on the context, invokes your listener",[1357,1400,1401,1406],{},[1372,1402,1403],{},[355,1404,1405],{},"schedule:\u003Cevent>",[1372,1407,1408],{},"a scheduled fire: builds a fresh envelope (id = the trigger's task id) and fans out",[1357,1410,1411,1416],{},[1372,1412,1413],{},[355,1414,1415],{},"job:\u003Cname>",[1372,1417,1418],{},"invokes the scheduled job's handler",[378,1420,1421,1422,1425,1426,1429,1430,1433],{},"Every handler runs through three middleware: a per-task Sentry hub (breadcrumb isolation), ",[404,1423,1424],{},"panic recovery"," (a panicking handler becomes an ",[355,1427,1428],{},"errs"," error and retries instead of killing the worker), and tracing: the consumer span continues the envelope's trace context, so the ",[389,1431,1432],{"href":233},"whole path is one trace",". A task with no registered handler (say, a deploy removed the listener) is skipped with a warning rather than retried forever.",[1340,1435,1437],{"id":1436},"shutdown-order","Shutdown order",[378,1439,1440,1441,1444,1445,1448,1449,1451],{},"On ",[355,1442,1443],{},"SIGINT","\u002F",[355,1446,1447],{},"SIGTERM",", ",[355,1450,386],{}," shuts down in a deterministic order:",[1453,1454,1455,1461,1471,1480],"ol",{},[400,1456,1457,1460],{},[404,1458,1459],{},"the producing loops stop",": the schedule runner (releasing its lease) and the relay's poll loop;",[400,1462,1463,1466,1467,1470],{},[404,1464,1465],{},"in-flight tasks drain",": for at most ",[355,1468,1469],{},"WORKER_SHUTDOWN_TIMEOUT","; whatever doesn't finish is requeued by asynq and redelivered later (one more reason for idempotent listeners);",[400,1472,1473,1476,1477,1479],{},[404,1474,1475],{},"closers run LIFO",": first the kit's own (scheduler, relay, queue client), then your ",[355,1478,1075],{},"s (in the shop, the pgx pool);",[400,1481,1482,1485],{},[404,1483,1484],{},"telemetry flush",": the last spans and logs still go out.",[378,1487,1488,1489,1492],{},"It is the same guarantee as on the HTTP side: a deploy doesn't cut an e-mail send in half. See the ",[389,1490,1491],{"href":74},"application lifecycle"," for details.",[451,1494,1496],{"id":1495},"options","Options",[1351,1498,1499,1508],{},[1354,1500,1501],{},[1357,1502,1503,1505],{},[1360,1504,1267],{},[1360,1506,1507],{},"Effect",[1367,1509,1510,1523,1533,1546,1556],{},[1357,1511,1512,1517],{},[1372,1513,1514],{},[355,1515,1516],{},"WithOutboxRelay(*outbox.Relay)",[1372,1518,1519,1520,1522],{},"runs the ",[389,1521,420],{"href":419}," inside this worker (safe on N replicas)",[1357,1524,1525,1530],{},[1372,1526,1527],{},[355,1528,1529],{},"WithCloser(name, fn)",[1372,1531,1532],{},"cleanup during graceful shutdown, after tasks have drained (LIFO)",[1357,1534,1535,1540],{},[1372,1536,1537],{},[355,1538,1539],{},"WithoutTelemetry()",[1372,1541,1542,1543,1545],{},"skips ",[355,1544,1319],{},"; for tests, or when the process configures it itself",[1357,1547,1548,1553],{},[1372,1549,1550],{},[355,1551,1552],{},"WithAsynqConfig(func(*asynq.Config))",[1372,1554,1555],{},"mutates the raw asynq config before the server is built; an escape hatch for settings the kit doesn't expose",[1357,1557,1558,1563],{},[1372,1559,1560],{},[355,1561,1562],{},"WithMux(func(*asynq.ServeMux))",[1372,1564,1565],{},"registers extra raw asynq handlers, for task types the kit doesn't model",[378,1567,1568,1569,1572],{},"The two escape hatches are the worker-side half of the kit's ",[389,1570,1571],{"href":174},"\"centralize, don't abstract\""," principle: when you need an asynq capability, you don't have to leave the chassis.",[348,1574,1576],{"className":350,"code":1575,"language":352,"meta":353,"style":353},"worker.Run(ctx, cfg.Worker, register,\n    worker.WithAsynqConfig(func(c *asynq.Config) {\n        c.HealthCheckFunc = reportHealth\n    }),\n    worker.WithMux(func(mux *asynq.ServeMux) {\n        mux.HandleFunc(\"import:products\", handleProductImport) \u002F\u002F your own task type\n    }),\n)\n",[355,1577,1578,1606,1635,1651,1656,1683,1713,1717],{"__ignoreMap":353},[358,1579,1580,1583,1585,1587,1589,1591,1593,1595,1597,1599,1601,1603],{"class":360,"line":361},[358,1581,1582],{"class":608},"worker",[358,1584,682],{"class":368},[358,1586,386],{"class":660},[358,1588,737],{"class":368},[358,1590,740],{"class":608},[358,1592,743],{"class":368},[358,1594,746],{"class":608},[358,1596,682],{"class":368},[358,1598,192],{"class":608},[358,1600,743],{"class":368},[358,1602,1253],{"class":608},[358,1604,1605],{"class":368},",\n",[358,1607,1608,1611,1613,1616,1619,1622,1624,1627,1629,1631,1633],{"class":360,"line":490},[358,1609,1610],{"class":608},"    worker",[358,1612,682],{"class":368},[358,1614,1615],{"class":660},"WithAsynqConfig",[358,1617,1618],{"class":368},"(func(",[358,1620,1621],{"class":841},"c",[358,1623,845],{"class":368},[358,1625,1626],{"class":372},"asynq",[358,1628,682],{"class":368},[358,1630,696],{"class":372},[358,1632,871],{"class":368},[358,1634,667],{"class":368},[358,1636,1637,1640,1642,1645,1648],{"class":360,"line":497},[358,1638,1639],{"class":608},"        c",[358,1641,682],{"class":368},[358,1643,1644],{"class":608},"HealthCheckFunc ",[358,1646,1647],{"class":368},"=",[358,1649,1650],{"class":608}," reportHealth\n",[358,1652,1653],{"class":360,"line":505},[358,1654,1655],{"class":368},"    }),\n",[358,1657,1658,1660,1662,1665,1667,1670,1672,1674,1676,1679,1681],{"class":360,"line":516},[358,1659,1610],{"class":608},[358,1661,682],{"class":368},[358,1663,1664],{"class":660},"WithMux",[358,1666,1618],{"class":368},[358,1668,1669],{"class":841},"mux",[358,1671,845],{"class":368},[358,1673,1626],{"class":372},[358,1675,682],{"class":368},[358,1677,1678],{"class":372},"ServeMux",[358,1680,871],{"class":368},[358,1682,667],{"class":368},[358,1684,1685,1688,1690,1693,1695,1697,1700,1702,1704,1707,1709],{"class":360,"line":526},[358,1686,1687],{"class":608},"        mux",[358,1689,682],{"class":368},[358,1691,1692],{"class":660},"HandleFunc",[358,1694,737],{"class":368},[358,1696,612],{"class":368},[358,1698,1699],{"class":1082},"import:products",[358,1701,612],{"class":368},[358,1703,743],{"class":368},[358,1705,1706],{"class":608}," handleProductImport",[358,1708,871],{"class":368},[358,1710,1712],{"class":1711},"sHwdD"," \u002F\u002F your own task type\n",[358,1714,1715],{"class":360,"line":531},[358,1716,1655],{"class":368},[358,1718,1719],{"class":360,"line":541},[358,1720,646],{"class":368},[451,1722,1724],{"id":1723},"queue-priorities","Queue priorities",[378,1726,1727,1728,1731,1732,1735,1736,1739,1740,1743,1744,1750],{},"The worker serves queues by weight: ",[355,1729,1730],{},"WORKER_QUEUES"," is a ",[355,1733,1734],{},"name:weight"," list, the counterpart of Horizon's ",[355,1737,1738],{},"balance","\u002Fqueue weighting. The shop puts its mail on a separate ",[355,1741,1742],{},"mail"," queue (the listener's ",[389,1745,1747],{"href":1746},"\u002Fen\u002Fasync\u002Fevents#listeners",[355,1748,1749],{},"queue.OnQueue(\"mail\")"," registration), so a mail burst can't crowd out the rest of the work:",[348,1752,1756],{"className":1753,"code":1754,"language":1755,"meta":353,"style":353},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","WORKER_QUEUES=default:3,mail:1\n","sh",[355,1757,1758],{"__ignoreMap":353},[358,1759,1760,1762,1764],{"class":360,"line":361},[358,1761,1730],{"class":608},[358,1763,1647],{"class":368},[358,1765,1766],{"class":1082},"default:3,mail:1\n",[378,1768,1769,1770,1773,1774,1776,1777,1780,1781,1784],{},"With that, the worker spends ~75% of its capacity on ",[355,1771,1772],{},"default"," and ~25% on ",[355,1775,1742],{}," whenever both have work. ",[355,1778,1779],{},"WORKER_STRICT_PRIORITY=true"," replaces weighting with a strict order: the highest-weight queue is drained completely before the next one is touched, useful when you have a ",[355,1782,1783],{},"critical"," queue that trumps everything.",[451,1786,52],{"id":1787},"configuration",[378,1789,1790,1791,1794,1795,1798],{},"You embed ",[355,1792,1793],{},"worker.Config"," without a prefix in the project config (ready-made in the generated ",[355,1796,1797],{},"config.go","):",[348,1800,1802],{"className":350,"code":1801,"language":352,"meta":353,"style":353},"type Config struct {\n    Worker worker.Config\n    DB     dbx.Config    `envPrefix:\"DB_\"`\n    Outbox outbox.Config `envPrefix:\"OUTBOX_\"`\n}\n",[355,1803,1804,1815,1827,1848,1867],{"__ignoreMap":353},[358,1805,1806,1808,1810,1813],{"class":360,"line":361},[358,1807,1281],{"class":368},[358,1809,1248],{"class":372},[358,1811,1812],{"class":368}," struct",[358,1814,667],{"class":368},[358,1816,1817,1820,1822,1824],{"class":360,"line":490},[358,1818,1819],{"class":608},"    Worker ",[358,1821,1582],{"class":372},[358,1823,682],{"class":368},[358,1825,1826],{"class":372},"Config\n",[358,1828,1829,1832,1835,1837,1839,1842,1845],{"class":360,"line":497},[358,1830,1831],{"class":608},"    DB     ",[358,1833,1834],{"class":372},"dbx",[358,1836,682],{"class":368},[358,1838,696],{"class":372},[358,1840,1841],{"class":368},"    `",[358,1843,1844],{"class":1082},"envPrefix:\"DB_\"",[358,1846,1847],{"class":368},"`\n",[358,1849,1850,1853,1855,1857,1859,1862,1865],{"class":360,"line":505},[358,1851,1852],{"class":608},"    Outbox ",[358,1854,962],{"class":372},[358,1856,682],{"class":368},[358,1858,696],{"class":372},[358,1860,1861],{"class":368}," `",[358,1863,1864],{"class":1082},"envPrefix:\"OUTBOX_\"",[358,1866,1847],{"class":368},[358,1868,1869],{"class":360,"line":516},[358,1870,1182],{"class":368},[1351,1872,1873,1886],{},[1354,1874,1875],{},[1357,1876,1877,1880,1883],{},[1360,1878,1879],{},"Variable",[1360,1881,1882],{},"Default",[1360,1884,1885],{},"Meaning",[1367,1887,1888,1903,1920,1935,1949],{},[1357,1889,1890,1895,1900],{},[1372,1891,1892],{},[355,1893,1894],{},"WORKER_CONCURRENCY",[1372,1896,1897],{},[355,1898,1899],{},"10",[1372,1901,1902],{},"number of tasks processed simultaneously",[1357,1904,1905,1909,1914],{},[1372,1906,1907],{},[355,1908,1730],{},[1372,1910,1911],{},[355,1912,1913],{},"default:1",[1372,1915,1916,1917,871],{},"queue → weight pairs (",[355,1918,1919],{},"critical:6,default:3,low:1",[1357,1921,1922,1927,1932],{},[1372,1923,1924],{},[355,1925,1926],{},"WORKER_STRICT_PRIORITY",[1372,1928,1929],{},[355,1930,1931],{},"false",[1372,1933,1934],{},"strict priority order instead of weighting",[1357,1936,1937,1941,1946],{},[1372,1938,1939],{},[355,1940,1469],{},[1372,1942,1943],{},[355,1944,1945],{},"30s",[1372,1947,1948],{},"bounds the graceful drain; unfinished tasks are requeued",[1357,1950,1951,1956,1961],{},[1372,1952,1953],{},[355,1954,1955],{},"WORKER_DEFAULT_MAX_RETRY",[1372,1957,1958],{},[355,1959,1960],{},"25",[1372,1962,1963,1964],{},"retry budget for listener\u002Fjob tasks without their own ",[355,1965,1966],{},"queue.MaxRetry",[378,1968,1969,1971,1972,905],{},[355,1970,1793],{}," embeds three more configs, so the worker binary is configured ",[404,1973,1974],{},"from a single set of env vars",[397,1976,1977,1994,2006],{},[400,1978,1979,1985,1986,1989,1990,1993],{},[389,1980,1982],{"href":1981},"\u002Fen\u002Fasync\u002Fqueue#configuration",[355,1983,1984],{},"queue.Config"," under the ",[355,1987,1988],{},"REDIS_"," prefix (",[355,1991,1992],{},"REDIS_ADDR",", ...),",[400,1995,1996,1985,2002,2005],{},[389,1997,1999],{"href":1998},"\u002Fen\u002Fasync\u002Fscheduler#configuration",[355,2000,2001],{},"scheduler.Config",[355,2003,2004],{},"SCHEDULER_"," prefix,",[400,2007,2008,2011,2012,1448,2015,1448,2018,2021,2022,682],{},[355,2009,2010],{},"telemetry.Config"," without a prefix (the standard ",[355,2013,2014],{},"OTEL_*",[355,2016,2017],{},"LOG_*",[355,2019,2020],{},"SENTRY_*"," names); see the ",[389,2023,2024],{"href":224},"observability overview",[378,2026,2027,2028,682],{},"The full env reference: ",[389,2029,1787],{"href":53},[451,2031,227],{"id":2032},"logging",[378,2034,2035,2036,2039],{},"The worker logs per task through the default ",[355,2037,2038],{},"slog"," logger, trace-correlated with the consumer span:",[397,2041,2042,2058,2067],{},[400,2043,2044,2047,2048,1448,2051,1448,2054,2057],{},[355,2045,2046],{},"worker: task started"," (Info): with ",[355,2049,2050],{},"task_type",[355,2052,2053],{},"task_id",[355,2055,2056],{},"attempt"," attributes;",[400,2059,2060,2063,2064,412],{},[355,2061,2062],{},"worker: task done"," (Info): plus ",[355,2065,2066],{},"duration",[400,2068,2069,2072,2073,2076,2077,2080],{},[355,2070,2071],{},"worker: task failed"," (Error): plus ",[355,2074,2075],{},"error","; an intentional skip (",[355,2078,2079],{},"SkipRetry",", e.g. no registered handler) appears only once, as a warning.",[378,2082,2083,2084,2087,2088,2091],{},"asynq's own internal logs flow into the same pipeline. Where the lines end up (dev console, JSON stdout, OTLP) is decided by the ",[389,2085,2086],{"href":228},"logging config","; ",[355,2089,2090],{},"LOG_LEVEL=WARN"," silences the per-task Info lines.",[451,2093,2095],{"id":2094},"scaling","Scaling",[378,2097,2098],{},"The worker is stateless: run as many replicas as your workload needs, and all three components are replica-safe.",[397,2100,2101,2106,2119],{},[400,2102,402,2103,2105],{},[404,2104,406],{}," by nature: one task goes to one worker at a time;",[400,2107,402,2108,2110,2111,2118],{},[404,2109,420],{}," via the ",[389,2112,2114,2117],{"href":2113},"\u002Fen\u002Fasync\u002Foutbox#scalability-n-replicas-no-double-delivery",[355,2115,2116],{},"FOR UPDATE SKIP LOCKED"," + deterministic TaskID"," pair;",[400,2120,402,2121,2110,2123,2127],{},[404,2122,428],{},[389,2124,2126],{"href":2125},"\u002Fen\u002Fasync\u002Fscheduler#replica-safety-the-leader-election","Redis-lease leader election",": one of N replicas fires.",[378,2129,2130,2131,682],{},"Nothing needs to be switched off or deployed separately to scale. The price is a single contract: delivery is at-least-once, so ",[389,2132,2134],{"href":2133},"\u002Fen\u002Fasync\u002Fevents#idempotency","listeners are idempotent",[451,2136,2138],{"id":2137},"running-locally","Running locally",[348,2140,2142],{"className":1753,"code":2141,"language":1755,"meta":353,"style":353},"go run .\u002Fcmd\u002Fmigrate up   # also applies the outbox_events migration\nmise run worker           # go run .\u002Fcmd\u002Fworker\n",[355,2143,2144,2160],{"__ignoreMap":353},[358,2145,2146,2148,2151,2154,2157],{"class":360,"line":361},[358,2147,352],{"class":372},[358,2149,2150],{"class":1082}," run",[358,2152,2153],{"class":1082}," .\u002Fcmd\u002Fmigrate",[358,2155,2156],{"class":1082}," up",[358,2158,2159],{"class":1711},"   # also applies the outbox_events migration\n",[358,2161,2162,2165,2167,2169],{"class":360,"line":490},[358,2163,2164],{"class":372},"mise",[358,2166,2150],{"class":1082},[358,2168,817],{"class":1082},[358,2170,2171],{"class":1711},"           # go run .\u002Fcmd\u002Fworker\n",[378,2173,2174,2175,2178,2179,2182,2183,1448,2186,1448,2188,1448,2190,2192,2193,682],{},"Redis comes from the project's ",[355,2176,2177],{},"compose.yml"," (",[355,2180,2181],{},"mise run dev","). For the generator commands (",[355,2184,2185],{},"add event",[355,2187,465],{},[355,2189,468],{},[355,2191,448],{},"), see the ",[389,2194,2195],{"href":335},"CLI worker generators",[2197,2198,2199],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":353,"searchDepth":490,"depth":490,"links":2201},[2202,2204,2208,2209,2210,2211,2212,2213],{"id":453,"depth":490,"text":2203},"The generated cmd\u002Fworker",{"id":1219,"depth":490,"text":386,"children":2205},[2206,2207],{"id":1342,"depth":497,"text":1343},{"id":1436,"depth":497,"text":1437},{"id":1495,"depth":490,"text":1496},{"id":1723,"depth":490,"text":1724},{"id":1787,"depth":490,"text":52},{"id":2032,"depth":490,"text":227},{"id":2094,"depth":490,"text":2095},{"id":2137,"depth":490,"text":2138},"The background-work chassis, asynq server, outbox relay and schedule runner in one binary, under a shared graceful shutdown.","md",null,{},{"icon":195},{"title":192,"description":2214},"Bxp29rWjGka0I-jTUJVlTdm-GVvFfk0i6g-opQV6poI",[2222,2224],{"title":187,"path":188,"stem":189,"description":2223,"icon":190,"children":-1},"Task scheduling in code, cron events and jobs, replica-safe with a Redis-lease leader election.",{"title":203,"path":204,"stem":205,"description":2225,"icon":206,"children":-1},"JWT issuing and the Bearer middleware: stateless auth.",1784668703994]