{"version":1,"lectureId":"01M1DABYJK6ZWC90PVPVTQ9420","attempt":0,"publication":{"slug":"understanding-activity-and-workflow-task-event-histories-in-temporal","title":"Understanding Activity and Workflow Task Event Histories in Temporal","subject":"computer-science","summary":"Every event in a Temporal history is named after the state of the task it belongs to. Remove the leading ActivityTask or WorkflowTask from the name and what remains is Scheduled, Started, Completed, Failed or TimedOut: three steps of one lifecycle, in a fixed order. This lecture lays that lifecycle out, shows why a worker is the party that reports completion and failure while the Temporal cluster is the party that declares a timeout, and reads the Start-To-Close timeout straight off the picture as the window between step two and step three. The same reading then transfers to workflow task events, so an event history in the Web UI can be interpreted rather than decoded.","metaDescription":"Strip the prefix from a Temporal event name and it names the task state: the lifecycle, the closed states, and the Start-To-Close window.","transcript":"Open an event history in the Temporal Web UI and the names are long. Activity Task Scheduled. Activity Task Started. Activity Task Completed. There is a pattern in them, and it is worth a couple of minutes of your attention. Every activity event begins with the same two words. Cross those off, and what is left is a state: Scheduled, in this case. That is the whole convention. It is not a coincidence and it is not occasional. Every activity event in the history is named this way. So here are the five you will meet. Scheduled and Started at the top, then the three ways a task can end: Completed, Failed, and Timed Out. Five names, five states. And those five states are not five separate ideas. They are three steps in one lifecycle, so the next thing to do is lay that lifecycle out. Those five states are three steps, and an activity task always takes them in the same order. Step one is Scheduled: the Temporal cluster has put the task on a task queue. Nothing of yours has run yet. Step two is Started. A worker has polled that queue, taken the task off it, and begun executing your activity code. Step three is a closed state, and there are three of those. Completed, when the worker ran your code all the way through and returned a value. Failed, when running your code produced an error instead. And Timed Out, when the time allowed ran out before any result came back. So Scheduled is always first, Started is always second, and one of those three is always last. Anything else you see between them in the history belongs to the workflow, not to this task. Once you can see those three steps, the timeout names stop being jargon. Take the one called Start To Close. Its first half names step two, the moment the worker began. Its second half names step three, whichever of those closed states the task reaches. So the timeout is the longest gap allowed between those two moments, and nothing else. A Start To Close of ten seconds says exactly this: once a worker picks the task up, it has ten seconds to finish, to fail, or to be declared timed out. Read another one the same way. Schedule To Start spans step one to step two: how long the task may sit on the queue before a worker picks it up. Every timeout in Temporal is named this way: two points of that lifecycle, and the stretch of time between them. Now, which of those three closed states a task lands in is decided by two different parties, and the split between them is not arbitrary. Completed and Failed are the worker's call, and that is because the worker is the thing actually running your code. If your activity function returns a value, the worker reports the task as Completed. If it raises an error instead, the worker reports Failed. Same worker, same process, one difference in what your code did. Timed Out is the odd one out. That decision comes from the Temporal cluster, and not from the worker at all. So why is the cluster the one that decides a timeout? Think about what a timeout usually means in a distributed system. Here is the ordinary case. A worker has taken the task and started running your code, and the cluster is waiting for it to report the result back. Now the worker process dies. It cannot finish the task, so no Completed event is coming. It cannot hand you an error, so no Failed event is coming either. It cannot report anything at all. The only party left that can notice is the cluster. It knows when it handed the task out and how long the task was allowed, so when that time is up with nothing received, the cluster writes the timed out event itself. And that is the whole responsibility model. The worker decides Completed or Failed, because it is the only one that watched your code run. The cluster decides Timed Out, because it is the only one still there to notice. One more thing, and it is the reason any of this is worth learning. The same pattern runs straight through workflow task events. Here are the activity events again, with the state beside each one. And here are the workflow task events. Scheduled, when the cluster puts a workflow task on a queue. Started, when a worker picks it up and runs your workflow code. Then Completed, when the worker is done with it. Failed, when the code raised. And Timed Out, when the cluster stopped waiting. Two different kinds of task, one vocabulary. The state column is the same on both sides, and so is the division of labour: the worker reports completion or failure, and the cluster declares the timeout. So there is nothing here to memorize. Read the suffix on an event, and it tells you where that task had got to. Read the pair of names in a timeout, and it tells you which stretch of that lifecycle the clock was watching.","watch":{"version":1,"scenes":[{"title":"Reading the Event Names","start":0,"end":59.306354166666665,"objects":{"head":"a Heading that says \"Reading the Event Names\"","name":"a Math [text] that says \"$upright(\"ActivityTask\") upright(\"Scheduled\")$\"","names":"a Table [text] that says \"Event in the history What is left ActivityTaskScheduled Scheduled ActivityTaskStarted Started ActivityTaskCompleted Completed ActivityTaskFailed Failed ActivityTaskTimedOut TimedOut\" (rows=(('Event in the history', 'What is left'), ('ActivityTaskSchedu…, header=True)","rule":"a Panel that says \"Drop the leading $upright(\"ActivityTask\")$ from an activity event name. What is left is the state that task was in when the event was written.\""},"beats":[{"start":0,"say":"Open an event history in the Temporal Web UI and the names are long. Activity Task Scheduled. Activity Task Started. Activity Task Completed. There is a pattern in them, and it is worth a couple of minutes of your attention.","live":[],"does":[[0,"head is shown on the screen, written out."],[5.48,"name is shown on the screen, written out."]]},{"start":15.7045,"say":"Every activity event begins with the same two words. Cross those off, and what is left is a state: Scheduled, in this case.","live":["name","head"],"does":[[19.686999999999998,"name (the \"upright(\"ActivityTask\")\" part) is struck through — it is ruled out."],[22.694000000000003,"name (the \"upright(\"Scheduled\")\" part) is emphasized."]]},{"start":25.198,"say":"That is the whole convention. It is not a coincidence and it is not occasional. Every activity event in the history is named this way.","live":null,"does":[[25.198,"name (the \"upright(\"Scheduled\")\" part) is no longer emphasized."],[26.556,"rule is shown on the screen, written out."],[34.6715,"name is hidden from the screen — left the board."],[34.6715,"rule is hidden from the screen — left the board."]]},{"start":35.2715,"say":"So here are the five you will meet. Scheduled and Started at the top, then the three ways a task can end: Completed, Failed, and Timed Out.","live":["head"],"does":[[35.2715,"names is shown on the screen, written out."],[38.05800000000001,"names is shown on the screen, written out."],[38.66100000000001,"names is shown on the screen, written out."],[43.178000000000004,"names is shown on the screen, written out."],[44.246,"names is shown on the screen, written out."],[45.151,"names is shown on the screen, written out."]]},{"start":46.80800000000001,"say":"Five names, five states. And those five states are not five separate ideas. They are three steps in one lifecycle, so the next thing to do is lay that lifecycle out.","live":null,"does":[[48.21300000000001,"names (the \"column=2\" part) is emphasized."],[53.75000000000001,"names (the \"column=2\" part) is no longer emphasized."],[58.26468750000001,"head is hidden from the screen — left the board."],[58.26468750000001,"names is hidden from the screen — left the board."]]}]},{"title":"Three Steps, and the Window Between Them","start":59.306354166666665,"end":168.65925000000004,"objects":{"actor_cluster":"a Math [gray] that says \"$upright(\"cluster\")$\" drawn in diagram","actor_worker":"a Math [gray] that says \"$upright(\"worker\")$\" drawn in diagram","arrow_completed":"a Vector [green] drawn in diagram (start=(7.4, 3.5), end=(8.5, 5.0))","arrow_dequeue":"a Vector [yellow] drawn in diagram (start=(3.45, 3.3), end=(4.3, 3.3))","arrow_failed":"a Vector [red] drawn in diagram (start=(7.4, 3.3), end=(8.5, 3.3))","arrow_timed_out":"a Vector [magenta] drawn in diagram (start=(7.4, 3.1), end=(8.5, 1.6))","box_completed":"a Polygon [green] drawn in diagram (vertices=((8.7, 4.7), (11.5, 4.7), (11.5, 5.7), (8.7, 5.7)), fill_opacity=0.18)","box_failed":"a Polygon [red] drawn in diagram (vertices=((8.7, 2.8), (11.5, 2.8), (11.5, 3.8), (8.7, 3.8)), fill_opacity=0.18)","box_scheduled":"a Polygon [blue] drawn in diagram (vertices=((0.5, 2.8), (3.3, 2.8), (3.3, 3.8), (0.5, 3.8)), fill_opacity=0.18)","box_started":"a Polygon [yellow] drawn in diagram (vertices=((4.4, 2.8), (7.2, 2.8), (7.2, 3.8), (4.4, 3.8)), fill_opacity=0.18)","box_timed_out":"a Polygon [magenta] drawn in diagram (vertices=((8.7, 0.9), (11.5, 0.9), (11.5, 1.9), (8.7, 1.9)), fill_opacity=0.18)","diagram":"a Figure (x_range=(0.0, 12.0), y_range=(0.0, 7.0), aspect=(12.0, 7.0))","drop_closed":"a Line [yellow] drawn in diagram (start=(10.1, 5.8), end=(10.1, 6.4), dashed=True)","drop_started":"a Line [yellow] drawn in diagram (start=(5.8, 3.9), end=(5.8, 6.4), dashed=True)","head":"a Heading that says \"Three Steps, and the Window Between Them\"","label_completed":"a Math [green] that says \"$upright(\"Completed\")$\" drawn in diagram","label_failed":"a Math [red] that says \"$upright(\"Failed\")$\" drawn in diagram","label_scheduled":"a Math [blue] that says \"$upright(\"Scheduled\")$\" drawn in diagram","label_started":"a Math [yellow] that says \"$upright(\"Started\")$\" drawn in diagram","label_timed_out":"a Math [magenta] that says \"$upright(\"TimedOut\")$\" drawn in diagram","span":"a Line [yellow] labelled \"upright(\"Start-To-Close\")\" drawn in diagram (start=(5.8, 6.4), end=(10.1, 6.4))","timeout_math":"a Math [text] that says \"$upright(\"Step 2\") arrow.r upright(\"Step 3\")$\"","timeout_note":"a Panel that says \"The longest time allowed between step two, when the worker begins executing the task, and step three, when the task reaches a closed state.\""},"beats":[{"start":59.306354166666665,"say":"Those five states are three steps, and an activity task always takes them in the same order. Step one is Scheduled: the Temporal cluster has put the task on a task queue. Nothing of yours has run yet.","live":[],"does":[[59.306354166666665,"head is shown on the screen, written out."],[59.306354166666665,"diagram is shown on the screen, written out."],[65.08835416666666,"box_scheduled is shown on the screen, written out."],[65.92435416666666,"label_scheduled is shown on the screen, written out."],[69.16335416666666,"actor_cluster is shown on the screen, written out."]]},{"start":72.58435416666667,"say":"Step two is Started. A worker has polled that queue, taken the task off it, and begun executing your activity code.","live":["diagram","head","box_scheduled","label_scheduled","actor_cluster"],"does":[[72.93235416666667,"box_started is shown on the screen, written out."],[73.96635416666666,"label_started is shown on the screen, written out."],[75.37035416666666,"actor_worker is shown on the screen, written out."],[77.00735416666666,"arrow_dequeue is shown on the screen, written out."]]},{"start":81.55485416666667,"say":"Step three is a closed state, and there are three of those. Completed, when the worker ran your code all the way through and returned a value.","live":["diagram","head","box_scheduled","label_scheduled","actor_cluster","box_started","label_started","actor_worker","arrow_dequeue"],"does":[[86.00135416666666,"box_completed is shown on the screen, written out."],[86.23449440321022,"label_completed is shown on the screen, written out."],[88.69535416666666,"arrow_completed is shown on the screen, written out."]]},{"start":91.21035416666666,"say":"Failed, when running your code produced an error instead. And Timed Out, when the time allowed ran out before any result came back.","live":["diagram","head","box_scheduled","label_scheduled","actor_cluster","box_started","label_started","actor_worker","arrow_dequeue","box_completed","label_completed","arrow_completed"],"does":[[91.55835416666667,"box_failed is shown on the screen, written out."],[91.88930343444909,"label_failed is shown on the screen, written out."],[93.78735416666667,"arrow_failed is shown on the screen, written out."],[95.78435416666666,"box_timed_out is shown on the screen, written out."],[96.01160312064155,"label_timed_out is shown on the screen, written out."],[98.58235416666666,"arrow_timed_out is shown on the screen, written out."]]},{"start":100.52985416666667,"say":"So Scheduled is always first, Started is always second, and one of those three is always last. Anything else you see between them in the history belongs to the workflow, not to this task.","live":["diagram","head","box_scheduled","label_scheduled","actor_cluster","box_started","label_started","actor_worker","arrow_dequeue","box_completed","label_completed","arrow_completed","box_failed","label_failed","arrow_failed","box_timed_out","label_timed_out","arrow_timed_out"],"does":[[102.12035416666666,"box_scheduled is indicated — a transient flash."],[103.59435416666668,"box_started is indicated — a transient flash."],[106.32235416666666,"box_completed is indicated — a transient flash."],[106.32235416666666,"box_failed is indicated — a transient flash."],[106.32235416666666,"box_timed_out is indicated — a transient flash."]]},{"start":113.01785416666667,"say":"Once you can see those three steps, the timeout names stop being jargon. Take the one called Start To Close. Its first half names step two, the moment the worker began.","live":null,"does":[[121.10935416666666,"diagram moves to a new place on the board."],[121.10935416666666,"timeout_math is shown on the screen, written out."],[122.14335416666667,"drop_started is shown on the screen, written out."]]},{"start":125.62235416666667,"say":"Its second half names step three, whichever of those closed states the task reaches. So the timeout is the longest gap allowed between those two moments, and nothing else.","live":["timeout_math","diagram","head","box_scheduled","label_scheduled","actor_cluster","box_started","label_started","actor_worker","arrow_dequeue","box_completed","label_completed","arrow_completed","box_failed","label_failed","arrow_failed","box_timed_out","label_timed_out","arrow_timed_out","drop_started"],"does":[[127.31735416666666,"drop_closed is shown on the screen, written out."],[132.58835416666668,"span is shown on the screen, written out."],[134.42335416666666,"timeout_note is shown on the screen, written out."]]},{"start":136.91535416666667,"say":"A Start To Close of ten seconds says exactly this: once a worker picks the task up, it has ten seconds to finish, to fail, or to be declared timed out.","live":["timeout_math","timeout_note","diagram","head","box_scheduled","label_scheduled","actor_cluster","box_started","label_started","actor_worker","arrow_dequeue","box_completed","label_completed","arrow_completed","box_failed","label_failed","arrow_failed","box_timed_out","label_timed_out","arrow_timed_out","drop_started","drop_closed","span"],"does":[[139.38835416666666,"span is indicated — a transient flash."]]},{"start":149.28785416666668,"say":"Read another one the same way. Schedule To Start spans step one to step two: how long the task may sit on the queue before a worker picks it up.","live":null,"does":[[153.53735416666666,"The segment (1.9, 2.55) to (5.8, 2.55) in diagram is lit up."],[159.96985416666666,"diagram: retire a lit segment (unemphasize_line)."]]},{"start":160.5698541666667,"say":"Every timeout in Temporal is named this way: two points of that lifecycle, and the stretch of time between them.","live":null,"does":[[163.80935416666665,"timeout_math is indicated — a transient flash."],[167.61758333333336,"diagram is hidden from the screen — left the board."],[167.61758333333336,"box_scheduled is hidden from the screen — diagram left the board."],[167.61758333333336,"label_scheduled is hidden from the screen — diagram left the board."],[167.61758333333336,"actor_cluster is hidden from the screen — diagram left the board."],[167.61758333333336,"box_started is hidden from the screen — diagram left the board."],[167.61758333333336,"label_started is hidden from the screen — diagram left the board."],[167.61758333333336,"actor_worker is hidden from the screen — diagram left the board."],[167.61758333333336,"arrow_dequeue is hidden from the screen — diagram left the board."],[167.61758333333336,"box_completed is hidden from the screen — diagram left the board."],[167.61758333333336,"label_completed is hidden from the screen — diagram left the board."],[167.61758333333336,"arrow_completed is hidden from the screen — diagram left the board."],[167.61758333333336,"box_failed is hidden from the screen — diagram left the board."],[167.61758333333336,"label_failed is hidden from the screen — diagram left the board."],[167.61758333333336,"arrow_failed is hidden from the screen — diagram left the board."],[167.61758333333336,"box_timed_out is hidden from the screen — diagram left the board."],[167.61758333333336,"label_timed_out is hidden from the screen — diagram left the board."],[167.61758333333336,"arrow_timed_out is hidden from the screen — diagram left the board."],[167.61758333333336,"drop_started is hidden from the screen — diagram left the board."],[167.61758333333336,"drop_closed is hidden from the screen — diagram left the board."],[167.61758333333336,"span is hidden from the screen — diagram left the board."],[167.61758333333336,"head is hidden from the screen — left the board."],[167.61758333333336,"timeout_math is hidden from the screen — left the board."],[167.61758333333336,"timeout_note is hidden from the screen — left the board."]]}]},{"title":"Who Decides How It Ends","start":168.65925000000004,"end":274.77377083333334,"objects":{"box_cluster":"a Polygon [blue] drawn in crash (vertices=((6.2, 3.9), (9.4, 3.9), (9.4, 5.1), (6.2, 5.1)), fill_opacity=0.18)","box_timed_out":"a Polygon [magenta] drawn in crash (vertices=((6.2, 1.0), (9.4, 1.0), (9.4, 2.2), (6.2, 2.2)), fill_opacity=0.18)","box_worker":"a Polygon [yellow] drawn in crash (vertices=((0.6, 3.9), (3.8, 3.9), (3.8, 5.1), (0.6, 5.1)), fill_opacity=0.18)","crash":"a Figure (x_range=(0.0, 10.0), y_range=(0.0, 6.0), aspect=(10.0, 6.0))","elapsed":"a Math [gray] that says \"$upright(\"time limit elapses\")$\" drawn in crash","fall":"a Vector [magenta] drawn in crash (start=(7.8, 3.8), end=(7.8, 2.4))","gash_1":"a Line [red] drawn in crash (start=(0.9, 4.1), end=(3.5, 4.9))","gash_2":"a Line [red] drawn in crash (start=(0.9, 4.9), end=(3.5, 4.1))","head":"a Heading that says \"Who Decides How It Ends\"","label_cluster":"a Math [blue] that says \"$upright(\"Cluster\")$\" drawn in crash","label_timed_out":"a Math [magenta] that says \"$upright(\"TimedOut\")$\" drawn in crash","label_worker":"a Math [yellow] that says \"$upright(\"Worker\")$\" drawn in crash","outcomes":"a Table [text] that says \"Closed state Decided by Why Completed the worker your code returned Failed the worker your code raised an error TimedOut the cluster no result arrived in time\" (rows=(('Closed state', 'Decided by', 'Why'), ('Completed', 'the work…, header=True)","report":"a Vector [green] labelled \"upright(\"result\")\" drawn in crash (start=(3.9, 4.5), end=(6.1, 4.5))"},"beats":[{"start":168.65925000000004,"say":"Now, which of those three closed states a task lands in is decided by two different parties, and the split between them is not arbitrary.","live":[],"does":[[168.65925000000004,"head is shown on the screen, written out."],[173.41925000000003,"outcomes is shown on the screen, written out."]]},{"start":177.82725000000005,"say":"Completed and Failed are the worker's call, and that is because the worker is the thing actually running your code. If your activity function returns a value, the worker reports the task as Completed.","live":["head"],"does":[[186.18725000000003,"outcomes is shown on the screen, written out."]]},{"start":190.80375000000004,"say":"If it raises an error instead, the worker reports Failed. Same worker, same process, one difference in what your code did.","live":null,"does":[[194.11325000000005,"outcomes is shown on the screen, written out."]]},{"start":200.85425000000004,"say":"Timed Out is the odd one out. That decision comes from the Temporal cluster, and not from the worker at all.","live":null,"does":[[201.15625000000006,"outcomes is shown on the screen, written out."],[206.17125000000004,"outcomes (the \"row=4\" part) is emphasized."],[208.91175000000004,"outcomes (the \"row=4\" part) is no longer emphasized."]]},{"start":209.51175000000003,"say":"So why is the cluster the one that decides a timeout? Think about what a timeout usually means in a distributed system.","live":null,"does":[[217.81225000000003,"outcomes is hidden from the screen — left the board."]]},{"start":218.41225000000003,"say":"Here is the ordinary case. A worker has taken the task and started running your code, and the cluster is waiting for it to report the result back.","live":null,"does":[[218.41225000000003,"crash is shown on the screen, written out."],[221.23325000000006,"box_worker is shown on the screen, written out."],[221.40483957501766,"label_worker is shown on the screen, written out."],[225.13425000000004,"box_cluster is shown on the screen, written out."],[225.32451473350557,"label_cluster is shown on the screen, written out."],[226.49225000000004,"report is shown on the screen, written out."]]},{"start":228.90425000000005,"say":"Now the worker process dies. It cannot finish the task, so no Completed event is coming. It cannot hand you an error, so no Failed event is coming either. It cannot report anything at all.","live":["head","crash","box_worker","label_worker","box_cluster","label_cluster","report"],"does":[[230.64525000000003,"gash_1 is shown on the screen, written out."],[231.20125922037613,"gash_2 is shown on the screen, written out."],[242.31325000000004,"report is hidden from the screen."]]},{"start":244.36525000000006,"say":"The only party left that can notice is the cluster. It knows when it handed the task out and how long the task was allowed, so when that time is up with nothing received, the cluster writes the timed out event itself.","live":["head","crash","box_worker","label_worker","box_cluster","label_cluster","gash_1","gash_2"],"does":[[253.11925000000005,"elapsed is shown on the screen, written out."],[255.90525000000002,"fall is shown on the screen, written out."],[256.12041076516084,"box_timed_out is shown on the screen, written out."],[256.49136016144354,"label_timed_out is shown on the screen, written out."]]},{"start":258.78075,"say":"And that is the whole responsibility model. The worker decides Completed or Failed, because it is the only one that watched your code run. The cluster decides Timed Out, because it is the only one still there to notice.","live":["head","crash","box_worker","label_worker","box_cluster","label_cluster","gash_1","gash_2","elapsed","fall","box_timed_out","label_timed_out"],"does":[[262.34525,"box_worker is indicated — a transient flash."],[268.74225,"box_cluster is indicated — a transient flash."],[273.7321041666667,"crash is hidden from the screen — left the board."],[273.7321041666667,"box_worker is hidden from the screen — crash left the board."],[273.7321041666667,"label_worker is hidden from the screen — crash left the board."],[273.7321041666667,"box_cluster is hidden from the screen — crash left the board."],[273.7321041666667,"label_cluster is hidden from the screen — crash left the board."],[273.7321041666667,"gash_1 is hidden from the screen — crash left the board."],[273.7321041666667,"gash_2 is hidden from the screen — crash left the board."],[273.7321041666667,"elapsed is hidden from the screen — crash left the board."],[273.7321041666667,"fall is hidden from the screen — crash left the board."],[273.7321041666667,"box_timed_out is hidden from the screen — crash left the board."],[273.7321041666667,"label_timed_out is hidden from the screen — crash left the board."],[273.7321041666667,"head is hidden from the screen — left the board."]]}]},{"title":"The Same Pattern for Workflow Tasks","start":274.77377083333334,"end":337.7111458333334,"objects":{"activity":"a Table [text] that says \"ActivityTaskScheduled Scheduled ActivityTaskStarted Started ActivityTaskCompleted Completed ActivityTaskFailed Failed ActivityTaskTimedOut TimedOut\" (rows=(('ActivityTaskScheduled', 'Scheduled'), ('ActivityTaskStarted'…)","head":"a Heading that says \"The Same Pattern for Workflow Tasks\"","label_left":"a Tex [text] that says \"Activity task events\"","label_right":"a Tex [text] that says \"Workflow task events\"","workflow":"a Table [text] that says \"WorkflowTaskScheduled Scheduled WorkflowTaskStarted Started WorkflowTaskCompleted Completed WorkflowTaskFailed Failed WorkflowTaskTimedOut TimedOut\" (rows=(('WorkflowTaskScheduled', 'Scheduled'), ('WorkflowTaskStarted'…)"},"beats":[{"start":274.77377083333334,"say":"One more thing, and it is the reason any of this is worth learning. The same pattern runs straight through workflow task events. Here are the activity events again, with the state beside each one.","live":[],"does":[[274.77377083333334,"head is shown on the screen, written out."],[283.52777083333336,"label_left is shown on the screen, written out."],[285.19977083333333,"activity is shown on the screen, written out."],[285.39962340529576,"activity is shown on the screen, written out."],[285.6128597906188,"activity is shown on the screen, written out."],[285.83468998354726,"activity is shown on the screen, written out."],[286.02577374102293,"activity is shown on the screen, written out."]]},{"start":287.40177083333333,"say":"And here are the workflow task events. Scheduled, when the cluster puts a workflow task on a queue. Started, when a worker picks it up and runs your workflow code.","live":["label_left","head"],"does":[[287.40177083333333,"label_right is shown on the screen, written out."],[290.7217708333333,"workflow is shown on the screen, written out."],[294.80877083333337,"workflow is shown on the screen, written out."]]},{"start":298.9382708333333,"say":"Then Completed, when the worker is done with it. Failed, when the code raised. And Timed Out, when the cluster stopped waiting.","live":["label_left","label_right","head"],"does":[[299.59977083333337,"workflow is shown on the screen, written out."],[302.65277083333336,"workflow is shown on the screen, written out."],[305.59077083333335,"workflow is shown on the screen, written out."]]},{"start":309.08077083333336,"say":"Two different kinds of task, one vocabulary. The state column is the same on both sides, and so is the division of labour: the worker reports completion or failure, and the cluster declares the timeout.","live":null,"does":[[314.37477083333334,"activity (the \"column=2\" part) is emphasized."],[314.37477083333334,"workflow (the \"column=2\" part) is emphasized."],[316.63877083333335,"activity (the \"column=2\" part) is no longer emphasized."],[316.63877083333335,"workflow (the \"column=2\" part) is no longer emphasized."]]},{"start":323.22977083333336,"say":"So there is nothing here to memorize. Read the suffix on an event, and it tells you where that task had got to. Read the pair of names in a timeout, and it tells you which stretch of that lifecycle the clock was watching.","live":null,"does":[[326.44577083333337,"activity (the \"column=2\" part) is indicated — a transient flash."],[326.44577083333337,"workflow (the \"column=2\" part) is indicated — a transient flash."],[336.6694791666667,"activity is hidden from the screen — left the board."],[336.6694791666667,"head is hidden from the screen — left the board."],[336.6694791666667,"label_left is hidden from the screen — left the board."],[336.6694791666667,"label_right is hidden from the screen — left the board."],[336.6694791666667,"workflow is hidden from the screen — left the board."]]}]}]},"durationSeconds":338,"chapters":[{"title":"Reading the Event Names","startSeconds":0,"narration":"Open an event history in the Temporal Web UI and the names are long. Activity Task Scheduled. Activity Task Started. Activity Task Completed. There is a pattern in them, and it is worth a couple of minutes of your attention. Every activity event begins with the same two words. Cross those off, and what is left is a state: Scheduled, in this case. That is the whole convention. It is not a coincidence and it is not occasional. Every activity event in the history is named this way. So here are the five you will meet. Scheduled and Started at the top, then the three ways a task can end: Completed, Failed, and Timed Out. Five names, five states. And those five states are not five separate ideas. They are three steps in one lifecycle, so the next thing to do is lay that lifecycle out."},{"title":"Three Steps, and the Window Between Them","startSeconds":59.306354166666665,"narration":"Those five states are three steps, and an activity task always takes them in the same order. Step one is Scheduled: the Temporal cluster has put the task on a task queue. Nothing of yours has run yet. Step two is Started. A worker has polled that queue, taken the task off it, and begun executing your activity code. Step three is a closed state, and there are three of those. Completed, when the worker ran your code all the way through and returned a value. Failed, when running your code produced an error instead. And Timed Out, when the time allowed ran out before any result came back. So Scheduled is always first, Started is always second, and one of those three is always last. Anything else you see between them in the history belongs to the workflow, not to this task. Once you can see those three steps, the timeout names stop being jargon. Take the one called Start To Close. Its first half names step two, the moment the worker began. Its second half names step three, whichever of those closed states the task reaches. So the timeout is the longest gap allowed between those two moments, and nothing else. A Start To Close of ten seconds says exactly this: once a worker picks the task up, it has ten seconds to finish, to fail, or to be declared timed out. Read another one the same way. Schedule To Start spans step one to step two: how long the task may sit on the queue before a worker picks it up. Every timeout in Temporal is named this way: two points of that lifecycle, and the stretch of time between them."},{"title":"Who Decides How It Ends","startSeconds":168.65925000000004,"narration":"Now, which of those three closed states a task lands in is decided by two different parties, and the split between them is not arbitrary. Completed and Failed are the worker's call, and that is because the worker is the thing actually running your code. If your activity function returns a value, the worker reports the task as Completed. If it raises an error instead, the worker reports Failed. Same worker, same process, one difference in what your code did. Timed Out is the odd one out. That decision comes from the Temporal cluster, and not from the worker at all. So why is the cluster the one that decides a timeout? Think about what a timeout usually means in a distributed system. Here is the ordinary case. A worker has taken the task and started running your code, and the cluster is waiting for it to report the result back. Now the worker process dies. It cannot finish the task, so no Completed event is coming. It cannot hand you an error, so no Failed event is coming either. It cannot report anything at all. The only party left that can notice is the cluster. It knows when it handed the task out and how long the task was allowed, so when that time is up with nothing received, the cluster writes the timed out event itself. And that is the whole responsibility model. The worker decides Completed or Failed, because it is the only one that watched your code run. The cluster decides Timed Out, because it is the only one still there to notice."},{"title":"The Same Pattern for Workflow Tasks","startSeconds":274.77377083333334,"narration":"One more thing, and it is the reason any of this is worth learning. The same pattern runs straight through workflow task events. Here are the activity events again, with the state beside each one. And here are the workflow task events. Scheduled, when the cluster puts a workflow task on a queue. Started, when a worker picks it up and runs your workflow code. Then Completed, when the worker is done with it. Failed, when the code raised. And Timed Out, when the cluster stopped waiting. Two different kinds of task, one vocabulary. The state column is the same on both sides, and so is the division of labour: the worker reports completion or failure, and the cluster declares the timeout. So there is nothing here to memorize. Read the suffix on an event, and it tells you where that task had got to. Read the pair of names in a timeout, and it tells you which stretch of that lifecycle the clock was watching."}]}}
