[{"data":1,"prerenderedAt":2690},["ShallowReactive",2],{"docs:\u002Fen\u002Fguide\u002Fperformer":3},{"page":4,"untranslated":2689,"translated":70},{"id":5,"title":6,"body":7,"description":2680,"extension":2681,"meta":2682,"navigation":70,"path":2683,"publishedAt":2684,"seo":2685,"stem":2686,"updatedAt":2687,"__hash__":2688},"docs_en\u002Fen\u002Fguide\u002Fperformer.md","Performer",{"type":8,"value":9,"toc":2659},"minimark",[10,14,22,27,321,334,338,352,376,398,466,469,499,517,547,551,561,675,688,693,709,764,773,775,795,965,1004,1008,1020,1065,1090,1094,1131,1135,1141,1315,1330,1334,1357,1527,1544,1743,1798,1802,1813,1852,1868,1922,1939,1943,1946,2162,2165,2222,2238,2304,2308,2334,2360,2375,2379,2400,2521,2549,2553,2565,2598,2603,2640,2644,2655],[11,12,6],"h1",{"id":13},"performer",[15,16,17,18,21],"p",{},"Job processing is defined as a class that extends ",[19,20,6],"code",{},".",[23,24,26],"h2",{"id":25},"基本形","Basic form",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-ts shiki shiki-themes github-light github-dark","import { Performer, type JobContext } from 'tsumugi\u002Fperformer';\n\nexport class SendMail extends Performer\u003C{ to: string; subject: string }, void, {}, Env> {\n  async perform(payload: { to: string; subject: string }, ctx: JobContext): Promise\u003Cvoid> {\n    const remaining = ctx.deadlineAt - Date.now();\n    await fetch('https:\u002F\u002Fapi.example.com\u002Fmail', {\n      method: 'POST',\n      body: JSON.stringify(payload),\n      \u002F\u002F Abort immediately if the deadline has passed\n      signal: remaining > 0 ? AbortSignal.timeout(remaining) : AbortSignal.abort(),\n    });\n  }\n}\n","ts","",[19,35,36,65,72,130,189,216,233,245,262,269,303,309,315],{"__ignoreMap":33},[37,38,41,45,49,52,55,58,62],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"szBVR","import",[37,46,48],{"class":47},"sVt8B"," { Performer, ",[37,50,51],{"class":43},"type",[37,53,54],{"class":47}," JobContext } ",[37,56,57],{"class":43},"from",[37,59,61],{"class":60},"sZZnC"," 'tsumugi\u002Fperformer'",[37,63,64],{"class":47},";\n",[37,66,68],{"class":39,"line":67},2,[37,69,71],{"emptyLinePlaceholder":70},true,"\n",[37,73,75,78,81,85,88,91,94,98,101,105,108,111,113,115,118,121,124,127],{"class":39,"line":74},3,[37,76,77],{"class":43},"export",[37,79,80],{"class":43}," class",[37,82,84],{"class":83},"sScJk"," SendMail",[37,86,87],{"class":43}," extends",[37,89,90],{"class":83}," Performer",[37,92,93],{"class":47},"\u003C{ ",[37,95,97],{"class":96},"s4XuR","to",[37,99,100],{"class":43},":",[37,102,104],{"class":103},"sj4cs"," string",[37,106,107],{"class":47},"; ",[37,109,110],{"class":96},"subject",[37,112,100],{"class":43},[37,114,104],{"class":103},[37,116,117],{"class":47}," }, ",[37,119,120],{"class":103},"void",[37,122,123],{"class":47},", {}, ",[37,125,126],{"class":83},"Env",[37,128,129],{"class":47},"> {\n",[37,131,133,136,139,142,145,147,150,152,154,156,158,160,162,164,166,169,171,174,177,179,182,185,187],{"class":39,"line":132},4,[37,134,135],{"class":43},"  async",[37,137,138],{"class":83}," perform",[37,140,141],{"class":47},"(",[37,143,144],{"class":96},"payload",[37,146,100],{"class":43},[37,148,149],{"class":47}," { ",[37,151,97],{"class":96},[37,153,100],{"class":43},[37,155,104],{"class":103},[37,157,107],{"class":47},[37,159,110],{"class":96},[37,161,100],{"class":43},[37,163,104],{"class":103},[37,165,117],{"class":47},[37,167,168],{"class":96},"ctx",[37,170,100],{"class":43},[37,172,173],{"class":83}," JobContext",[37,175,176],{"class":47},")",[37,178,100],{"class":43},[37,180,181],{"class":83}," Promise",[37,183,184],{"class":47},"\u003C",[37,186,120],{"class":103},[37,188,129],{"class":47},[37,190,192,195,198,201,204,207,210,213],{"class":39,"line":191},5,[37,193,194],{"class":43},"    const",[37,196,197],{"class":103}," remaining",[37,199,200],{"class":43}," =",[37,202,203],{"class":47}," ctx.deadlineAt ",[37,205,206],{"class":43},"-",[37,208,209],{"class":47}," Date.",[37,211,212],{"class":83},"now",[37,214,215],{"class":47},"();\n",[37,217,219,222,225,227,230],{"class":39,"line":218},6,[37,220,221],{"class":43},"    await",[37,223,224],{"class":83}," fetch",[37,226,141],{"class":47},[37,228,229],{"class":60},"'https:\u002F\u002Fapi.example.com\u002Fmail'",[37,231,232],{"class":47},", {\n",[37,234,236,239,242],{"class":39,"line":235},7,[37,237,238],{"class":47},"      method: ",[37,240,241],{"class":60},"'POST'",[37,243,244],{"class":47},",\n",[37,246,248,251,254,256,259],{"class":39,"line":247},8,[37,249,250],{"class":47},"      body: ",[37,252,253],{"class":103},"JSON",[37,255,21],{"class":47},[37,257,258],{"class":83},"stringify",[37,260,261],{"class":47},"(payload),\n",[37,263,265],{"class":39,"line":264},9,[37,266,268],{"class":267},"sJ8bj","      \u002F\u002F Abort immediately if the deadline has passed\n",[37,270,272,275,278,281,284,287,290,293,295,297,300],{"class":39,"line":271},10,[37,273,274],{"class":47},"      signal: remaining ",[37,276,277],{"class":43},">",[37,279,280],{"class":103}," 0",[37,282,283],{"class":43}," ?",[37,285,286],{"class":47}," AbortSignal.",[37,288,289],{"class":83},"timeout",[37,291,292],{"class":47},"(remaining) ",[37,294,100],{"class":43},[37,296,286],{"class":47},[37,298,299],{"class":83},"abort",[37,301,302],{"class":47},"(),\n",[37,304,306],{"class":39,"line":305},11,[37,307,308],{"class":47},"    });\n",[37,310,312],{"class":39,"line":311},12,[37,313,314],{"class":47},"  }\n",[37,316,318],{"class":39,"line":317},13,[37,319,320],{"class":47},"}\n",[15,322,323,324,21,326,329,330,333],{},"The type arguments are, in order, the payload, the return value, the declaration of required keys, and ",[19,325,126],{},[327,328],"br",{},"\nInside a performer, ",[19,331,332],{},"this.env"," gives access to the Worker's bindings.",[23,335,337],{"id":336},"binding名","Binding name",[15,339,340,341,343,344,347,348,351],{},"The binding name is the name exported from the Worker's entry point.",[327,342],{},"\nFor ",[19,345,346],{},"export class SendMail",", the binding name is ",[19,349,350],{},"SendMail",", and no separate registration is required.",[28,353,355],{"className":30,"code":354,"language":32,"meta":33,"style":33},"\u002F\u002F src\u002Findex.ts\nexport { SendMail } from '.\u002Fperformers\u002Fsend-mail.js';\n",[19,356,357,362],{"__ignoreMap":33},[37,358,359],{"class":39,"line":40},[37,360,361],{"class":267},"\u002F\u002F src\u002Findex.ts\n",[37,363,364,366,369,371,374],{"class":39,"line":67},[37,365,77],{"class":43},[37,367,368],{"class":47}," { SendMail } ",[37,370,57],{"class":43},[37,372,373],{"class":60}," '.\u002Fperformers\u002Fsend-mail.js'",[37,375,64],{"class":47},[15,377,378,379,382,383,21,386,388,389,391,392,394,395,397],{},"Pass the module that collects your performers directly to ",[19,380,381],{},"performers"," in ",[19,384,385],{},"defineTsumugi",[327,387],{},"\nThe payload and required-key types for each binding are derived from this ",[19,390,381],{}," object.",[327,393],{},"\nThe keys of ",[19,396,381],{}," must match the names exported from the Worker's entry point.",[28,399,401],{"className":30,"code":400,"language":32,"meta":33,"style":33},"import * as performers from '.\u002Fperformers\u002Findex.js';\n\nexport * from '.\u002Fperformers\u002Findex.js';\n\nconst tsumugi = defineTsumugi({ performers, \u002F* ... *\u002F });\n",[19,402,403,423,427,440,444],{"__ignoreMap":33},[37,404,405,407,410,413,416,418,421],{"class":39,"line":40},[37,406,44],{"class":43},[37,408,409],{"class":103}," *",[37,411,412],{"class":43}," as",[37,414,415],{"class":47}," performers ",[37,417,57],{"class":43},[37,419,420],{"class":60}," '.\u002Fperformers\u002Findex.js'",[37,422,64],{"class":47},[37,424,425],{"class":39,"line":67},[37,426,71],{"emptyLinePlaceholder":70},[37,428,429,431,433,436,438],{"class":39,"line":74},[37,430,77],{"class":43},[37,432,409],{"class":103},[37,434,435],{"class":43}," from",[37,437,420],{"class":60},[37,439,64],{"class":47},[37,441,442],{"class":39,"line":132},[37,443,71],{"emptyLinePlaceholder":70},[37,445,446,449,452,454,457,460,463],{"class":39,"line":191},[37,447,448],{"class":43},"const",[37,450,451],{"class":103}," tsumugi",[37,453,200],{"class":43},[37,455,456],{"class":83}," defineTsumugi",[37,458,459],{"class":47},"({ performers, ",[37,461,462],{"class":267},"\u002F* ... *\u002F",[37,464,465],{"class":47}," });\n",[15,467,468],{},"To use a different name for a binding, assign the alias in the file that collects and exports your performers.",[28,470,472],{"className":30,"code":471,"language":32,"meta":33,"style":33},"\u002F\u002F src\u002Fperformers\u002Findex.ts\nexport { SendMail as MAIL } from '.\u002Fsend-mail.js';\n",[19,473,474,479],{"__ignoreMap":33},[37,475,476],{"class":39,"line":40},[37,477,478],{"class":267},"\u002F\u002F src\u002Fperformers\u002Findex.ts\n",[37,480,481,483,486,489,492,494,497],{"class":39,"line":67},[37,482,77],{"class":43},[37,484,485],{"class":47}," { SendMail ",[37,487,488],{"class":43},"as",[37,490,491],{"class":47}," MAIL } ",[37,493,57],{"class":43},[37,495,496],{"class":60}," '.\u002Fsend-mail.js'",[37,498,64],{"class":47},[15,500,501,502,21,505,507,508,510,511,513,514,516],{},"If you assign the alias in the Worker's entry point, the runtime binding name becomes ",[19,503,504],{},"MAIL",[327,506],{},"\nIn that case, the key in ",[19,509,381],{}," remains ",[19,512,350],{},", so the two do not match.",[327,515],{},"\nDo not assign aliases in the Worker's entry point.",[28,518,520],{"className":30,"code":519,"language":32,"meta":33,"style":33},"\u002F\u002F src\u002Findex.ts\n\u002F\u002F Only the runtime export changes; the binding name in the types no longer matches\nexport { SendMail as MAIL } from '.\u002Fperformers\u002Fsend-mail.js';\n",[19,521,522,526,531],{"__ignoreMap":33},[37,523,524],{"class":39,"line":40},[37,525,361],{"class":267},[37,527,528],{"class":39,"line":67},[37,529,530],{"class":267},"\u002F\u002F Only the runtime export changes; the binding name in the types no longer matches\n",[37,532,533,535,537,539,541,543,545],{"class":39,"line":74},[37,534,77],{"class":43},[37,536,485],{"class":47},[37,538,488],{"class":43},[37,540,491],{"class":47},[37,542,57],{"class":43},[37,544,373],{"class":60},[37,546,64],{"class":47},[23,548,550],{"id":549},"実行コンテキスト","Execution context",[15,552,553,554,557,558,21],{},"The second argument of ",[19,555,556],{},"perform"," is a ",[19,559,560],{},"JobContext",[562,563,564,577],"table",{},[565,566,567],"thead",{},[568,569,570,574],"tr",{},[571,572,573],"th",{},"Field",[571,575,576],{},"Description",[578,579,580,591,601,611,621,631,641,655,665],"tbody",{},[568,581,582,588],{},[583,584,585],"td",{},[19,586,587],{},"jobId",[583,589,590],{},"The job ID",[568,592,593,598],{},[583,594,595],{},[19,596,597],{},"attempt",[583,599,600],{},"The attempt number. 1 for the first attempt",[568,602,603,608],{},[583,604,605],{},[19,606,607],{},"idempotencyKey",[583,609,610],{},"A value that is constant for each job. The same value is used on re-execution",[568,612,613,618],{},[583,614,615],{},[19,616,617],{},"deadlineAt",[583,619,620],{},"The timeout time, in epoch milliseconds",[568,622,623,628],{},[583,624,625],{},[19,626,627],{},"heartbeat",[583,629,630],{},"A function that reports that the job is running",[568,632,633,638],{},[583,634,635],{},[19,636,637],{},"log",[583,639,640],{},"An async function that saves messages during processing",[568,642,643,648],{},[583,644,645],{},[19,646,647],{},"traceparent",[583,649,650,651,654],{},"The trace information specified at enqueue. ",[19,652,653],{},"null"," if not specified",[568,656,657,662],{},[583,658,659],{},[19,660,661],{},"spawn",[583,663,664],{},"A function that adds a child node to the node of the running Flow",[568,666,667,672],{},[583,668,669],{},[19,670,671],{},"fail",[583,673,674],{},"A function that specifies whether a failed attempt can be retried (see \"Specifying a retry\" for usage)",[15,676,677,678,681,682,684,685,687],{},"With ",[19,679,680],{},"at-least-once",", assume that the same job may run more than once.",[327,683],{},"\nUse ",[19,686,607],{}," to make external side effects idempotent.",[689,690,692],"h3",{"id":691},"タイムアウトによる中断","Aborting on timeout",[15,694,695,696,699,700,702,703,705,706,21],{},"To abort processing on timeout, create an ",[19,697,698],{},"AbortSignal"," from ",[19,701,617],{}," and pass it to the operation.",[327,704],{},"\nIf the deadline has already passed, use ",[19,707,708],{},"AbortSignal.abort()",[28,710,712],{"className":30,"code":711,"language":32,"meta":33,"style":33},"const remaining = ctx.deadlineAt - Date.now();\nconst signal = remaining > 0 ? AbortSignal.timeout(remaining) : AbortSignal.abort();\n",[19,713,714,732],{"__ignoreMap":33},[37,715,716,718,720,722,724,726,728,730],{"class":39,"line":40},[37,717,448],{"class":43},[37,719,197],{"class":103},[37,721,200],{"class":43},[37,723,203],{"class":47},[37,725,206],{"class":43},[37,727,209],{"class":47},[37,729,212],{"class":83},[37,731,215],{"class":47},[37,733,734,736,739,741,744,746,748,750,752,754,756,758,760,762],{"class":39,"line":67},[37,735,448],{"class":43},[37,737,738],{"class":103}," signal",[37,740,200],{"class":43},[37,742,743],{"class":47}," remaining ",[37,745,277],{"class":43},[37,747,280],{"class":103},[37,749,283],{"class":43},[37,751,286],{"class":47},[37,753,289],{"class":83},[37,755,292],{"class":47},[37,757,100],{"class":43},[37,759,286],{"class":47},[37,761,299],{"class":83},[37,763,215],{"class":47},[15,765,766,767,769,770,772],{},"Tsumugi does not automatically stop a performer that has passed its deadline.",[327,768],{},"\nA performer that does not implement aborting with ",[19,771,617],{}," may continue to run after the deadline.",[689,774,627],{"id":627},[15,776,777,778,781,782,784,785,788,789,791,792,794],{},"For processing whose duration varies greatly depending on the input, you need to set ",[19,779,780],{},"timeoutMs"," to match the longest duration.",[327,783],{},"\nCalling ",[19,786,787],{},"ctx.heartbeat()"," updates the starting point of the timeout to the time of the last report.",[327,790],{},"\nTherefore, set ",[19,793,780],{}," to a value based on the interval between reports.",[28,796,798],{"className":30,"code":797,"language":32,"meta":33,"style":33},"class Import extends Performer\u003C{ rows: string[] }, void, {}, Env> {\n  async perform(payload: { rows: string[] }, ctx: JobContext): Promise\u003Cvoid> {\n    for (const [index, row] of payload.rows.entries()) {\n      await store(row);\n      await ctx.heartbeat((index + 1) \u002F payload.rows.length);\n    }\n  }\n}\n",[19,799,800,832,872,909,920,952,957,961],{"__ignoreMap":33},[37,801,802,805,808,810,812,814,817,819,821,824,826,828,830],{"class":39,"line":40},[37,803,804],{"class":43},"class",[37,806,807],{"class":83}," Import",[37,809,87],{"class":43},[37,811,90],{"class":83},[37,813,93],{"class":47},[37,815,816],{"class":96},"rows",[37,818,100],{"class":43},[37,820,104],{"class":103},[37,822,823],{"class":47},"[] }, ",[37,825,120],{"class":103},[37,827,123],{"class":47},[37,829,126],{"class":83},[37,831,129],{"class":47},[37,833,834,836,838,840,842,844,846,848,850,852,854,856,858,860,862,864,866,868,870],{"class":39,"line":67},[37,835,135],{"class":43},[37,837,138],{"class":83},[37,839,141],{"class":47},[37,841,144],{"class":96},[37,843,100],{"class":43},[37,845,149],{"class":47},[37,847,816],{"class":96},[37,849,100],{"class":43},[37,851,104],{"class":103},[37,853,823],{"class":47},[37,855,168],{"class":96},[37,857,100],{"class":43},[37,859,173],{"class":83},[37,861,176],{"class":47},[37,863,100],{"class":43},[37,865,181],{"class":83},[37,867,184],{"class":47},[37,869,120],{"class":103},[37,871,129],{"class":47},[37,873,874,877,880,882,885,888,891,894,897,900,903,906],{"class":39,"line":74},[37,875,876],{"class":43},"    for",[37,878,879],{"class":47}," (",[37,881,448],{"class":43},[37,883,884],{"class":47}," [",[37,886,887],{"class":103},"index",[37,889,890],{"class":47},", ",[37,892,893],{"class":103},"row",[37,895,896],{"class":47},"] ",[37,898,899],{"class":43},"of",[37,901,902],{"class":47}," payload.rows.",[37,904,905],{"class":83},"entries",[37,907,908],{"class":47},"()) {\n",[37,910,911,914,917],{"class":39,"line":132},[37,912,913],{"class":43},"      await",[37,915,916],{"class":83}," store",[37,918,919],{"class":47},"(row);\n",[37,921,922,924,927,929,932,935,938,941,944,946,949],{"class":39,"line":191},[37,923,913],{"class":43},[37,925,926],{"class":47}," ctx.",[37,928,627],{"class":83},[37,930,931],{"class":47},"((index ",[37,933,934],{"class":43},"+",[37,936,937],{"class":103}," 1",[37,939,940],{"class":47},") ",[37,942,943],{"class":43},"\u002F",[37,945,902],{"class":47},[37,947,948],{"class":103},"length",[37,950,951],{"class":47},");\n",[37,953,954],{"class":39,"line":218},[37,955,956],{"class":47},"    }\n",[37,958,959],{"class":39,"line":235},[37,960,314],{"class":47},[37,962,963],{"class":39,"line":247},[37,964,320],{"class":47},[15,966,967,968,970,971,973,974,976,977,979,980,982,983,986,987,989,990,993,994,21,996,998,999,21],{},"The progress argument is a number from 0 to 1 inclusive.",[327,969],{},"\nOut-of-range values are clamped, and non-numeric values are treated as a report with no progress.",[327,972],{},"\nThe reported progress is shown in the job details on the dashboard.",[327,975],{},"\nA call made within 5 seconds of the previous report does not send a report.",[327,978],{},"\nA failure to send a report is not raised as an exception.",[327,981],{},"\nThe return value is ",[19,984,985],{},"{ cancelRequested: boolean }",", which indicates whether cancellation has been requested.",[327,988],{},"\nOnce it becomes ",[19,991,992],{},"true",", the return values of subsequent calls are also ",[19,995,992],{},[327,997],{},"\nFor details on how cancellation works, see the section ",[1000,1001,1003],"a",{"href":1002},"\u002Fen\u002Fguide\u002Fexecution#%E5%AE%9F%E8%A1%8C%E4%B8%AD%E3%81%AE%E5%8F%96%E3%82%8A%E6%B6%88%E3%81%97","Cancellation during execution",[689,1005,1007],{"id":1006},"ログ","Logs",[15,1009,1010,1013,1014,1016,1017,21],{},[19,1011,1012],{},"ctx.log(message)"," saves a message during processing.",[327,1015],{},"\nThe call requires ",[19,1018,1019],{},"await",[28,1021,1023],{"className":30,"code":1022,"language":32,"meta":33,"style":33},"await ctx.log('Import started');\nawait importRows(payload.rows);\nawait ctx.log('Import completed');\n",[19,1024,1025,1040,1050],{"__ignoreMap":33},[37,1026,1027,1029,1031,1033,1035,1038],{"class":39,"line":40},[37,1028,1019],{"class":43},[37,1030,926],{"class":47},[37,1032,637],{"class":83},[37,1034,141],{"class":47},[37,1036,1037],{"class":60},"'Import started'",[37,1039,951],{"class":47},[37,1041,1042,1044,1047],{"class":39,"line":67},[37,1043,1019],{"class":43},[37,1045,1046],{"class":83}," importRows",[37,1048,1049],{"class":47},"(payload.rows);\n",[37,1051,1052,1054,1056,1058,1060,1063],{"class":39,"line":74},[37,1053,1019],{"class":43},[37,1055,926],{"class":47},[37,1057,637],{"class":83},[37,1059,141],{"class":47},[37,1061,1062],{"class":60},"'Import completed'",[37,1064,951],{"class":47},[15,1066,1067,1068,1070,1071,1073,1074,1076,1077,1079,1080,1082,1083,1085,1086,1089],{},"The dashboard shows the saved logs in the job details, together with the attempt number, the recording time, and the message body.",[327,1069],{},"\nIf the performer terminates abnormally afterward, the saved logs are not deleted.",[327,1072],{},"\nOnly the latest 20 logs are kept for each job.",[327,1075],{},"\nThe message body can be up to 2,000 characters, measured as JavaScript string length.",[327,1078],{},"\nAnything beyond that is truncated.",[327,1081],{},"\nA call made within 1 second of the previous save does not save a log.",[327,1084],{},"\nIf saving fails, the error is written to ",[19,1087,1088],{},"console.error"," and the job continues processing.",[689,1091,1093],{"id":1092},"トレース情報","Trace information",[15,1095,1096,1099,1100,1102,1103,1105,1106,1108,1109,1111,1112,1114,1115,1117,1118,1120,1121,1125,1126,1130],{},[19,1097,1098],{},"ctx.traceparent"," is the ",[19,1101,647],{}," value specified at enqueue, or ",[19,1104,653],{}," if none was specified.",[327,1107],{},"\nOn a retry, it has the same value as at enqueue.",[327,1110],{},"\nWhen you use a tracing SDK, create spans with ",[19,1113,1098],{}," as the parent context.",[327,1116],{},"\nFor the format to specify at enqueue and how to use ",[19,1119,661],{},", see ",[1000,1122,1124],{"href":1123},"\u002Fen\u002Fguide\u002Fenqueue#%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B9%E6%83%85%E5%A0%B1","Enqueuing jobs"," and ",[1000,1127,1129],{"href":1128},"\u002Fen\u002Fguide\u002Fflow#perform%E5%86%85%E3%81%8B%E3%82%89%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E8%BF%BD%E5%8A%A0","Flow",", respectively.",[23,1132,1134],{"id":1133},"失敗とリトライ","Failures and retries",[15,1136,1137,1138,1140],{},"When a job fails, an exception is thrown.",[327,1139],{},"\nIf the attempt count has not reached the limit, the job is retried.",[28,1142,1144],{"className":30,"code":1143,"language":32,"meta":33,"style":33},"class ChargeCard extends Performer\u003C{ customerId: string; amountJpy: number }, void, { concurrencyKey: true }, Env> {\n  async perform(payload: { customerId: string; amountJpy: number }): Promise\u003Cvoid> {\n    const res = await this.env.PAYMENT.charge(payload);\n    if (!res.ok) throw new Error(`payment failed: ${res.status}`);\n  }\n}\n",[19,1145,1146,1197,1238,1267,1307,1311],{"__ignoreMap":33},[37,1147,1148,1150,1153,1155,1157,1159,1162,1164,1166,1168,1171,1173,1176,1178,1180,1183,1186,1188,1191,1193,1195],{"class":39,"line":40},[37,1149,804],{"class":43},[37,1151,1152],{"class":83}," ChargeCard",[37,1154,87],{"class":43},[37,1156,90],{"class":83},[37,1158,93],{"class":47},[37,1160,1161],{"class":96},"customerId",[37,1163,100],{"class":43},[37,1165,104],{"class":103},[37,1167,107],{"class":47},[37,1169,1170],{"class":96},"amountJpy",[37,1172,100],{"class":43},[37,1174,1175],{"class":103}," number",[37,1177,117],{"class":47},[37,1179,120],{"class":103},[37,1181,1182],{"class":47},", { ",[37,1184,1185],{"class":96},"concurrencyKey",[37,1187,100],{"class":43},[37,1189,1190],{"class":103}," true",[37,1192,117],{"class":47},[37,1194,126],{"class":83},[37,1196,129],{"class":47},[37,1198,1199,1201,1203,1205,1207,1209,1211,1213,1215,1217,1219,1221,1223,1225,1228,1230,1232,1234,1236],{"class":39,"line":67},[37,1200,135],{"class":43},[37,1202,138],{"class":83},[37,1204,141],{"class":47},[37,1206,144],{"class":96},[37,1208,100],{"class":43},[37,1210,149],{"class":47},[37,1212,1161],{"class":96},[37,1214,100],{"class":43},[37,1216,104],{"class":103},[37,1218,107],{"class":47},[37,1220,1170],{"class":96},[37,1222,100],{"class":43},[37,1224,1175],{"class":103},[37,1226,1227],{"class":47}," })",[37,1229,100],{"class":43},[37,1231,181],{"class":83},[37,1233,184],{"class":47},[37,1235,120],{"class":103},[37,1237,129],{"class":47},[37,1239,1240,1242,1245,1247,1250,1253,1256,1259,1261,1264],{"class":39,"line":74},[37,1241,194],{"class":43},[37,1243,1244],{"class":103}," res",[37,1246,200],{"class":43},[37,1248,1249],{"class":43}," await",[37,1251,1252],{"class":103}," this",[37,1254,1255],{"class":47},".env.",[37,1257,1258],{"class":103},"PAYMENT",[37,1260,21],{"class":47},[37,1262,1263],{"class":83},"charge",[37,1265,1266],{"class":47},"(payload);\n",[37,1268,1269,1272,1274,1277,1280,1283,1286,1289,1291,1294,1297,1299,1302,1305],{"class":39,"line":132},[37,1270,1271],{"class":43},"    if",[37,1273,879],{"class":47},[37,1275,1276],{"class":43},"!",[37,1278,1279],{"class":47},"res.ok) ",[37,1281,1282],{"class":43},"throw",[37,1284,1285],{"class":43}," new",[37,1287,1288],{"class":83}," Error",[37,1290,141],{"class":47},[37,1292,1293],{"class":60},"`payment failed: ${",[37,1295,1296],{"class":47},"res",[37,1298,21],{"class":60},[37,1300,1301],{"class":47},"status",[37,1303,1304],{"class":60},"}`",[37,1306,951],{"class":47},[37,1308,1309],{"class":39,"line":191},[37,1310,314],{"class":47},[37,1312,1313],{"class":39,"line":218},[37,1314,320],{"class":47},[15,1316,1317,1318,1320,1321,1323,1324,1326,1327,21],{},"The exception message is saved in the attempt history, and the dashboard shows the attempt history in the job details.",[327,1319],{},"\nThe storage limits are 2,000 characters for a message and 20 entries of attempt history per job.",[327,1322],{},"\nIf the return value exceeds 8,192 characters or cannot be serialized, the return value is not saved.",[327,1325],{},"\nFor how return values are handled in Flow nodes, see ",[1000,1328,1129],{"href":1329},"\u002Fen\u002Fguide\u002Fflow#%E5%88%B6%E7%B4%84",[689,1331,1333],{"id":1332},"再試行の指定","Specifying a retry",[15,1335,1336,1337,1340,1341,1343,1344,1346,1347,1350,1351,21,1354,1356],{},"If you throw an exception after calling ",[19,1338,1339],{},"ctx.fail()",", the settings passed to ",[19,1342,1339],{}," apply to the retry that follows that attempt.",[327,1345],{},"\nIf you specify ",[19,1348,1349],{},"{ retry: false }",", the job is not retried even if the attempt count has not reached the limit, and it moves to ",[19,1352,1353],{},"FAILED",[327,1355],{},"\nUse this for failures where retrying will not change the result.",[28,1358,1360],{"className":30,"code":1359,"language":32,"meta":33,"style":33},"class SyncUser extends Performer\u003C{ userId: string }, void, {}, Env> {\n  async perform(payload: { userId: string }, ctx: JobContext): Promise\u003Cvoid> {\n    const res = await fetch(`https:\u002F\u002Fapi.example.com\u002Fusers\u002F${payload.userId}`);\n    if (res.status === 404) {\n      await ctx.fail({ retry: false });\n      throw new Error(`user not found: ${payload.userId}`);\n    }\n  }\n}\n",[19,1361,1362,1392,1432,1459,1475,1491,1515,1519,1523],{"__ignoreMap":33},[37,1363,1364,1366,1369,1371,1373,1375,1378,1380,1382,1384,1386,1388,1390],{"class":39,"line":40},[37,1365,804],{"class":43},[37,1367,1368],{"class":83}," SyncUser",[37,1370,87],{"class":43},[37,1372,90],{"class":83},[37,1374,93],{"class":47},[37,1376,1377],{"class":96},"userId",[37,1379,100],{"class":43},[37,1381,104],{"class":103},[37,1383,117],{"class":47},[37,1385,120],{"class":103},[37,1387,123],{"class":47},[37,1389,126],{"class":83},[37,1391,129],{"class":47},[37,1393,1394,1396,1398,1400,1402,1404,1406,1408,1410,1412,1414,1416,1418,1420,1422,1424,1426,1428,1430],{"class":39,"line":67},[37,1395,135],{"class":43},[37,1397,138],{"class":83},[37,1399,141],{"class":47},[37,1401,144],{"class":96},[37,1403,100],{"class":43},[37,1405,149],{"class":47},[37,1407,1377],{"class":96},[37,1409,100],{"class":43},[37,1411,104],{"class":103},[37,1413,117],{"class":47},[37,1415,168],{"class":96},[37,1417,100],{"class":43},[37,1419,173],{"class":83},[37,1421,176],{"class":47},[37,1423,100],{"class":43},[37,1425,181],{"class":83},[37,1427,184],{"class":47},[37,1429,120],{"class":103},[37,1431,129],{"class":47},[37,1433,1434,1436,1438,1440,1442,1444,1446,1449,1451,1453,1455,1457],{"class":39,"line":74},[37,1435,194],{"class":43},[37,1437,1244],{"class":103},[37,1439,200],{"class":43},[37,1441,1249],{"class":43},[37,1443,224],{"class":83},[37,1445,141],{"class":47},[37,1447,1448],{"class":60},"`https:\u002F\u002Fapi.example.com\u002Fusers\u002F${",[37,1450,144],{"class":47},[37,1452,21],{"class":60},[37,1454,1377],{"class":47},[37,1456,1304],{"class":60},[37,1458,951],{"class":47},[37,1460,1461,1463,1466,1469,1472],{"class":39,"line":132},[37,1462,1271],{"class":43},[37,1464,1465],{"class":47}," (res.status ",[37,1467,1468],{"class":43},"===",[37,1470,1471],{"class":103}," 404",[37,1473,1474],{"class":47},") {\n",[37,1476,1477,1479,1481,1483,1486,1489],{"class":39,"line":191},[37,1478,913],{"class":43},[37,1480,926],{"class":47},[37,1482,671],{"class":83},[37,1484,1485],{"class":47},"({ retry: ",[37,1487,1488],{"class":103},"false",[37,1490,465],{"class":47},[37,1492,1493,1496,1498,1500,1502,1505,1507,1509,1511,1513],{"class":39,"line":218},[37,1494,1495],{"class":43},"      throw",[37,1497,1285],{"class":43},[37,1499,1288],{"class":83},[37,1501,141],{"class":47},[37,1503,1504],{"class":60},"`user not found: ${",[37,1506,144],{"class":47},[37,1508,21],{"class":60},[37,1510,1377],{"class":47},[37,1512,1304],{"class":60},[37,1514,951],{"class":47},[37,1516,1517],{"class":39,"line":235},[37,1518,956],{"class":47},[37,1520,1521],{"class":39,"line":247},[37,1522,314],{"class":47},[37,1524,1525],{"class":39,"line":264},[37,1526,320],{"class":47},[15,1528,1529,1530,1533,1534,21,1537,1539,1540,1543],{},"If you specify epoch milliseconds in ",[19,1531,1532],{},"{ retryAt }",", that attempt alone is retried at the specified time instead of after the interval calculated by ",[19,1535,1536],{},"backoff",[327,1538],{},"\nThe following example converts the value of the ",[19,1541,1542],{},"Retry-After"," header (a number of seconds or an HTTP-date) into a time.",[28,1545,1547],{"className":30,"code":1546,"language":32,"meta":33,"style":33},"if (res.status === 429) {\n  const header = res.headers.get('Retry-After') ?? '';\n  const date = Date.parse(header);\n  \u002F\u002F 60 seconds later if the value cannot be parsed\n  const retryAt = \u002F^\\d+$\u002F.test(header)\n    ? Date.now() + Number(header) * 1_000\n    : Number.isNaN(date)\n      ? Date.now() + 60_000\n      : date;\n  await ctx.fail({ retryAt });\n  throw new Error('rate limited');\n}\n",[19,1548,1549,1563,1594,1611,1616,1647,1673,1687,1703,1711,1723,1739],{"__ignoreMap":33},[37,1550,1551,1554,1556,1558,1561],{"class":39,"line":40},[37,1552,1553],{"class":43},"if",[37,1555,1465],{"class":47},[37,1557,1468],{"class":43},[37,1559,1560],{"class":103}," 429",[37,1562,1474],{"class":47},[37,1564,1565,1568,1571,1573,1576,1579,1581,1584,1586,1589,1592],{"class":39,"line":67},[37,1566,1567],{"class":43},"  const",[37,1569,1570],{"class":103}," header",[37,1572,200],{"class":43},[37,1574,1575],{"class":47}," res.headers.",[37,1577,1578],{"class":83},"get",[37,1580,141],{"class":47},[37,1582,1583],{"class":60},"'Retry-After'",[37,1585,940],{"class":47},[37,1587,1588],{"class":43},"??",[37,1590,1591],{"class":60}," ''",[37,1593,64],{"class":47},[37,1595,1596,1598,1601,1603,1605,1608],{"class":39,"line":74},[37,1597,1567],{"class":43},[37,1599,1600],{"class":103}," date",[37,1602,200],{"class":43},[37,1604,209],{"class":47},[37,1606,1607],{"class":83},"parse",[37,1609,1610],{"class":47},"(header);\n",[37,1612,1613],{"class":39,"line":132},[37,1614,1615],{"class":267},"  \u002F\u002F 60 seconds later if the value cannot be parsed\n",[37,1617,1618,1620,1623,1625,1628,1631,1634,1637,1639,1641,1644],{"class":39,"line":191},[37,1619,1567],{"class":43},[37,1621,1622],{"class":103}," retryAt",[37,1624,200],{"class":43},[37,1626,1627],{"class":60}," \u002F",[37,1629,1630],{"class":43},"^",[37,1632,1633],{"class":103},"\\d",[37,1635,1636],{"class":43},"+$",[37,1638,943],{"class":60},[37,1640,21],{"class":47},[37,1642,1643],{"class":83},"test",[37,1645,1646],{"class":47},"(header)\n",[37,1648,1649,1652,1654,1656,1659,1661,1664,1667,1670],{"class":39,"line":218},[37,1650,1651],{"class":43},"    ?",[37,1653,209],{"class":47},[37,1655,212],{"class":83},[37,1657,1658],{"class":47},"() ",[37,1660,934],{"class":43},[37,1662,1663],{"class":83}," Number",[37,1665,1666],{"class":47},"(header) ",[37,1668,1669],{"class":43},"*",[37,1671,1672],{"class":103}," 1_000\n",[37,1674,1675,1678,1681,1684],{"class":39,"line":235},[37,1676,1677],{"class":43},"    :",[37,1679,1680],{"class":47}," Number.",[37,1682,1683],{"class":83},"isNaN",[37,1685,1686],{"class":47},"(date)\n",[37,1688,1689,1692,1694,1696,1698,1700],{"class":39,"line":247},[37,1690,1691],{"class":43},"      ?",[37,1693,209],{"class":47},[37,1695,212],{"class":83},[37,1697,1658],{"class":47},[37,1699,934],{"class":43},[37,1701,1702],{"class":103}," 60_000\n",[37,1704,1705,1708],{"class":39,"line":264},[37,1706,1707],{"class":43},"      :",[37,1709,1710],{"class":47}," date;\n",[37,1712,1713,1716,1718,1720],{"class":39,"line":271},[37,1714,1715],{"class":43},"  await",[37,1717,926],{"class":47},[37,1719,671],{"class":83},[37,1721,1722],{"class":47},"({ retryAt });\n",[37,1724,1725,1728,1730,1732,1734,1737],{"class":39,"line":305},[37,1726,1727],{"class":43},"  throw",[37,1729,1285],{"class":43},[37,1731,1288],{"class":83},[37,1733,141],{"class":47},[37,1735,1736],{"class":60},"'rate limited'",[37,1738,951],{"class":47},[37,1740,1741],{"class":39,"line":311},[37,1742,320],{"class":47},[15,1744,1745,1746,1749,1750,1752,1753,1756,1757,21,1759,1761,1762,1765,1766,21,1769,1771,1772,1774,1775,1777,1778,1752,1780,1782,1783,1785,1786,1788,1789,1791,1792,1794,1795,1797],{},"Even if you specify ",[19,1747,1748],{},"retryAt",", that attempt still counts toward the attempt count.",[327,1751],{},"\nIf ",[19,1754,1755],{},"maxAttempts"," has been reached, the job moves to ",[19,1758,1353],{},[327,1760],{},"\nIf the specified time is later than the deadline (",[19,1763,1764],{},"expiresAt","), the job moves to ",[19,1767,1768],{},"CANCELLED",[327,1770],{},"\nIf you specify a time in the past, the job becomes eligible for retry immediately.",[327,1773],{},"\nThe settings passed to ",[19,1776,1339],{}," apply only to an attempt that ends with a throw.",[327,1779],{},[19,1781,556],{}," finishes without throwing, the job completes even if ",[19,1784,1339],{}," was called.",[327,1787],{},"\nIf you call ",[19,1790,1339],{}," more than once in a single attempt, the last call takes effect.",[327,1793],{},"\nIf you pass a value in an invalid format to ",[19,1796,1339],{},", that call throws an exception.",[23,1799,1801],{"id":1800},"キーの必須化","Requiring keys",[15,1803,1804,1805,1808,1809,1812],{},"For a performer whose third type argument is ",[19,1806,1807],{},"{ concurrencyKey: true }"," or ",[19,1810,1811],{},"{ uniqueKey: true }",", the key must be specified when the job is enqueued.",[28,1814,1816],{"className":30,"code":1815,"language":32,"meta":33,"style":33},"class ChargeCard extends Performer\u003CPayload, void, { concurrencyKey: true }, Env> {}\n",[19,1817,1818],{"__ignoreMap":33},[37,1819,1820,1822,1824,1826,1828,1830,1833,1835,1837,1839,1841,1843,1845,1847,1849],{"class":39,"line":40},[37,1821,804],{"class":43},[37,1823,1152],{"class":83},[37,1825,87],{"class":43},[37,1827,90],{"class":83},[37,1829,184],{"class":47},[37,1831,1832],{"class":83},"Payload",[37,1834,890],{"class":47},[37,1836,120],{"class":103},[37,1838,1182],{"class":47},[37,1840,1185],{"class":96},[37,1842,100],{"class":43},[37,1844,1190],{"class":103},[37,1846,117],{"class":47},[37,1848,126],{"class":83},[37,1850,1851],{"class":47},"> {}\n",[15,1853,1854,1855,1857,1858,1860,1861,1125,1864,1867],{},"The key is passed as a string when the job is enqueued.",[327,1856],{},"\nTsumugi does not provide a mechanism for defining a function on the performer side that derives the key.",[327,1859],{},"\nWith ",[19,1862,1863],{},"tsumugi.enqueue",[19,1865,1866],{},"tsumugi.jobs(env)",", omitting the key causes a compile-time error.",[28,1869,1871],{"className":30,"code":1870,"language":32,"meta":33,"style":33},"await tsumugi.enqueue(env, { binding: 'CHARGE', payload, concurrencyKey: 'customer:c1' });\nawait tsumugi.jobs(env).enqueue('CHARGE', payload, { concurrencyKey: 'customer:c1' });\n",[19,1872,1873,1897],{"__ignoreMap":33},[37,1874,1875,1877,1880,1883,1886,1889,1892,1895],{"class":39,"line":40},[37,1876,1019],{"class":43},[37,1878,1879],{"class":47}," tsumugi.",[37,1881,1882],{"class":83},"enqueue",[37,1884,1885],{"class":47},"(env, { binding: ",[37,1887,1888],{"class":60},"'CHARGE'",[37,1890,1891],{"class":47},", payload, concurrencyKey: ",[37,1893,1894],{"class":60},"'customer:c1'",[37,1896,465],{"class":47},[37,1898,1899,1901,1903,1906,1909,1911,1913,1915,1918,1920],{"class":39,"line":67},[37,1900,1019],{"class":43},[37,1902,1879],{"class":47},[37,1904,1905],{"class":83},"jobs",[37,1907,1908],{"class":47},"(env).",[37,1910,1882],{"class":83},[37,1912,141],{"class":47},[37,1914,1888],{"class":60},[37,1916,1917],{"class":47},", payload, { concurrencyKey: ",[37,1919,1894],{"class":60},[37,1921,465],{"class":47},[1923,1924,1926],"callout",{"type":1925},"warning",[15,1927,1928,1929,21,1932,1934,1935,21],{},"The key requirement is not enforced for ",[19,1930,1931],{},"createClient()",[327,1933],{},"\nFor details, see ",[1000,1936,1938],{"href":1937},"\u002Fen\u002Fguide\u002Fenqueue#%E6%8A%95%E5%85%A5%E6%96%B9%E6%B3%95","How to enqueue",[23,1940,1942],{"id":1941},"別workerへの配置","Placing a performer in a separate Worker",[15,1944,1945],{},"A performer is executed by Tsumugi even when it is placed in a separate Worker connected through a Service Binding.",[28,1947,1949],{"className":30,"code":1948,"language":32,"meta":33,"style":33},"\u002F\u002F Worker that hosts the performer\nimport { Performer, type JobContext } from 'tsumugi\u002Fperformer';\n\nexport class SendMail extends Performer\u003C{ to: string; subject: string }, void, {}, Env> {\n  async perform(payload: { to: string; subject: string }, ctx: JobContext): Promise\u003Cvoid> {\n    \u002F\u002F ...\n  }\n}\n\n\u002F\u002F A default export is required in addition to the named export of the WorkerEntrypoint\nexport default {\n  async fetch(): Promise\u003CResponse> {\n    return new Response('performer only', { status: 404 });\n  },\n} satisfies ExportedHandler\u003CEnv>;\n",[19,1950,1951,1956,1972,1976,2014,2062,2067,2071,2075,2079,2084,2094,2114,2137,2143],{"__ignoreMap":33},[37,1952,1953],{"class":39,"line":40},[37,1954,1955],{"class":267},"\u002F\u002F Worker that hosts the performer\n",[37,1957,1958,1960,1962,1964,1966,1968,1970],{"class":39,"line":67},[37,1959,44],{"class":43},[37,1961,48],{"class":47},[37,1963,51],{"class":43},[37,1965,54],{"class":47},[37,1967,57],{"class":43},[37,1969,61],{"class":60},[37,1971,64],{"class":47},[37,1973,1974],{"class":39,"line":74},[37,1975,71],{"emptyLinePlaceholder":70},[37,1977,1978,1980,1982,1984,1986,1988,1990,1992,1994,1996,1998,2000,2002,2004,2006,2008,2010,2012],{"class":39,"line":132},[37,1979,77],{"class":43},[37,1981,80],{"class":43},[37,1983,84],{"class":83},[37,1985,87],{"class":43},[37,1987,90],{"class":83},[37,1989,93],{"class":47},[37,1991,97],{"class":96},[37,1993,100],{"class":43},[37,1995,104],{"class":103},[37,1997,107],{"class":47},[37,1999,110],{"class":96},[37,2001,100],{"class":43},[37,2003,104],{"class":103},[37,2005,117],{"class":47},[37,2007,120],{"class":103},[37,2009,123],{"class":47},[37,2011,126],{"class":83},[37,2013,129],{"class":47},[37,2015,2016,2018,2020,2022,2024,2026,2028,2030,2032,2034,2036,2038,2040,2042,2044,2046,2048,2050,2052,2054,2056,2058,2060],{"class":39,"line":191},[37,2017,135],{"class":43},[37,2019,138],{"class":83},[37,2021,141],{"class":47},[37,2023,144],{"class":96},[37,2025,100],{"class":43},[37,2027,149],{"class":47},[37,2029,97],{"class":96},[37,2031,100],{"class":43},[37,2033,104],{"class":103},[37,2035,107],{"class":47},[37,2037,110],{"class":96},[37,2039,100],{"class":43},[37,2041,104],{"class":103},[37,2043,117],{"class":47},[37,2045,168],{"class":96},[37,2047,100],{"class":43},[37,2049,173],{"class":83},[37,2051,176],{"class":47},[37,2053,100],{"class":43},[37,2055,181],{"class":83},[37,2057,184],{"class":47},[37,2059,120],{"class":103},[37,2061,129],{"class":47},[37,2063,2064],{"class":39,"line":218},[37,2065,2066],{"class":267},"    \u002F\u002F ...\n",[37,2068,2069],{"class":39,"line":235},[37,2070,314],{"class":47},[37,2072,2073],{"class":39,"line":247},[37,2074,320],{"class":47},[37,2076,2077],{"class":39,"line":264},[37,2078,71],{"emptyLinePlaceholder":70},[37,2080,2081],{"class":39,"line":271},[37,2082,2083],{"class":267},"\u002F\u002F A default export is required in addition to the named export of the WorkerEntrypoint\n",[37,2085,2086,2088,2091],{"class":39,"line":305},[37,2087,77],{"class":43},[37,2089,2090],{"class":43}," default",[37,2092,2093],{"class":47}," {\n",[37,2095,2096,2098,2100,2103,2105,2107,2109,2112],{"class":39,"line":311},[37,2097,135],{"class":43},[37,2099,224],{"class":83},[37,2101,2102],{"class":47},"()",[37,2104,100],{"class":43},[37,2106,181],{"class":83},[37,2108,184],{"class":47},[37,2110,2111],{"class":83},"Response",[37,2113,129],{"class":47},[37,2115,2116,2119,2121,2124,2126,2129,2132,2135],{"class":39,"line":317},[37,2117,2118],{"class":43},"    return",[37,2120,1285],{"class":43},[37,2122,2123],{"class":83}," Response",[37,2125,141],{"class":47},[37,2127,2128],{"class":60},"'performer only'",[37,2130,2131],{"class":47},", { status: ",[37,2133,2134],{"class":103},"404",[37,2136,465],{"class":47},[37,2138,2140],{"class":39,"line":2139},14,[37,2141,2142],{"class":47},"  },\n",[37,2144,2146,2149,2152,2155,2157,2159],{"class":39,"line":2145},15,[37,2147,2148],{"class":47},"} ",[37,2150,2151],{"class":43},"satisfies",[37,2153,2154],{"class":83}," ExportedHandler",[37,2156,184],{"class":47},[37,2158,126],{"class":83},[37,2160,2161],{"class":47},">;\n",[15,2163,2164],{},"In the caller's wrangler.jsonc, you must configure a Service Binding that maps the binding name to the entrypoint.",[28,2166,2170],{"className":2167,"code":2168,"language":2169,"meta":33,"style":33},"language-jsonc shiki shiki-themes github-light github-dark","\"services\": [\n  { \"binding\": \"MAIL\", \"service\": \"my-mailer\", \"entrypoint\": \"SendMail\" },\n],\n","jsonc",[19,2171,2172,2180,2217],{"__ignoreMap":33},[37,2173,2174,2177],{"class":39,"line":40},[37,2175,2176],{"class":60},"\"services\"",[37,2178,2179],{"class":47},": [\n",[37,2181,2182,2185,2188,2191,2194,2196,2199,2201,2204,2206,2209,2211,2214],{"class":39,"line":67},[37,2183,2184],{"class":47},"  { ",[37,2186,2187],{"class":103},"\"binding\"",[37,2189,2190],{"class":47},": ",[37,2192,2193],{"class":60},"\"MAIL\"",[37,2195,890],{"class":47},[37,2197,2198],{"class":103},"\"service\"",[37,2200,2190],{"class":47},[37,2202,2203],{"class":60},"\"my-mailer\"",[37,2205,890],{"class":47},[37,2207,2208],{"class":103},"\"entrypoint\"",[37,2210,2190],{"class":47},[37,2212,2213],{"class":60},"\"SendMail\"",[37,2215,2216],{"class":47}," },\n",[37,2218,2219],{"class":39,"line":74},[37,2220,2221],{"class":47},"],\n",[15,2223,2224,2225,2227,2228,2231,2232,2234,2235,2237],{},"In the caller's ",[19,2226,381],{},", specify ",[19,2229,2230],{},"remote()"," instead of the class.",[327,2233],{},"\nA single ",[19,2236,381],{}," can also mix performers from the same Worker with performers from a separate Worker.",[28,2239,2241],{"className":30,"code":2240,"language":32,"meta":33,"style":33},"import { remote } from 'tsumugi';\nimport type { SendMail } from 'my-mailer';\n\nconst performers = { ...local, MAIL: remote\u003CSendMail>() };\n",[19,2242,2243,2257,2273,2277],{"__ignoreMap":33},[37,2244,2245,2247,2250,2252,2255],{"class":39,"line":40},[37,2246,44],{"class":43},[37,2248,2249],{"class":47}," { remote } ",[37,2251,57],{"class":43},[37,2253,2254],{"class":60}," 'tsumugi'",[37,2256,64],{"class":47},[37,2258,2259,2261,2264,2266,2268,2271],{"class":39,"line":67},[37,2260,44],{"class":43},[37,2262,2263],{"class":43}," type",[37,2265,368],{"class":47},[37,2267,57],{"class":43},[37,2269,2270],{"class":60}," 'my-mailer'",[37,2272,64],{"class":47},[37,2274,2275],{"class":39,"line":74},[37,2276,71],{"emptyLinePlaceholder":70},[37,2278,2279,2281,2284,2286,2288,2291,2294,2297,2299,2301],{"class":39,"line":132},[37,2280,448],{"class":43},[37,2282,2283],{"class":103}," performers",[37,2285,200],{"class":43},[37,2287,149],{"class":47},[37,2289,2290],{"class":43},"...",[37,2292,2293],{"class":47},"local, MAIL: ",[37,2295,2296],{"class":83},"remote",[37,2298,184],{"class":47},[37,2300,350],{"class":83},[37,2302,2303],{"class":47},">() };\n",[689,2305,2307],{"id":2306},"別workerに配置した場合の制約","Constraints when placed in a separate Worker",[15,2309,2310,2311,1125,2314,2317,2318,21,2320,1752,2322,2324,2325,2327,2328,2330,2331,2333],{},"For a performer placed in a separate Worker, calls to ",[19,2312,2313],{},"ctx.spawn",[19,2315,2316],{},"ctx.fail"," require ",[19,2319,1019],{},[327,2321],{},[19,2323,556],{}," finishes without awaiting ",[19,2326,2313],{},", the addition of the child node is not applied.",[327,2329],{},"\nIf you throw an exception without awaiting ",[19,2332,2316],{},", the specification may not be applied either.",[28,2335,2337],{"className":30,"code":2336,"language":32,"meta":33,"style":33},"await ctx.spawn('child', 'MAIL', payload);\n",[19,2338,2339],{"__ignoreMap":33},[37,2340,2341,2343,2345,2347,2349,2352,2354,2357],{"class":39,"line":40},[37,2342,1019],{"class":43},[37,2344,926],{"class":47},[37,2346,661],{"class":83},[37,2348,141],{"class":47},[37,2350,2351],{"class":60},"'child'",[37,2353,890],{"class":47},[37,2355,2356],{"class":60},"'MAIL'",[37,2358,2359],{"class":47},", payload);\n",[15,2361,2362,2363,2365,2366,2368,2369,2371,2372,2374],{},"A child node added with ",[19,2364,661],{}," is created after ",[19,2367,556],{}," completes.",[327,2370],{},"\nThe child node does not run at the time ",[19,2373,661],{}," is called.",[23,2376,2378],{"id":2377},"テスト","Testing",[15,2380,2381,382,2384,2387,2388,2390,2391,2393,2394,890,2397,21],{},[19,2382,2383],{},"runPerformer",[19,2385,2386],{},"tsumugi\u002Ftesting"," calls a performer directly without enqueuing a job.",[327,2389],{},"\nThe ",[19,2392,6],{}," constructor takes the same two arguments as ",[19,2395,2396],{},"WorkerEntrypoint",[19,2398,2399],{},"(ctx, env)",[28,2401,2403],{"className":30,"code":2402,"language":32,"meta":33,"style":33},"import { createTestContext, runPerformer } from 'tsumugi\u002Ftesting';\n\ndeclare const ctx: ExecutionContext;\ndeclare const env: Env;\n\nconst result = await runPerformer(new SendWelcome(ctx, env), { userId: 'u_1' });\n\nif (result.ok) console.log(result.value);\nelse console.error(result.error);\n",[19,2404,2405,2419,2423,2441,2457,2461,2491,2495,2507],{"__ignoreMap":33},[37,2406,2407,2409,2412,2414,2417],{"class":39,"line":40},[37,2408,44],{"class":43},[37,2410,2411],{"class":47}," { createTestContext, runPerformer } ",[37,2413,57],{"class":43},[37,2415,2416],{"class":60}," 'tsumugi\u002Ftesting'",[37,2418,64],{"class":47},[37,2420,2421],{"class":39,"line":67},[37,2422,71],{"emptyLinePlaceholder":70},[37,2424,2425,2428,2431,2434,2436,2439],{"class":39,"line":74},[37,2426,2427],{"class":43},"declare",[37,2429,2430],{"class":43}," const",[37,2432,2433],{"class":103}," ctx",[37,2435,100],{"class":43},[37,2437,2438],{"class":83}," ExecutionContext",[37,2440,64],{"class":47},[37,2442,2443,2445,2447,2450,2452,2455],{"class":39,"line":132},[37,2444,2427],{"class":43},[37,2446,2430],{"class":43},[37,2448,2449],{"class":103}," env",[37,2451,100],{"class":43},[37,2453,2454],{"class":83}," Env",[37,2456,64],{"class":47},[37,2458,2459],{"class":39,"line":191},[37,2460,71],{"emptyLinePlaceholder":70},[37,2462,2463,2465,2468,2470,2472,2475,2477,2480,2483,2486,2489],{"class":39,"line":218},[37,2464,448],{"class":43},[37,2466,2467],{"class":103}," result",[37,2469,200],{"class":43},[37,2471,1249],{"class":43},[37,2473,2474],{"class":83}," runPerformer",[37,2476,141],{"class":47},[37,2478,2479],{"class":43},"new",[37,2481,2482],{"class":83}," SendWelcome",[37,2484,2485],{"class":47},"(ctx, env), { userId: ",[37,2487,2488],{"class":60},"'u_1'",[37,2490,465],{"class":47},[37,2492,2493],{"class":39,"line":235},[37,2494,71],{"emptyLinePlaceholder":70},[37,2496,2497,2499,2502,2504],{"class":39,"line":247},[37,2498,1553],{"class":43},[37,2500,2501],{"class":47}," (result.ok) console.",[37,2503,637],{"class":83},[37,2505,2506],{"class":47},"(result.value);\n",[37,2508,2509,2512,2515,2518],{"class":39,"line":264},[37,2510,2511],{"class":43},"else",[37,2513,2514],{"class":47}," console.",[37,2516,2517],{"class":83},"error",[37,2519,2520],{"class":47},"(result.error);\n",[15,2522,2523,2524,890,2526,2528,2529,21,2531,2533,2535,2536,2538,2539,2542,2543,382,2545,2548],{},"For a performer that does not use ",[19,2525,332],{},[19,2527,2383],{}," also accepts a plain object that has ",[19,2530,556],{},[327,2532],{},[19,2534,2383],{}," does not rethrow exceptions, and it returns a result in the same shape for both success and failure.",[327,2537],{},"\nThe context returned by ",[19,2540,2541],{},"createTestContext()"," records the settings passed to ",[19,2544,1339],{},[19,2546,2547],{},"fails",", in the order of the calls.",[689,2550,2552],{"id":2551},"実行コンテキストの差し替え","Replacing the execution context",[15,2554,2555,2556,2559,2560,21,2562,2564],{},"By passing values to ",[19,2557,2558],{},"createTestContext",", you can override fields of the execution context passed to ",[19,2561,2383],{},[327,2563],{},"\nThe following example sets the attempt number to 3.",[28,2566,2568],{"className":30,"code":2567,"language":32,"meta":33,"style":33},"const ctx = createTestContext({ attempt: 3 });\nawait runPerformer(performer, payload, ctx);\n",[19,2569,2570,2589],{"__ignoreMap":33},[37,2571,2572,2574,2576,2578,2581,2584,2587],{"class":39,"line":40},[37,2573,448],{"class":43},[37,2575,2433],{"class":103},[37,2577,200],{"class":43},[37,2579,2580],{"class":83}," createTestContext",[37,2582,2583],{"class":47},"({ attempt: ",[37,2585,2586],{"class":103},"3",[37,2588,465],{"class":47},[37,2590,2591,2593,2595],{"class":39,"line":67},[37,2592,1019],{"class":43},[37,2594,2474],{"class":83},[37,2596,2597],{"class":47},"(performer, payload, ctx);\n",[15,2599,2600,2601,21],{},"To verify how a performer behaves with respect to the deadline, specify a time in the past or in the near future for ",[19,2602,617],{},[28,2604,2606],{"className":30,"code":2605,"language":32,"meta":33,"style":33},"const ctx = createTestContext({ deadlineAt: Date.now() + 50 });\nawait runPerformer(performer, payload, ctx);\n",[19,2607,2608,2632],{"__ignoreMap":33},[37,2609,2610,2612,2614,2616,2618,2621,2623,2625,2627,2630],{"class":39,"line":40},[37,2611,448],{"class":43},[37,2613,2433],{"class":103},[37,2615,200],{"class":43},[37,2617,2580],{"class":83},[37,2619,2620],{"class":47},"({ deadlineAt: Date.",[37,2622,212],{"class":83},[37,2624,1658],{"class":47},[37,2626,934],{"class":43},[37,2628,2629],{"class":103}," 50",[37,2631,465],{"class":47},[37,2633,2634,2636,2638],{"class":39,"line":67},[37,2635,1019],{"class":43},[37,2637,2474],{"class":83},[37,2639,2597],{"class":47},[689,2641,2643],{"id":2642},"投入から実行までのテスト","Testing from enqueue to execution",[15,2645,2646,2647,21,2650,2652,2654],{},"To verify the whole flow from enqueuing a job to executing it, use ",[19,2648,2649],{},"@cloudflare\u002Fvitest-pool-workers",[327,2651],{},[19,2653,2386],{}," is not intended for tests at this scope.",[2656,2657,2658],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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":33,"searchDepth":74,"depth":74,"links":2660},[2661,2662,2663,2669,2672,2673,2676],{"id":25,"depth":67,"text":26},{"id":336,"depth":67,"text":337},{"id":549,"depth":67,"text":550,"children":2664},[2665,2666,2667,2668],{"id":691,"depth":74,"text":692},{"id":627,"depth":74,"text":627},{"id":1006,"depth":74,"text":1007},{"id":1092,"depth":74,"text":1093},{"id":1133,"depth":67,"text":1134,"children":2670},[2671],{"id":1332,"depth":74,"text":1333},{"id":1800,"depth":67,"text":1801},{"id":1941,"depth":67,"text":1942,"children":2674},[2675],{"id":2306,"depth":74,"text":2307},{"id":2377,"depth":67,"text":2378,"children":2677},[2678,2679],{"id":2551,"depth":74,"text":2552},{"id":2642,"depth":74,"text":2643},"The execution context of a Performer, which defines how a job is processed, plus failures and retries, placement in a separate Worker, and testing","md",{},"\u002Fen\u002Fguide\u002Fperformer","2026-07-22",{"title":6,"description":2680},"en\u002Fguide\u002Fperformer","2026-10-25","tVmd7_Bswa4sk8eskq4XzxBEzk3SBqTDVi0YJP4HXgs",false,1794027574652]