diff --git a/docs/cloud/get-started/certificates.mdx b/docs/cloud/get-started/certificates.mdx index 33fd961ed3..2d80f50015 100644 --- a/docs/cloud/get-started/certificates.mdx +++ b/docs/cloud/get-started/certificates.mdx @@ -30,7 +30,7 @@ private keys are used for verification. An expired root CA certificate invalidates all downstream certificates. -An expired end-entity certificate prevents a [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) from +An expired end-entity certificate prevents a [Temporal Client](/encyclopedia/temporal-client) from connecting to a Namespace or starting a Workflow Execution. If the client is on a Worker, any current Workflow Executions that are processed by that Worker either run indefinitely without making progress until the Worker resumes or fail because of timeouts. diff --git a/docs/develop/dotnet/client/temporal-client.mdx b/docs/develop/dotnet/client/temporal-client.mdx index 3ac3bfc119..1e35a78b1c 100644 --- a/docs/develop/dotnet/client/temporal-client.mdx +++ b/docs/develop/dotnet/client/temporal-client.mdx @@ -17,7 +17,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the Temporal Service. +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the Temporal Service. Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals and Queries to Workflow Executions, getting Workflow results, and more. diff --git a/docs/develop/go/client/temporal-client.mdx b/docs/develop/go/client/temporal-client.mdx index c73b8b140a..81fc7d72e2 100644 --- a/docs/develop/go/client/temporal-client.mdx +++ b/docs/develop/go/client/temporal-client.mdx @@ -32,7 +32,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the [Temporal Service](/temporal-service). Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals to Workflow Executions, sending Queries to Workflow Executions, getting the results of a Workflow Execution, and providing Activity Task Tokens. diff --git a/docs/develop/go/workflows/schedules.mdx b/docs/develop/go/workflows/schedules.mdx index 1a21c94f01..1b7275f6c1 100644 --- a/docs/develop/go/workflows/schedules.mdx +++ b/docs/develop/go/workflows/schedules.mdx @@ -43,7 +43,7 @@ If a Workflow Execution started by a Schedule is [Paused](/cli/command-reference Schedules are initiated with the `create` call. The user generates a unique Schedule ID for each new Schedule. -To create a Schedule in Go, use `Create()` on the [Client](/encyclopedia/temporal-sdks#temporal-client). +To create a Schedule in Go, use `Create()` on the [Client](/encyclopedia/temporal-client). Schedules must be initialized with a Schedule ID, [Spec](/schedule), and [Action](/schedule) in `client.ScheduleOptions{}`. diff --git a/docs/develop/java/client/temporal-client.mdx b/docs/develop/java/client/temporal-client.mdx index ecf6a9bcf5..2b67b1a48c 100644 --- a/docs/develop/java/client/temporal-client.mdx +++ b/docs/develop/java/client/temporal-client.mdx @@ -32,7 +32,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the [Temporal Service](/temporal-service). Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals to Workflow Executions, sending Queries to Workflow Executions, getting the results of a Workflow Execution, and providing Activity Task Tokens. diff --git a/docs/develop/php/client/temporal-client.mdx b/docs/develop/php/client/temporal-client.mdx index e43d7c1dea..643e2b9575 100644 --- a/docs/develop/php/client/temporal-client.mdx +++ b/docs/develop/php/client/temporal-client.mdx @@ -26,7 +26,7 @@ This page shows how to do the following: ## How to connect a Temporal Client to a Temporal Service {/* #connect-to-a-dev-cluster */} -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the [Temporal Service](/temporal-service). +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the [Temporal Service](/temporal-service). Communication with a Temporal Service includes, but isn't limited to, the following: - Scheduling Workflow Executions. diff --git a/docs/develop/python/client/temporal-client.mdx b/docs/develop/python/client/temporal-client.mdx index 8370a66aca..f2646c7c88 100644 --- a/docs/develop/python/client/temporal-client.mdx +++ b/docs/develop/python/client/temporal-client.mdx @@ -30,7 +30,7 @@ tags: import { ViewSourceCodeNotice } from '@site/src/components'; -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the Temporal Service. +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the Temporal Service. Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals and Queries to Workflow Executions, getting Workflow results, and more. diff --git a/docs/develop/ruby/client/temporal-client.mdx b/docs/develop/ruby/client/temporal-client.mdx index 4f3ab696d8..7f4c8d1554 100644 --- a/docs/develop/ruby/client/temporal-client.mdx +++ b/docs/develop/ruby/client/temporal-client.mdx @@ -16,7 +16,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the Temporal Service. +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the Temporal Service. Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals and Queries to Workflow Executions, getting Workflow results, and more. diff --git a/docs/develop/rust/client/temporal-client.mdx b/docs/develop/rust/client/temporal-client.mdx index 1e726d365f..79bc4c52aa 100644 --- a/docs/develop/rust/client/temporal-client.mdx +++ b/docs/develop/rust/client/temporal-client.mdx @@ -27,7 +27,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) lets your application communicate with the Temporal Service. Use it to start Workflow Executions, send Signals, run Queries, fetch Workflow results, and more. +A [Temporal Client](/encyclopedia/temporal-client) lets your application communicate with the Temporal Service. Use it to start Workflow Executions, send Signals, run Queries, fetch Workflow results, and more. This page shows how to do the following using the Rust SDK and Temporal Client: diff --git a/docs/develop/typescript/client/temporal-client.mdx b/docs/develop/typescript/client/temporal-client.mdx index cc7b78e4f2..d089c12d9f 100644 --- a/docs/develop/typescript/client/temporal-client.mdx +++ b/docs/develop/typescript/client/temporal-client.mdx @@ -28,7 +28,7 @@ tags: - Certificates --- -A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) enables you to communicate with the Temporal Service. +A [Temporal Client](/encyclopedia/temporal-client) enables you to communicate with the Temporal Service. Communication with a Temporal Service lets you perform actions such as starting Workflow Executions, sending Signals and Queries to Workflow Executions, getting Workflow results, and more. You cannot initialize a Temporal Client inside a Workflow. However, they're commonly initialized inside an Activity to communicate with a Temporal Service. diff --git a/docs/develop/typescript/install-typescript-sdk.mdx b/docs/develop/typescript/install-typescript-sdk.mdx index ff0b3ef555..c5e20ad4f3 100644 --- a/docs/develop/typescript/install-typescript-sdk.mdx +++ b/docs/develop/typescript/install-typescript-sdk.mdx @@ -11,12 +11,12 @@ tags: ## How to install a Temporal SDK {/* #install-a-temporal-sdk */} -A [Temporal SDK](/encyclopedia/temporal-sdks) provides a framework for +A [Temporal SDK](/encyclopedia/architecture/temporal-sdks) provides a framework for [Temporal Application](/temporal#temporal-application) development. An SDK provides you with the following: -- A [Temporal Client](/encyclopedia/temporal-sdks#temporal-client) to communicate with a +- A [Temporal Client](/encyclopedia/temporal-client) to communicate with a [Temporal Service](/temporal-service). - APIs to develop [Workflows](/workflows). - APIs to create and manage [Worker Processes](/workers#worker). diff --git a/docs/encyclopedia/activities/standalone-activity.mdx b/docs/encyclopedia/activities/standalone-activity.mdx index 82dd3886e5..87f26d0ddd 100644 --- a/docs/encyclopedia/activities/standalone-activity.mdx +++ b/docs/encyclopedia/activities/standalone-activity.mdx @@ -45,7 +45,7 @@ the simplest way to run durable, retryable tasks on Temporal. A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a -[Client](/encyclopedia/temporal-sdks#temporal-client), without using a Workflow. This results in +[Client](/encyclopedia/temporal-client), without using a Workflow. This results in fewer [Billable Actions](/cloud/actions-usage#actions-in-workflows) in Temporal Cloud than using a Workflow to run a single Activity. If your Activity Execution is short-lived, you will also notice lower latency, since there are fewer Worker round-trips. diff --git a/docs/encyclopedia/architecture/how-temporal-works.mdx b/docs/encyclopedia/architecture/how-temporal-works.mdx new file mode 100644 index 0000000000..e12aca769d --- /dev/null +++ b/docs/encyclopedia/architecture/how-temporal-works.mdx @@ -0,0 +1,146 @@ +--- +id: how-temporal-works +title: How Temporal works +sidebar_label: How Temporal works +description: How the Temporal Client, Server, and Worker interact during a Workflow and Activity lifecycle, with a step-by-step walkthrough and interactive demo. +toc_max_heading_level: 4 +keywords: + - architecture + - durable execution + - how temporal works + - temporal service +tags: + - Durable Execution + - Temporal + - Architecture +--- + +import { + CaptionedImage, + TemporalLifecycleDemo, +} from '@site/src/components'; + +In a Temporal application, the [Temporal Client](/encyclopedia/architecture/temporal-architecture#client-application), [Temporal Server](/encyclopedia/architecture/temporal-architecture#the-temporal-server), and [Worker](/workers#worker) are three separate parts that communicate over the network. The Client sends control requests such as starting a Workflow, sending a Signal, or requesting a result. The Server records [Event History](/workflow-execution/event), schedules [Tasks](/tasks#task) on [Task Queues](/task-queue), and persists state to a database. The Worker polls Task Queues and runs Workflow and Activity code. +The Client does not execute Workflow or Activity code. The Server does not run your application code directly. + +Understanding how these three parts exchange requests, Tasks, Commands, and Events is the basis for understanding Temporal's internal mechanics. + + +## Relationship between the Client, Service, and Worker + +### Service + +The Temporal Service is a group of backend services that together form the core Temporal system. It exposes a [Frontend Service](/encyclopedia/architecture/temporal-architecture#frontend-service), which is the network API that everything else connects to, and [backend services](/encyclopedia/architecture/temporal-architecture#temporal-service-backend) like the [History Service](/encyclopedia/architecture/temporal-architecture#history-service), which keeps the full Event History and state for each Workflow Execution, and the [Matching Service](/encyclopedia/architecture/temporal-architecture#matching-service), which manages [Task Queues](/task-queue) that hold pending work items for [Workers](/workers#worker). + +### Server + +The [Server](/encyclopedia/architecture/temporal-architecture#the-temporal-server) is a part of the Temporal Service that handles all the Temporal functionality. All of this state is written to a database, so the Server can remember what has happened even if processes or machines fail. You can run a Server yourself (self‑hosted cluster) or use [Temporal Cloud](/cloud), which is the same kind of service but operated for you. + +### Client + +A [Temporal Client](/encyclopedia/architecture/temporal-architecture#client-application) is a library object from a [Temporal SDK](/develop) that your application code uses to talk to the [Temporal Server's Frontend](/encyclopedia/architecture/temporal-architecture#frontend-service). It opens a network connection (using gRPC) to the Server and sends requests like "start this Workflow with these inputs," "cancel this Workflow," "send this Signal to a running Workflow," "run this Query on a Workflow," or "get the result of this Workflow." + +The Client does not run Workflow or Activity code; it only sends and receives these control requests. This is important because it gives your existing services, CLIs, or UIs a simple and consistent way to interact with Temporal without knowing anything about how Tasks, Task Queues, or Event histories are implemented inside the Server. + +
+ +
+ +## Worker + +A [Worker](/workers#worker) is the application component responsible for running your Workflow and Activity code, built with a Temporal SDK. Workers have historically been long-running processes deployed on bare metal, virtual machines, or in containers. + +They can now also run as [Serverless Workers](/serverless-workers) on serverless cloud infrastructure, such as AWS Lambda. Regardless of how and where Workers are deployed, they are always separate and distinct from the Temporal Service. + +The Worker connects to the Server and polls Task Queues managed by the Matching Service to ask "do you have work for me?" + +When it receives a Workflow Task, it replays the Workflow's Event History and runs your Workflow code until it either completes or reaches a point where it must wait (for example, waiting for an Activity or a Timer). It then sends Commands back to the Server that describe what should happen next, such as "schedule this Activity" or "start this Timer." + +When it receives an Activity Task, it calls your Activity function or method and then sends the outcome (success or failure and any additional result data) back to the Server, which records this as Events in the Event History. Temporal explicitly does not run your Workflow or Activity code inside the Server; that code only runs in Workers, which are under your control. + +The Server records all state and creates Workflow and Activity Tasks in Task Queues. Workers poll those queues, run your Workflow and Activity code, and send back Commands and results. The Server uses this information to update the [Event History](/workflow-execution/event) so that any Client can later request the current status or the final result, and execution can safely continue (or replay) even if individual Worker processes or machines fail. + +This is the heart of how durable execution works. + +## End-to-end lifecycle of a Workflow and Activity + +The following fifteen steps describe one Workflow Execution from start to finish, including a single Activity. The interactive demo below shows the same sequence and highlights which components communicate at each point. + +### Interactive demo + + + +### Workflow lifecycle + +**Step 1: The Temporal Client asks Temporal to start a Workflow** + +Your application calls `StartWorkflowExecution` on the Temporal API (gRPC) exposed by the Frontend Service. The request includes the Workflow type (which Workflow function/class to run), input arguments, and the Task Queue name. Frontend forwards the request to the History Service, which owns this Workflow Execution. + +**Step 2: The History Service creates the Workflow Execution** + +History creates a new Workflow Execution in the database and initializes its Event History with: `WorkflowExecutionStarted` and `WorkflowTaskScheduled` (to tell a Worker to run Workflow code). It also creates an internal Transfer Task telling the system to put a Workflow Task on the specified Task Queue. + +**Step 3: The Matching Service adds a Workflow Task to the Task Queue** + +A background queue processor in the History Service reads the Transfer Task and calls the Matching Service to `AddWorkflowTask` for that Task Queue. The Task Queue now has one pending Workflow Task for this Workflow Execution. + +**Step 4: A Worker polls for a Workflow Task** + +A Worker process (your code + SDK) is already polling that Task Queue using `PollWorkflowTask` via Frontend Service. The Frontend Service asks Matching for a Task. The Matching Service picks this Workflow Task and tells the History Service that it was started. The History Service appends `WorkflowTaskStarted` to the Event History and returns the Workflow Task (plus history) to the Worker through Frontend. + +**Step 5: The Worker runs your Workflow code** + +The SDK replays the Event History to reconstruct logical Workflow state, then starts your Workflow function/method. The Workflow runs until either returns a result or until it needs to wait (for an Activity, Timer, Signal, etc.). + +**Step 6: Your Workflow asks for work via Commands** + +When your Workflow calls Temporal APIs (for example, "execute Activity"), the SDK records Commands like `ScheduleActivityTask` or `StartTimer` instead of executing them directly. When the Workflow cannot make more progress, the Worker sends `RespondWorkflowTaskCompleted` to Frontend, carrying the list of Commands. Then the Frontend forwards this list to History. + +**Step 7: The History Service turns Commands into Events and new Tasks** + +The History appends Events based on the Commands and updates state, for example: For `ScheduleActivityTask`: `WorkflowTaskCompleted`, then `ActivityTaskScheduled`. It then creates new internal Tasks (Transfer/Timer Tasks) and, through the queue processors, calls Matching to add Activity Tasks to Activity Task Queues or later add more Workflow Tasks when needed. + +At this point, the Workflow is waiting on whatever it asked for (Activities, Timers, etc.). When those complete, the Workflow will resume. + +### Activity lifecycle + +**Step 8: The Matching Service puts an Activity Task on the Activity Task Queue** + +For each `ActivityTaskScheduled` Event, a queue processor in History calls Matching to `AddActivityTask` on the corresponding Activity Task Queue. + +**Step 9: An Activity Worker polls and starts the Activity** + +A (possibly different) Worker is polling that Activity Task Queue using `PollActivityTask` via Frontend. Frontend asks Matching; Matching selects the Activity Task and notifies History that it has started. History appends `ActivityTaskStarted` and sets up any Activity timeout timers (for example, schedule-to-close). The Activity Task is then returned to the Worker via Frontend. + +**Step 10: Worker runs your Activity code** + +The Worker calls your Activity function/method with the inputs from the Task. This code can do I/O, call external services, etc., because it is not replayed the same way as Workflow code. + +**Step 11: Activity reports success or failure** + +On success, the Worker sends `RespondActivityTaskCompleted` (with the result) to Frontend; Frontend forwards it to History. The History appends: `ActivityTaskCompleted` (including the result) and `WorkflowTaskScheduled` (to wake up the Workflow), and adds a Transfer Task to create the next Workflow Task. + +On failure, the Worker sends `RespondActivityTaskFailed`; History appends `ActivityTaskFailed` and either will append a new `ActivityTaskScheduled` (for a retry), or leaves the failure to propagate to the Workflow, depending on retry settings. + +### Workflow resumes and finishes + +**Step 12: A new Workflow Task is scheduled** + +Because of the Activity completion (or other Events like Timers), History has appended Events and scheduled a new Workflow Task. A queue processor in History calls Matching to add that Workflow Task to the Workflow Task Queue. + +**Step 13: Worker picks up the next Workflow Task and continues** + +A Worker polls the Workflow Task Queue again (`PollWorkflowTask`). The Matching Service selects the Task; the History Service appends `WorkflowTaskStarted`. The Worker receives the updated Event History via Frontend. The SDK replays the Event History, unblocks the waiting Activity or Timer, and your Workflow code continues from this new state. + +**Step 14: Workflow eventually closes** + +This cycle (Workflow Task → Commands → Events → new Tasks) repeats as many times as needed. When the Workflow function/method returns a result, the Worker sends `RespondWorkflowTaskCompleted` with a `CompleteWorkflowExecution` command. The History Service appends `WorkflowTaskCompleted` and `WorkflowExecutionCompleted` and marks the Workflow Execution as closed. Workflows can also close via failure, cancellation, termination, or "continue-as-new," but in all cases they move from open to closed and do not reopen. + +**Step 15: The Client reads the result or status from the Frontend Service** + +While the Workflow is open, Clients can query it (read-only inspection of state) and send Signals to it. After it is closed, a Client can request the final result or failure by calling the SDK, which talks to Frontend; the Frontend Service reads the necessary data from the History Service/Persistence Layer and returns it. diff --git a/docs/encyclopedia/architecture/temporal-architecture.mdx b/docs/encyclopedia/architecture/temporal-architecture.mdx new file mode 100644 index 0000000000..7add30afc3 --- /dev/null +++ b/docs/encyclopedia/architecture/temporal-architecture.mdx @@ -0,0 +1,110 @@ +--- +id: temporal-architecture +title: Temporal architecture +sidebar_label: Temporal architecture +description: A comprehensive guide to Temporal's architecture, covering how the platform orchestrates durable Workflow Executions through its Frontend, backend services, and Worker coordination. +toc_max_heading_level: 4 +keywords: + - architecture + - durable execution + - how temporal works + - temporal service +tags: + - Durable Execution + - Temporal + - Architecture +--- + +import { CaptionedImage } from '@site/src/components'; + +Before reading this, it would be helpful to read [Understanding Temporal](/evaluate/understanding-temporal) as it assumes knowledge of the following introductory concepts: Workflow, Activity, Worker, Task Queues, and Event History. + +Temporal is a tool that abstracts away a lot of difficulty for anyone managing applications that need to be resilient to failures. This guide provides you with a high level overview of how Temporal works under the hood. + +## Application structure recap + +Before diving into the architecture, let's recap what you're responsible for as a developer: the Temporal Application code which includes writing the Activity Definition, Workflow Definition, and the code to configure and start the Workers that coordinate with a Temporal Service to execute your Workflow and Activity code. + +As part of the Temporal Platform, the Temporal Service runs the Temporal Server with its database and optional components, and is responsible for orchestrating execution. A Temporal application gains its durability, scalability, and reliability from the support provided by the Temporal Service. + +
+ +
+ +In the wider platform, there are three kinds of clients that talk to the Temporal Server: + +- Temporal's [command-line interface (CLI)](/cli) +- Temporal's [web-based user interface (Web UI)](/web-ui) +- A [Temporal Client](#client-application) embedded into the applications you run + +## Client application + +Temporal Clients offer a set of APIs to communicate with a Temporal Service. They are one aspect of your Temporal application and provided by a Temporal SDK. You instantiate and use it in your own application code to start and manage Workflow Executions. + +Consider the example of an order processing system. + +A Temporal Client lets you: + +- **Start a Workflow Execution** when a customer places an order. +- **Signal a Workflow Execution** to update the order if the customer changes their shipping address. +- **Query a Workflow Execution** to retrieve the current status of the order. +- **List Workflow Executions** to view all orders being processed. +- **Get the result of a Workflow Execution** to retrieve the final outcome of the order processing. + +Clients are responsible for starting Workflows by sending requests to initiate new Workflow Executions. They can query Workflows to retrieve current state or synchronous data from running Workflows and signal Workflows to send asynchronous messages that influence their behavior. Clients also manage Workflows by canceling or terminating Workflow Executions. + +## The Temporal Server + +The Temporal Server is the heart of the platform. It's responsible for orchestrating Workflow Execution, maintaining state, and ensuring reliability. + +The Temporal Server consists of a Frontend and multiple backend services, plus a database as a required external component. A Temporal Server may also include some optional components, such as Elasticsearch for advanced search visibility or Grafana for creating operational dashboards for observability. + +
+ +
+ +### Frontend Service + +From your application's perspective, the Frontend Service is the Temporal endpoint your Temporal Client talks to. Your client sends requests (start Workflow, Signal, Query, etc.) to the Frontend, and the Frontend forwards them to the appropriate backend services. + +It handles rate limiting, authorization, validation, and routing requests internally to the right subsystem. Clients never communicate directly with backend services or Workers so all requests goes through this unified entry point. + +### Temporal Service backend + +The backend consists of several specialized services including the History, Matching, and Worker services, and a Persistence Layer. + +#### History Service + +The History Service is the part of Temporal that keeps track of everything that happens in each Workflow. It writes an ordered [Event History](/encyclopedia/event-history/) to the database so Temporal always knows what has happened. This includes when a Workflow started, Activities ran, Signals were received, timers fired, and when it completed or failed. + +The Event History (every event/step of each Workflow) is the key to making your application reliable and crash-proof. When an error or failure happens in your app, Temporal will recreate the state by parsing the Event History and replaying each step. + +That's why [determinism](/workflow-definition#deterministic-constraints) and [idempotency](/activity-definition#idempotency) are important when you're creating your Workflows. + +The History Service is a central part of how Temporal provides Durable Execution. It persists all Workflow Execution state, including the Event History, any mutable state, and internal task queues like timers, transfers, replication, and visibility/indexing. + +#### Matching Service + +The Matching Service manages most of the coordination with the other services, especially the Task Queues or Task Queue partitions. This is where Tasks are dispatched to their respective queues before being picked up by the corresponding Workers. To determine how many more Tasks should be sent to a Worker from the Task Queue, Worker polling also takes place here. This is how Tasks are dispatched to different queues before being sent to a Worker. + +When a Workflow Task or Activity needs to be done, the Matching Service finds an appropriate Worker polling the queue and hands off the Task. + +#### Worker Service + +The Worker Service is where all of the background functionality that keeps the Temporal Service running smoothly is handled. It takes care of all the internal/system Workflows that Temporal needs like maintenance jobs, cleanup, replication, archival, and visibility indexing. You won't need to directly interact with this layer because it's different from your application Workers. The Worker Service handles Temporal's own operational tasks, like archiving old Event Histories or running scheduled maintenance. + +#### Persistence layer + +You can configure the database that you want to store Workflow state, Event History, and Task Queues. You can choose between Cassandra, MySQL, PostgreSQL, and SQLite. This is also where you store metadata about your Workflows and other data that needs to be recorded in order to ensure Durable Execution. This persistence enables recovery and replay - if anything fails, Temporal can reconstruct the exact state of a Workflow from its Event History. + +Application [Workers](/workers#worker) run your Workflow and Activity code on your own infrastructure. For how they coordinate with the Server, see [How Temporal works](/encyclopedia/architecture/how-temporal-works). diff --git a/docs/encyclopedia/temporal-sdks.mdx b/docs/encyclopedia/architecture/temporal-sdks.mdx similarity index 56% rename from docs/encyclopedia/temporal-sdks.mdx rename to docs/encyclopedia/architecture/temporal-sdks.mdx index 40bd88039f..16417383fe 100644 --- a/docs/encyclopedia/temporal-sdks.mdx +++ b/docs/encyclopedia/architecture/temporal-sdks.mdx @@ -20,31 +20,21 @@ tags: - Durable Execution --- -import { CaptionedImage } from '@site/src/components'; +import { CaptionedImage, SdkGuideLinks } from '@site/src/components'; -Temporal SDKs (software development kits) are an open source collection of tools, libraries, and APIs that enable Temporal Application development. +A Temporal SDK (software development kit) is the open-source library you add to your application to use Temporal. -They offer a [Temporal Client](#temporal-client) to interact with the [Temporal Service](/temporal-service), APIs to develop your [Temporal Application](#temporal-application), and APIs to run horizontally scalable [Workers](/workers#worker). - -SDKs are more than just a development tool, however. -The SDK APIs enable developers to write code in a particular pattern that mirrors real world processes. -The SDK's internal implementation, working in collaboration with the Temporal Service, steps through that code, guaranteeing execution progression during application runtime. +It provides everything needed to build Workflows, Activities, and other Temporal features in a specific programming language including APIs to configure a Temporal Client, develop your Temporal Application, and run [Workers](/workers#worker) you can scale out as your load grows. ## Temporal Applications {/* #temporal-application */} -A Temporal Application is the code you write, comprised of [Workflow Definitions](/workflow-definition), [Activity Definitions](/activity-definition), code used to configure [Temporal Clients](#temporal-client), and code used to configure and start [Workers](/workers#worker). Developers create Temporal Applications using an [official Temporal SDK](#official-sdks). +A Temporal Application is the code you write, comprised of [Workflow Definitions](/workflow-definition), [Activity Definitions](/activity-definition), code used to configure [Temporal Clients](#temporal-client), and code used to configure and start [Workers](/workers#worker). + Consider that the Workflow Definition code can be executed repeatedly. The Temporal Platform can concurrently support millions to billions of Workflow Executions, each of which representing an invoked Workflow Definition. - -Additionally, a Temporal Workflow Execution is both resumable and recoverable, and it can react to external events. - -- Resumable: The ability of a process to resume execution after suspending on an _awaitable_. -- Recoverable: The ability of a process to resume execution after suspending due to a _failure_. -- Reactive: The ability of a process to respond to external events. - -Hence, a Temporal Application can run for seconds or years in the presence of arbitrary load and failures. +A Temporal Application can run for seconds or years in the presence of arbitrary load and failures. ## Official SDKs {/* #official-sdks */} @@ -52,16 +42,18 @@ Hence, a Temporal Application can run for seconds or years in the presence of ar Each Temporal SDK targets a specific programming language. -- [.NET SDK feature guides](/develop/dotnet) -- [Go SDK feature guides](/develop/go) -- [Java SDK feature guides](/develop/java) -- [PHP SDK feature guides](/develop/php) -- [Python SDK feature guides](/develop/python/) -- [Ruby SDK feature guides](/develop/ruby/) -- [Rust SDK feature guides](/develop/rust) -- [TypeScript SDK feature guides](/develop/typescript/) - -Despite supporting multiple languages, and supporting many features, Temporal SDKs aim to make developers feel at home in their language. + ### Third-party SDKs @@ -76,6 +68,8 @@ The following third-party SDKs exist but are not officially supported by Tempora Temporal SDKs empower developers to concentrate on creating dependable and scalable business logic, alleviating the need to build home-grown supervisor systems to ensure reliability and fault-tolerance. This is possible because the Temporal SDK provides a unified library that abstracts the intricacies of how Temporal handles distributed systems. +SDKs are more than a development toolkit. The APIs encourage a code pattern that mirrors real-world processes, and the SDK's internal implementation, working with the [Temporal Service](/temporal-service), steps through that code at runtime to guarantee execution progression. + ### Development pattern By abstracting complexities and streamlining boilerplate code, developers can craft straightforward code that directly aligns with their business logic, enhancing code readability and bolstering developer productivity. @@ -106,31 +100,6 @@ func LoanApplicationWorkflow { For instance, Temporal SDKs have built-in support for handling failures, timeouts, and retries. In the event of an Activity failure, the SDK automatically initiates retries according to configurable policies established by the developer within the SDK. This streamlined process simplifies the integration of fault-tolerance mechanisms into applications. -:::caution Do not copy and use code - -The following is pseudocode. For tested samples see your language SDK's developer's guide. - -::: - -``` -func LoanApplicationWorkflow { - - options = { - MaxAttempts: 3, - StartToCloseTimeout: 30min, - HeartbeatTimeout: 10min, - } - - sdk.ExecuteActivity(CreditCheck, options) - - sdk.ExecuteActivity(AutomatedApproval) - - sdk.ExecuteActivity(NotifyApplicant) - - // ... -} -``` - ### Replays Another quality of the SDKs lies in their ability to replay Workflow Executions, a complex operation that contributes significantly to the Platform's promised reliability. @@ -142,8 +111,6 @@ Another quality of the SDKs lies in their ability to replay Workflow Executions, We will delve into this idea more later, but for now, it signifies that the SDKs can automatically continue a process from the point of interruption, should a failure occur. This capability stems from the SDK's ability to persist each step the program takes. -{/* - [Developing for Durable Execution using the Go SDK](/develop/go/durable-execution) */} - ## Temporal SDKs major components {/* #major-components */} **What are the major components of Temporal SDKs?** @@ -173,196 +140,42 @@ The most common operations that a Temporal Client enables you to perform are the - Signal a Workflow Execution. - Start a Workflow Execution. -The following code is an example using the Go SDK. -It showcases how to initialize a Temporal Client, create a connection to a local Temporal Service, and start a Workflow Execution: - -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. - -- [Go SDK Temporal Client feature guide](/develop/go/client/temporal-client) -- [Java SDK Temporal Client feature guide](/develop/java/client/temporal-client) -- [PHP SDK Temporal Client feature guide](/develop/php/client/temporal-client) -- [Python SDK Temporal Client feature guide](/develop/python/client) -- [TypeScript SDK Temporal Client feature guide](/develop/typescript/client) - -::: - -```go -package main - -import ( - "context" - - "go.temporal.io/sdk/client" -) - -func main() { - // Temporal Client setup code - c, err := client.NewClient(client.Options{}) - if err != nil { - log.Fatalln("Unable to create client", err) - } - defer c.Close() - // Prepare Workflow option and parameters - workflowOptions := client.StartWorkflowOptions{ - ID: "loan-application-1", - TaskQueue: "loan-application-task-queue", - } - applicantDetails := ApplicantDetails{ - // ... - } - // Start the Workflow - workflowRun, err := c.ExecuteWorkflow(context.Background(), workflowOptions, "loan-application-workflow", applicantDetails) - if err != nil { - // ... - } - // ... -} -``` +Developers use the Client as the main entry point for interacting with the application through Temporal, for example, to start or Signal Workflows, Query a Workflow's state, or get a Workflow result. -Developers can then use the Client as the main entry point for interacting with the application through Temporal. -Using that Client, developers may for example start or Signal Workflows, Query a Workflow's state, etc. -We can see in the example above how the developer has used `ExecuteWorkflow` API to start a Workflow. + ### APIs to Develop Workflows Workflows are defined as code: either a function or an object method, depending on the language. -For example, the following is a valid Temporal Workflow in Go: - -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. - -::: - -```go -func LoanApplication(ctx context.Context) (error) { - // ... - return nil -} -``` - The Workflow code uses Temporal SDK APIs to orchestrate the steps of the application. -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. -::: - -```go -func LoanApplication(ctx workflow.Context, input *LoanApplicationWorkflowInput) (*LoanApplicationWorkflowResult, error) { - // ... - var result activities.CreditCheckResult - f := workflow.ExecuteActivity(ctx, a.CreditCheck, CreditCheckInput(*input)) - err := f.Get(ctx, &result) - // ... - // Return the results - return &loanApplicationResults, nil -} -``` A Workflow executes Activities (other functions that interact with external systems), handles and sends messages (Queries, Signals, Updates), and interacts with other Workflows. This Workflow code, while executing, can be paused, resumed, and migrated across physical machines without losing state. When a Workflow calls the API to execute an Activity, the Worker sends a [Command](/references/commands) back to the Temporal Service. The Temporal Service creates Activity Tasks in response which the same or a different Worker can then pick up and begin executing. In this way, the Worker and Temporal Service work together to incrementally execute Workflow code in a reliable way. -We discuss this more in detail in [The SDK and Temporal Service relationship](/encyclopedia/temporal-sdks#sdk-and-cluster-relationship) section. +We discuss this more in the expandable [section below](#sdk-and-service-relationship). The SDK APIs also enable developers to write code that more genuinely maps to their process. This is because without a specialized SDK, developers might have to write a lot of boilerplate code. This can lead to code that's hard to maintain, difficult to understand, or that doesn't directly correspond to the underlying business process. -For example, the bank loan application Workflow might actually look like this: - -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. - -::: - -```go -// LoanApplicationWorkflow is the workflow definition. -func LoanApplicationWorkflow(ctx workflow.Context, applicantName string, loanAmount int) (string, error) { - // Step 1: Notify the applicant that the application process has started - err := workflow.ExecuteActivity(ctx, NotifyApplicantActivity, applicantName, "Application process started").Get(ctx, nil) - if err != nil { - return "", err - } - - // Step 2: Perform a credit check - var creditCheckResult string - err = workflow.ExecuteActivity(ctx, LoanCreditCheckActivity, loanAmount).Get(ctx, &creditCheckResult) - if err != nil { - return "", err - } - - // Step 3: Perform an automatic approval check - var approvalCheckResult string - err = workflow.ExecuteActivity(ctx, AutomaticApprovalCheckActivity, creditCheckResult).Get(ctx, &approvalCheckResult) - if err != nil { - return "", err - } - - // Step 4: Notify the applicant of the decision - var notificationResult string - err = workflow.ExecuteActivity(ctx, NotifyApplicantActivity, applicantName, approvalCheckResult).Get(ctx, ¬ificationResult) - if err != nil { - return "", err - } - - return notificationResult, nil -} -``` - The level of abstraction that APIs offer enables the developer to focus on business logic without having to worry about the intricacies of distributed computing such as retries, or having to explicitly maintain a state machine and the intermediate state for each step of the process. Additionally, the state of the Workflow is automatically persisted so if a failure does occur, it resumes right where it left off. + + ### APIs to create and manage Worker Processes Workers are responsible for executing Workflow and Activity code (application code). The SDK provides APIs for configuring and starting Workers, enabling developers to control how the code is executed. Workers are horizontally scalable, often run with systems like Kubernetes, and configured according to the application's needs. -Here is an example of how you could initialize a Worker using the Go SDK. - -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. - -::: - -```go -func main() { - // Create the client object just once per process - c, err := client.NewClient(client.Options{}) - if err != nil { - log.Fatalln("Unable to create Temporal client", err) - } - defer c.Close() - - // Create the Worker instance - w := worker.New(c, "loan-application-task-queue", worker.Options{}) - - // Register the workflow and activity with the worker - w.RegisterWorkflow(LoanApplicationWorkflow) - w.RegisterActivity(LoanCreditCheck) - - // Start listening to the Task Queue - err = w.Run(worker.InterruptCh()) - if err != nil { - log.Fatalln("Unable to start Worker", err) - } -} -``` - The Worker polls on the specified Task Queue, processing those Tasks, and reporting the results back to the Temporal Service. They execute both the Workflows and Activities, and the SDK ensures that they perform these tasks efficiently and reliably. + + ### APIs to customize Activity Execution behavior Activities in Temporal are individual units of work that often represent non-deterministic parts of the code logic, such as querying a database or calling an external service. The SDK provides APIs to customize the behavior of an Activity Execution. @@ -371,92 +184,29 @@ By default, if an Activity attempts to communicate with another system and encou However, Temporal enables developers to control a variety of timeouts, a Retry Policy, Heartbeat monitoring, and asynchronous completion. -The following code is an example of a custom set of Activity Execution options that affect the timeout and retry behavior of the execution, should the Activity encounter a failure. + -:::caution Do not copy and use code - -The following code is for example purposes only. -For tested code samples and best practices, use your preferred language SDK's developer's guide. - -::: - -```go -// LoanApplicationWorkflow is the Workflow Definition. -func LoanApplicationWorkflow(ctx workflow.Context, applicantName string, loanAmount int) (string, error) { - // ... - var creditCheckResult string - // set a Retry Policy - ao := workflow.ActivityOptions{ - ScheduleToCloseTimeout: time.Hour, - HeartbeatTimeout: time.Minute, - RetryPolicy: &temporal.RetryPolicy{ - InitialInterval: time.Second, - BackoffCoefficient: 2, - MaximumInterval: time.Minute, - MaximumAttempts: 5, - }, - } - ctx = workflow.WithActivityOptions(ctx, ao) - err = workflow.ExecuteActivity(ctx, LoanCreditCheckActivity, loanAmount).Get(ctx, &creditCheckResult) - if err != nil { - return "", err - } - // ... - return notificationResult, nil -} - -// LoanCreditCheckActivity is an Activity function that performs a credit check. -func LoanCreditCheckActivity(ctx context.Context, loanAmount int) (string, error) { - // ... your logic here ... - return "Credit check passed", nil -} -``` +## How SDKs work with the Temporal Service {/* #sdk-and-service-relationship */} -## The SDK and Temporal Service relationship {/* #sdk-and-cluster-relationship */} +The section below explains how your Client, Workers, and the Temporal Service work together when you run Workflow and Activity code. -**How do the Temporal SDKs work with the Temporal Service?** +
+ +How do the Temporal SDKs work with the Temporal Service? + The Temporal Service functions more as a choreographer than a conductor. Rather than directly assigning tasks to Workers, the Temporal Service arranges the Tasks into a Task Queue while Workers poll the Task Queue. Developers may create a fleet of Workers and tune them so that a Task is picked up as soon as it is available. If a Worker goes down, Tasks can wait until the next Worker is available. A Workflow might request to execute an Activity, start a Timer, or start a Child Workflow, each of which translates into a Command, dispatched to the Temporal Service. In addition to acting on these Commands, the Temporal Service documents that interaction by appending their corresponding Events into the Workflow Execution's Event History. -Take for instance the call to execute an Activity. When a Workflow invokes it, the Worker doesn't immediately execute that Activity code. Instead, it generates a ScheduleActivityTask Command, dispatching it to the Cluster. In response, the Cluster queues up a new Activity Task. Only when a Worker finds itself free, it collects the task and begins executing the Activity code. +Take for instance the call to execute an Activity. When a Workflow invokes it, the Worker doesn't immediately execute that Activity code. Instead, it generates a ScheduleActivityTask Command, dispatching it to the Temporal Service. In response, the Temporal Service queues up a new Activity Task. Only when a Worker finds itself free, it collects the task and begins executing the Activity code. The Temporal Service persists Workflow Execution Event History, so that if there is a failure, the SDK Worker is able to Replay the execution and resume where it left off. This is where the deterministic constraints of the Workflow code comes into play, requiring the use of Activities to create side effects and interact with the outside world. -Let's look at an example Workflow with a single Activity. - -```go -func LoanApplication(ctx workflow.Context, input *LoanApplicationWorkflowInput) (*LoanApplicationWorkflowResult, error) { - - ctx = workflow.WithActivityOptions(ctx, workflow.ActivityOptions{ - StartToCloseTimeout: time.Minute, - }) - - var result activities.NotifyApplicantActivityResult - f := workflow.ExecuteActivity(ctx, a.NotifyApplicantActivity, NotifyApplicantActivityInput(*input)) - - err := f.Get(ctx, &result) - - // Return the results - return &l.LoanApplicationState, nil -} - -type Activities struct {} - -func (a *Activities) NotifyApplicantActivity(ctx context.Context, input *NotifyApplicantActivityInput) (*NotifyApplicantActivityResult, error) { - var result NotifyApplicantActivityResult - - // Call the thirdparty API and handle the result - - return &result, err -} -``` - -The Activity above is performing a single call to an external API. Since the call can fail due to transient issues, we define it outside of the Workflow and provide it with retry options. +Activities perform work outside the Workflow, for example, calling an external API. Since the call can fail due to transient issues, you define it as an Activity and configure retry options in your SDK. When you create a new Worker process, the Worker creates a long-lasting connection to the Temporal Service, polling a Task Queue for Tasks that are related to the code it is capable of executing. @@ -519,3 +269,5 @@ The result of the Workflow can now be retrieved using a Temporal Client. title="The Temporal Client can now access the result of the Workflow" /> And that’s how a Temporal Worker and Temporal Service work together. + +
diff --git a/docs/encyclopedia/index.mdx b/docs/encyclopedia/index.mdx index 547627faa7..86bd2a619b 100644 --- a/docs/encyclopedia/index.mdx +++ b/docs/encyclopedia/index.mdx @@ -12,8 +12,9 @@ keywords: The following Encyclopedia pages describe the concepts, components, and features of Temporal in detail: - [Temporal](/temporal) -- [Temporal SDKs](/encyclopedia/temporal-sdks) -- [Temporal Client](/temporal-client) +- [Temporal architecture](/encyclopedia/architecture/temporal-architecture) +- [Temporal SDKs](/encyclopedia/architecture/temporal-sdks) +- [Temporal Client](/encyclopedia/temporal-client) - [Workflows](/workflows) - [Activities](/activities) - [Failures and error handling](/encyclopedia/failures-and-error-handling) diff --git a/docs/encyclopedia/nexus/standalone-nexus-operation.mdx b/docs/encyclopedia/nexus/standalone-nexus-operation.mdx index f1be08f98f..69e211d965 100644 --- a/docs/encyclopedia/nexus/standalone-nexus-operation.mdx +++ b/docs/encyclopedia/nexus/standalone-nexus-operation.mdx @@ -31,7 +31,7 @@ import { ReleaseNoteHeader, SdkGuideLinks } from '@site/src/components'; ## What is a Standalone Nexus Operation? {/* #standalone-nexus-operation */} A Standalone Nexus Operation is a top-level [Nexus Operation Execution](/nexus/operations) started -directly by a [Client](/encyclopedia/temporal-sdks#temporal-client), without using a caller +directly by a [Client](/encyclopedia/architecture/temporal-sdks#temporal-client), without using a caller Workflow. Instead of calling a Nexus Operation from within a Workflow Definition, you execute it directly from a Nexus Client created from the Temporal SDK Client and bound to a [Nexus Endpoint](/nexus/endpoints) and Service. diff --git a/docs/encyclopedia/temporal-client.mdx b/docs/encyclopedia/temporal-client.mdx index 9ac763738f..82709ccd8b 100644 --- a/docs/encyclopedia/temporal-client.mdx +++ b/docs/encyclopedia/temporal-client.mdx @@ -3,7 +3,6 @@ id: temporal-client title: Temporal Client sidebar_label: Temporal Client description: A Temporal Client acts as the bridge for communication between your applications and the Temporal Service, enabling you to start Workflow Executions, send Signals and Queries, and retrieve results. -slug: /temporal-client toc_max_heading_level: 4 keywords: - client diff --git a/docs/encyclopedia/temporal.mdx b/docs/encyclopedia/temporal.mdx index 4d0ec2d072..1b56b56b6c 100644 --- a/docs/encyclopedia/temporal.mdx +++ b/docs/encyclopedia/temporal.mdx @@ -16,9 +16,9 @@ tags: - Concepts --- -import { CaptionedImage } from '@site/src/components'; +import { CaptionedImage, QuickstartCards } from '@site/src/components'; -Temporal is a scalable and reliable runtime for durable function executions called [Temporal Workflow Executions](/workflow-execution). +Temporal is a scalable and reliable runtime for durable function executions called [Temporal Workflow Executions](/workflow-execution). Said another way, it's a platform that guarantees the [Durable Execution](#durable-execution) of your application code. @@ -36,8 +36,6 @@ The Temporal Platform handles these types of problems, allowing you to focus on Durable Execution in the context of Temporal refers to the ability of a Workflow Execution to maintain its state and progress even in the face of failures, crashes, or server outages. This is achieved through Temporal's use of an [Event History](/workflow-execution/event#event-history), which records the state of a Workflow Execution at each step. If a failure occurs, the Workflow Execution can resume from the last recorded event, ensuring that progress isn't lost. -This durability is a key feature of Temporal Workflow Executions, making them reliable and resilient. -It enables application code to execute effectively once and to completion, regardless of whether it takes seconds or years. ## What is the Temporal Platform? {/* #temporal-platform */} @@ -55,42 +53,46 @@ Our software as a service (SaaS) offering, Temporal Cloud, offers an alternative Worker Processes are hosted and operated by you and execute your code. Workers run using one of our SDKs. - - ## What is a Temporal Application? {/* #temporal-application */} A Temporal Application is a set of [Temporal Workflow Executions](/workflow-execution). Each Temporal Workflow Execution has exclusive access to its local state, executes concurrently to all other Workflow Executions, and communicates with other Workflow Executions and the environment via message passing. -A Temporal Application can consist of millions to billions of Workflow Executions. -Workflow Executions are lightweight. -A Workflow Execution consumes few compute resources; in fact, if a Workflow Execution is suspended, such as when it is in a waiting state, the Workflow Execution consumes no compute resources at all. - -**Reentrant Process** - -A Temporal Workflow Execution is a Reentrant Process. A Reentrant Process is resumable, recoverable, and reactive. - -- Resumable: Ability of a process to continue execution after execution was suspended on an _awaitable_. -- Recoverable: Ability of a process to continue execution after execution was suspended on a _failure_. -- Reactive: Ability of a process to react to external events. - -Therefore, a Temporal Workflow Execution executes a [Temporal Workflow Definition](/workflow-definition), also called a Temporal Workflow Function, your application code, exactly once and to completion—whether your code executes for seconds or years, in the presence of arbitrary load and arbitrary failures. - -A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a [Client](/encyclopedia/temporal-sdks#temporal-client), without using a Workflow. - -If you need to orchestrate multiple Activities, use a [Workflow](/workflows). But if you just need to execute a single Activity, use a [Standalone Activity](/standalone-activity). - -## What is a Failure? {/* #failure */} - -[Temporal Failures](/references/failures) are representations (in the SDKs and Event History) of various types of errors that occur in the system. - -Failure handling is an essential part of development. -For more information, including the difference between application-level and platform-level failures, see [Handling Failure From First Principles](https://dominik-tornow.medium.com/handling-failures-from-first-principles-1ed976b1b869). -For the practical application of those concepts in Temporal, see [Failure Handling in Practice](https://temporal.io/blog/failure-handling-in-practice). - -For languages that throw (or raise) errors (or exceptions), throwing an error that is not a Temporal Failure from a Workflow fails the Workflow Task (and the Task will be retried until it succeeds), whereas throwing a Temporal Failure (or letting a Temporal Failure propagate from Temporal calls, like an [Activity Failure](/references/failures#activity-failure) from an Activity call) fails the Workflow Execution. -For more information, see [Application Failure](/references/failures#application-failure). +Therefore, a Temporal Workflow Execution executes a [Temporal Workflow Definition](/workflow-definition), also called a Temporal Workflow Function, your application code, exactly once and to completion—whether your code executes for seconds or years, in the presence of arbitrary load and arbitrary failures. + +## Next steps {/* #next-steps */} + + diff --git a/docs/evaluate/development-production-features/core-application.mdx b/docs/evaluate/development-production-features/core-application.mdx index 0d080c9194..3d39636ab4 100644 --- a/docs/evaluate/development-production-features/core-application.mdx +++ b/docs/evaluate/development-production-features/core-application.mdx @@ -38,7 +38,7 @@ Conceptually, a Workflow specifies a sequence of steps and orchestrates the exec The system can automatically retry these Activities upon some failures. Activities perform a single, well-defined action, such as calling another service, transcoding a media file, or sending an email message. -**Standalone Activities**: A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a [Client](/temporal-client), without using a Workflow. Use a [Workflow](/workflows) to orchestrate multiple Activities, but if you just need to execute a single Activity, use a [Standalone Activity](/standalone-activity). Standalone Activities are Temporal's job queue. +**Standalone Activities**: A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a [Client](/encyclopedia/temporal-client), without using a Workflow. Use a [Workflow](/workflows) to orchestrate multiple Activities, but if you just need to execute a single Activity, use a [Standalone Activity](/standalone-activity). Standalone Activities are Temporal's job queue. **Workers**: A Worker executes your Workflow and Activity code. diff --git a/docs/evaluate/temporal-cloud/security.mdx b/docs/evaluate/temporal-cloud/security.mdx index 6c5d0da082..43f7e91b6e 100644 --- a/docs/evaluate/temporal-cloud/security.mdx +++ b/docs/evaluate/temporal-cloud/security.mdx @@ -32,14 +32,14 @@ For information about the general security features of Temporal, see our [Platfo ### Code execution boundaries Temporal Cloud provides the capabilities of Temporal Server as a managed service; it does not manage your applications or [Workers](/workers#worker). -Applications and services written using [Temporal SDKs](/encyclopedia/temporal-sdks) run in your computing environment, such as containers (Docker, Kubernetes) or virtual machines (in any hosting environment). +Applications and services written using [Temporal SDKs](/encyclopedia/architecture/temporal-sdks) run in your computing environment, such as containers (Docker, Kubernetes) or virtual machines (in any hosting environment). You have full control over how you secure your applications and services. ### Data Converter: Client-side encryption The optional [Data Conversion](/dataconversion) capability of the Temporal Platform lets you transparently encrypt data before it's sent to Temporal Cloud and decrypt it when it comes out. -Data Conversion runs on your Temporal Workers and [Clients](/encyclopedia/temporal-sdks#temporal-client); Temporal Cloud cannot see or decrypt your data. +Data Conversion runs on your Temporal Workers and [Clients](/encyclopedia/temporal-client); Temporal Cloud cannot see or decrypt your data. If you use this feature, data stored in Temporal Cloud remains encrypted even if the service itself is compromised. By deploying a [Codec Server](/production-deployment/data-encryption) you can securely decrypt data in the [Temporal Web UI](/web-ui) without sharing encryption keys with Temporal. diff --git a/docs/evaluate/understanding-temporal.mdx b/docs/evaluate/understanding-temporal.mdx index 4092d5a644..b9c60fa21e 100644 --- a/docs/evaluate/understanding-temporal.mdx +++ b/docs/evaluate/understanding-temporal.mdx @@ -75,7 +75,7 @@ You have full control over how often and how many times these retries should hap If you need to orchestrate multiple Activities, use a [Workflow](/workflows). But if you just need to execute a single Activity, use a [Standalone Activity](/standalone-activity). -A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a [Client](/encyclopedia/temporal-sdks#temporal-client), without using a Workflow. +A Standalone Activity is a top-level [Activity Execution](/activity-execution) started directly by a [Client](/encyclopedia/temporal-client), without using a Workflow. ### SDK diff --git a/docs/glossary.md b/docs/glossary.md index 144476baad..1cf3f9c3b4 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -229,7 +229,7 @@ loss during failover. -#### [Failure](/temporal#failure) +#### [Failure](/references/failures) Temporal Failures are representations of various types of errors that occur in the system. @@ -655,7 +655,7 @@ The Temporal CLI is the most recent version of Temporal's command-line tool. -#### [Temporal Client](/temporal-client) +#### [Temporal Client](/encyclopedia/temporal-client) A Temporal Client, provided by a Temporal SDK, provides a set of APIs to communicate with a Temporal Service. @@ -721,7 +721,7 @@ The Temporal Platform consists of a Temporal Service and Worker Processes. -#### [Temporal SDK](/encyclopedia/temporal-sdks) +#### [Temporal SDK](/encyclopedia/architecture/temporal-sdks) A Temporal SDK is a language-specific library that offers APIs to construct and use a Temporal Client to communicate with a Temporal Service, develop Workflow Definitions, and develop Worker Programs. diff --git a/docs/production-deployment/self-hosted-guide/server-frontend-api-reference.mdx b/docs/production-deployment/self-hosted-guide/server-frontend-api-reference.mdx index ccd04c3ba5..3fe26c0512 100644 --- a/docs/production-deployment/self-hosted-guide/server-frontend-api-reference.mdx +++ b/docs/production-deployment/self-hosted-guide/server-frontend-api-reference.mdx @@ -18,7 +18,7 @@ tags: import { CaptionedImage } from '@site/src/components'; While it's usually easiest to interact with [Temporal Server](/temporal-service/temporal-server) via a -[Client SDK](/encyclopedia/temporal-sdks#temporal-client) or the [Temporal CLI](/cli), you can +[Client SDK](/encyclopedia/temporal-client) or the [Temporal CLI](/cli), you can also use its gRPC API. Our Client and Worker SDKs use the gRPC API. The API reference is located here: diff --git a/docs/references/cluster-metrics.mdx b/docs/references/cluster-metrics.mdx index 2204c790d2..0c33cb7887 100644 --- a/docs/references/cluster-metrics.mdx +++ b/docs/references/cluster-metrics.mdx @@ -17,7 +17,7 @@ The information on this page is relevant to open source [Temporal Service deploy See [Cloud metrics](/cloud/metrics/) for metrics emitted by [Temporal Cloud](/cloud/overview). -See [SDK metrics](/references/sdk-metrics) for metrics emitted by the [SDKs](/encyclopedia/temporal-sdks). +See [SDK metrics](/references/sdk-metrics) for metrics emitted by the [SDKs](/encyclopedia/architecture/temporal-sdks). ::: diff --git a/docs/references/errors.mdx b/docs/references/errors.mdx index f81d94b2cd..179b6cb1b8 100644 --- a/docs/references/errors.mdx +++ b/docs/references/errors.mdx @@ -75,7 +75,7 @@ Enter a valid Marker name and redeploy the Task. This error either indicates the possibility of unset attributes for [RequestCancelActivity](/references/commands#requestcancelactivitytask), or an invalid History Builder state. -Update the [Temporal SDK](/encyclopedia/temporal-sdks) to the most recent release. +Update the [Temporal SDK](/encyclopedia/architecture/temporal-sdks) to the most recent release. Reset any unset attributes before retrying the [Workflow Task](/tasks#workflow-task). If you continue to see this error, review your code for [nondeterministic causes](/workflow-definition#non-deterministic-change). @@ -156,7 +156,7 @@ This error indicates that a [Workflow Execution](/workflow-execution) tried to c `BadUpdate` can happen when a [Worker](/workers#worker) generates a [Workflow Task Completed](/references/events#workflowtaskcompleted) message with missing fields or an invalid Update response format. This error might indicate usage of an unsupported SDK. -Make sure you're using a [supported SDK](/encyclopedia/temporal-sdks). +Make sure you're using a [supported SDK](/encyclopedia/architecture/temporal-sdks). ## Cause Reset Workflow {/* #cause-reset-workflow */} diff --git a/docs/references/sdk-metrics.mdx b/docs/references/sdk-metrics.mdx index 906ca34d79..474e0ab3ad 100644 --- a/docs/references/sdk-metrics.mdx +++ b/docs/references/sdk-metrics.mdx @@ -13,7 +13,7 @@ tags: :::info SDK metrics -The information on this page is relevant to [Temporal SDKs](/encyclopedia/temporal-sdks). +The information on this page is relevant to [Temporal SDKs](/encyclopedia/architecture/temporal-sdks). See [Cloud metrics](/cloud/metrics/) for metrics emitted by [Temporal Cloud](/cloud/overview). diff --git a/sidebars.js b/sidebars.js index 8e8684a1bd..599bf9e5a5 100644 --- a/sidebars.js +++ b/sidebars.js @@ -1539,7 +1539,16 @@ module.exports = { }, items: [ 'encyclopedia/temporal', - 'encyclopedia/temporal-sdks', + { + type: 'category', + label: 'Architecture', + collapsed: true, + items: [ + 'encyclopedia/architecture/temporal-architecture', + 'encyclopedia/architecture/how-temporal-works', + 'encyclopedia/architecture/temporal-sdks', + ], + }, 'encyclopedia/temporal-client', { type: 'category', diff --git a/src/components/Demos/TemporalLifecycle/LifecycleDiagram.js b/src/components/Demos/TemporalLifecycle/LifecycleDiagram.js new file mode 100644 index 0000000000..1c2bdd5181 --- /dev/null +++ b/src/components/Demos/TemporalLifecycle/LifecycleDiagram.js @@ -0,0 +1,194 @@ +import React, { useMemo } from "react"; +import { useColorMode } from "@docusaurus/theme-common"; +import { + DIAGRAM_NODES, + routePath, + getActiveNodes, + getDiagramPalette, +} from "./temporal-lifecycle-layout"; + +const ENV_BOX = { x: 2, y: 8, w: 38, h: 62 }; +const SERVER_BOX = { x: 44, y: 8, w: 80, h: 62 }; + +function ServerBlock({ x, y, w, h, label, active, dim, kind, palette, fontSize = 3.2 }) { + let fill = palette.serverBlock; + if (dim) fill = palette.serverBlockDim; + if (active) fill = palette.serverBlockActive; + if (kind === "frontend") fill = active ? palette.serverBlockActive : palette.serverBlock; + if (kind === "queue") fill = active ? palette.taskQueueActive : palette.taskQueue; + if (kind === "client") fill = active ? palette.clientBlockActive : palette.clientBlock; + if (kind === "env") fill = active ? palette.envBlock : palette.envBlockDim; + + const labelFill = active && fill === palette.serverBlockActive ? palette.textOnAccent : palette.text; + + return ( + + {active && ( + + )} + + + {label} + + + ); +} + +const LifecycleDiagram = ({ step, prefix = "lifecycle", palette: paletteProp }) => { + const { colorMode } = useColorMode(); + const isDark = colorMode === "dark"; + const palette = useMemo(() => paletteProp || getDiagramPalette(isDark), [paletteProp, isDark]); + const activeNodes = getActiveNodes(step); + + const envCenterX = ENV_BOX.x + ENV_BOX.w / 2; + const serverCenterX = SERVER_BOX.x + SERVER_BOX.w / 2; + + return ( + + ); +}; + +export default LifecycleDiagram; diff --git a/src/components/Demos/TemporalLifecycle/TemporalLifecycleDemo.js b/src/components/Demos/TemporalLifecycle/TemporalLifecycleDemo.js new file mode 100644 index 0000000000..bd69abe280 --- /dev/null +++ b/src/components/Demos/TemporalLifecycle/TemporalLifecycleDemo.js @@ -0,0 +1,154 @@ +import React, { useEffect, useMemo, useState } from "react"; +import LifecycleDiagram from "./LifecycleDiagram"; +import styles from "./temporal-lifecycle-demo.module.css"; +import { LIFECYCLE_STEPS } from "./temporal-lifecycle-steps"; + +function StepPanel({ display, step11Variant, onStep11Variant, showStep11Toggle }) { + return ( +
+
+ + Step {display.number}/{LIFECYCLE_STEPS.length} + +
+ +

{display.title}

+ + {showStep11Toggle && ( +
+ + +
+ )} + + {display.callout && ( +
+ + {display.callout.label}: {display.callout.value} + +
+ )} + + {display.events?.length > 0 && ( +
+ {display.events.map((event) => ( + + {event} + + ))} +
+ )} + +

{display.note}

+
+ ); +} + +function Controls({ currentStep, onStep, onPrev, onNext }) { + return ( +
+ + +
+ {LIFECYCLE_STEPS.map((s) => ( + + ))} +
+ + +
+ ); +} + +const TemporalLifecycleDemo = () => { + const [currentStep, setCurrentStep] = useState(1); + const [step11Variant, setStep11Variant] = useState("success"); + + const step = LIFECYCLE_STEPS[currentStep - 1]; + + const display = useMemo(() => { + if (currentStep === 11 && step.variants) { + return { ...step, ...step.variants[step11Variant] }; + } + return step; + }, [currentStep, step, step11Variant]); + + useEffect(() => { + const onKeyDown = (event) => { + if (event.key === "ArrowLeft") setCurrentStep((s) => Math.max(1, s - 1)); + if (event.key === "ArrowRight") setCurrentStep((s) => Math.min(LIFECYCLE_STEPS.length, s + 1)); + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, []); + + return ( +
+
+

Temporal Architecture: 15-Step Lifecycle

+

+ Interactive visualization of how the Client, Frontend Service, History Service, Matching Service, Workers, + and database collaborate to execute Workflows and Activities. +

+
+ +
+
+ +
+ + +
+ + setCurrentStep(Math.max(1, currentStep - 1))} + onNext={() => setCurrentStep(Math.min(LIFECYCLE_STEPS.length, currentStep + 1))} + /> + +

+ Blue lines show requests sent through the Frontend. Green arrows show + responses coming back. Your Worker runs in YOUR ENVIRONMENT. +

+
+ ); +}; + +export default TemporalLifecycleDemo; diff --git a/src/components/Demos/TemporalLifecycle/temporal-lifecycle-demo.module.css b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-demo.module.css new file mode 100644 index 0000000000..58b6d2039b --- /dev/null +++ b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-demo.module.css @@ -0,0 +1,215 @@ +.demo { + margin: 2rem 0; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: 0; + overflow: hidden; + background: var(--ifm-background-color); + color: var(--ifm-font-color-base); +} + +.header { + padding: 1.25rem 1.5rem 0; +} + +.headerTitle { + margin: 0 0 0.35rem; + font-size: 1.15rem; + color: var(--ifm-font-color-base); +} + +.headerDesc { + margin: 0; + font-size: 0.9rem; + color: var(--ifm-color-emphasis-700); + line-height: 1.5; +} + +.content { + display: grid; + grid-template-columns: 1.15fr 0.85fr; + gap: 1.25rem; + padding: 1.25rem 1.5rem; +} + +@media (max-width: 996px) { + .content { + grid-template-columns: 1fr; + } +} + +.diagramPanel { + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 0; + background: var(--ifm-background-surface-color); + min-height: 380px; + display: flex; + align-items: center; + justify-content: center; + padding: 0.75rem 1rem; +} + +.diagramPanel :global(.lifecycle-diagram-svg) { + width: 100%; + min-height: 380px; + height: auto; + display: block; +} + +.diagramPanel :global(.lifecycle-diagram-label) { + font-family: var(--ifm-font-family-base); + letter-spacing: 0.02em; +} + +.detailsPanel { + display: flex; + flex-direction: column; + gap: 0.85rem; +} + +.stepMeta { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + align-items: center; +} + +.stepBadge { + display: inline-block; + padding: 0.25rem 0.55rem; + border-radius: 0; + font-size: 0.75rem; + font-weight: 700; + background: #444ce7; + color: #ffffff; +} + +.stepTitle { + margin: 0; + font-size: 1.1rem; + color: var(--ifm-font-color-base); +} + +.chipRow { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; +} + +.chip { + padding: 0.25rem 0.5rem; + border-radius: 0; + font-size: 0.78rem; + font-family: var(--ifm-font-family-monospace); + background: var(--ifm-color-emphasis-100); + border: 1px solid var(--ifm-color-emphasis-200); + color: var(--ifm-font-color-base); +} + +.chipEvent { + border-color: rgba(46, 158, 107, 0.35); + background: rgba(46, 158, 107, 0.1); +} + +.note { + margin: 0; + font-size: 0.88rem; + line-height: 1.55; + color: var(--ifm-color-emphasis-800); +} + +.variantToggle { + display: flex; + gap: 0.5rem; +} + +.variantBtn { + padding: 0.35rem 0.7rem; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: 0; + background: transparent; + font-size: 0.8rem; + cursor: pointer; + color: var(--ifm-font-color-base); +} + +.variantBtnActive { + border-color: #444ce7; + background: rgba(68, 76, 231, 0.12); + color: #444ce7; + font-weight: 600; +} + +.controls { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; + padding: 0 1.5rem 1.25rem; + flex-wrap: wrap; +} + +.navBtn { + padding: 0.5rem 0.9rem; + border: 1px solid #444ce7; + border-radius: 0; + background: #444ce7; + color: #ffffff; + font-size: 0.85rem; + font-weight: 500; + cursor: pointer; +} + +.navBtn:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +.stepDots { + display: flex; + flex-wrap: nowrap; + gap: 0.3rem; + justify-content: center; + flex: 1; + min-width: 0; + overflow-x: auto; + padding: 0.15rem 0; +} + +.stepDot { + min-width: 1.85rem; + height: 1.75rem; + padding: 0 0.3rem; + border-radius: 0; + border: 1px solid var(--ifm-color-emphasis-400); + background: transparent; + font-size: 0.7rem; + font-weight: 600; + cursor: pointer; + color: var(--ifm-font-color-base); + flex-shrink: 0; + white-space: nowrap; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.stepDotActive { + background: #444ce7; + border-color: #444ce7; + color: #ffffff; +} + +.legend { + margin: 0 1.5rem 1.25rem; + padding: 0.75rem 1rem; + border-left: 3px solid #444ce7; + background: rgba(68, 76, 231, 0.06); + font-size: 0.82rem; + line-height: 1.5; + color: var(--ifm-color-emphasis-800); +} + +.legend strong { + color: var(--ifm-font-color-base); +} diff --git a/src/components/Demos/TemporalLifecycle/temporal-lifecycle-layout.js b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-layout.js new file mode 100644 index 0000000000..f4cb8ca0d9 --- /dev/null +++ b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-layout.js @@ -0,0 +1,84 @@ +const ACCENT = "#444CE7"; + +export function getDiagramPalette(isDark) { + if (isDark) { + return { + serverBg: "#242526", + serverBlock: "#3538a0", + serverBlockActive: ACCENT, + serverBlockDim: "#2a2d5c", + envBorder: "#3d9e5f", + envBg: "#1b1b1d", + envBlock: "#2f5e44", + envBlockDim: "#1f3d2c", + clientBlock: "#3538a0", + clientBlockActive: ACCENT, + taskQueue: "#3538a0", + taskQueueActive: ACCENT, + connector: "rgba(255,255,255,0.2)", + connectorActive: ACCENT, + connectorReturn: "#5bb98a", + glow: "rgba(68, 76, 231, 0.5)", + text: "#ffffff", + textOnAccent: "#ffffff", + textMuted: "rgba(255,255,255,0.65)", + }; + } + + return { + serverBg: "#f0f1fd", + serverBlock: "#c8ccf9", + serverBlockActive: ACCENT, + serverBlockDim: "#e4e6fc", + envBorder: "#3d9e5f", + envBg: "#ffffff", + envBlock: "#d9efe3", + envBlockDim: "#eef7f1", + clientBlock: "#c8ccf9", + clientBlockActive: ACCENT, + taskQueue: "#c8ccf9", + taskQueueActive: ACCENT, + connector: "rgba(20,20,20,0.15)", + connectorActive: ACCENT, + connectorReturn: "#2e9e6b", + glow: "rgba(68, 76, 231, 0.35)", + text: "#141414", + textOnAccent: "#ffffff", + textMuted: "rgba(20,20,20,0.65)", + }; +} + +export const DIAGRAM_NODES = { + Client: { cx: 21, cy: 25, w: 30, h: 9, label: "Client", kind: "client", fontSize: 3.2 }, + Worker: { cx: 21, cy: 51, w: 30, h: 10, label: "Worker", kind: "worker", fontSize: 3 }, + Frontend: { cx: 80, cy: 22, w: 66, h: 8, label: "Frontend", kind: "frontend", fontSize: 3.1 }, + History: { cx: 62, cy: 38, w: 16, h: 9, label: "History", kind: "service", fontSize: 3 }, + Matching: { cx: 80, cy: 38, w: 16, h: 9, label: "Matching", kind: "service", fontSize: 2.8 }, + WorkerService: { cx: 98, cy: 38, w: 16, h: 9, label: "Internal", kind: "internal", alwaysDim: true, fontSize: 2.6 }, + TaskQueue: { cx: 70, cy: 52, w: 44, h: 7, label: "Task Queue", kind: "queue", fontSize: 2.8 }, + Persistence: { cx: 62, cy: 66, w: 24, h: 8, label: "Database", kind: "service", fontSize: 2.7 }, +}; + +export function getActiveNodes(step) { + const active = new Set(); + if (step.local) { + active.add(step.local); + return active; + } + step.routes.forEach((route) => { + active.add(route.from); + active.add(route.to); + }); + return active; +} + +export function getNodeCenter(id) { + const n = DIAGRAM_NODES[id]; + return { x: n.cx, y: n.cy }; +} + +export function routePath(from, to) { + const start = getNodeCenter(from); + const end = getNodeCenter(to); + return `M ${start.x} ${start.y} L ${end.x} ${end.y}`; +} diff --git a/src/components/Demos/TemporalLifecycle/temporal-lifecycle-steps.js b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-steps.js new file mode 100644 index 0000000000..5e4dbd3893 --- /dev/null +++ b/src/components/Demos/TemporalLifecycle/temporal-lifecycle-steps.js @@ -0,0 +1,179 @@ +export const LIFECYCLE_STEPS = [ + { + number: 1, + title: "Client starts a Workflow", + callout: { label: "Request", value: "StartWorkflowExecution" }, + events: [], + routes: [ + { from: "Client", to: "Frontend" }, + { from: "Frontend", to: "History" }, + ], + note: "Frontend forwards the start request to History, which owns the Workflow Execution.", + }, + { + number: 2, + title: "History creates the Workflow Execution", + events: ["WorkflowExecutionStarted", "WorkflowTaskScheduled"], + routes: [ + { from: "History", to: "Persistence" }, + ], + note: "History also creates an internal Transfer Task to enqueue a Workflow Task.", + }, + { + number: 3, + title: "Matching adds a Workflow Task", + events: [], + routes: [ + { from: "History", to: "Matching" }, + { from: "Matching", to: "TaskQueue" }, + ], + note: "A History queue processor reads the Transfer Task and calls Matching to AddWorkflowTask for that Task Queue.", + }, + { + number: 4, + title: "Worker polls for a Workflow Task", + callout: { label: "Request", value: "PollWorkflowTask" }, + events: ["WorkflowTaskStarted"], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "Matching" }, + { from: "Matching", to: "History" }, + { from: "History", to: "Persistence" }, + { from: "Frontend", to: "Worker", return: true }, + ], + note: "Matching selects the task; History appends WorkflowTaskStarted and returns task + history via Frontend.", + }, + { + number: 5, + title: "Worker runs Workflow code", + events: [], + routes: [], + local: "Worker", + note: "The SDK replays the Event History locally. No Server calls until the Workflow blocks or completes.", + }, + { + number: 6, + title: "Workflow emits Commands", + callout: { label: "Request", value: "RespondWorkflowTaskCompleted" }, + events: [], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "History" }, + ], + note: "The SDK records Commands (e.g. ScheduleActivityTask) and sends them with RespondWorkflowTaskCompleted.", + }, + { + number: 7, + title: "History turns Commands into Events", + events: ["WorkflowTaskCompleted", "ActivityTaskScheduled"], + routes: [ + { from: "History", to: "Persistence" }, + { from: "History", to: "Matching" }, + ], + note: "History appends Events and creates Transfer Tasks for Matching to enqueue Activity Tasks.", + }, + { + number: 8, + title: "Matching queues an Activity Task", + events: [], + routes: [ + { from: "History", to: "Matching" }, + { from: "Matching", to: "TaskQueue" }, + ], + note: "For each ActivityTaskScheduled Event, History calls Matching to AddActivityTask on the corresponding Activity Task Queue.", + }, + { + number: 9, + title: "Worker polls for an Activity Task", + callout: { label: "Request", value: "PollActivityTask" }, + events: ["ActivityTaskStarted"], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "Matching" }, + { from: "Matching", to: "History" }, + { from: "History", to: "Persistence" }, + { from: "Frontend", to: "Worker", return: true }, + ], + note: "A possibly different Worker polls the Activity Task Queue via Frontend.", + }, + { + number: 10, + title: "Worker runs Activity code", + events: [], + routes: [], + local: "Worker", + note: "Activity code runs normally (I/O allowed). It is not replayed like Workflow code.", + }, + { + number: 11, + title: "Activity reports outcome", + callout: { label: "Request", value: "RespondActivityTaskCompleted" }, + events: ["ActivityTaskCompleted", "WorkflowTaskScheduled"], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "History" }, + { from: "History", to: "Persistence" }, + ], + variants: { + success: { + callout: { label: "Request", value: "RespondActivityTaskCompleted" }, + events: ["ActivityTaskCompleted", "WorkflowTaskScheduled"], + note: "History appends ActivityTaskCompleted and schedules the next Workflow Task.", + }, + failure: { + callout: { label: "Request", value: "RespondActivityTaskFailed" }, + events: ["ActivityTaskFailed"], + note: "History may schedule a retry (new ActivityTaskScheduled) or propagate failure to the Workflow.", + }, + }, + note: "History appends ActivityTaskCompleted and schedules the next Workflow Task.", + }, + { + number: 12, + title: "New Workflow Task scheduled", + events: ["WorkflowTaskScheduled"], + routes: [ + { from: "History", to: "Matching" }, + { from: "Matching", to: "TaskQueue" }, + ], + note: "Activity completion (or Timer/Signal Events) triggers a new Workflow Task on the Task Queue.", + }, + { + number: 13, + title: "Worker continues the Workflow", + callout: { label: "Request", value: "PollWorkflowTask" }, + events: ["WorkflowTaskStarted"], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "Matching" }, + { from: "Matching", to: "History" }, + { from: "Frontend", to: "Worker", return: true }, + ], + note: "The SDK replays updated history, unblocks the waiting Activity, and Workflow code continues.", + }, + { + number: 14, + title: "Workflow closes", + callout: { label: "Command", value: "CompleteWorkflowExecution" }, + events: ["WorkflowTaskCompleted", "WorkflowExecutionCompleted"], + routes: [ + { from: "Worker", to: "Frontend" }, + { from: "Frontend", to: "History" }, + { from: "History", to: "Persistence" }, + ], + note: "The cycle repeats until the Workflow returns; History marks the execution closed.", + }, + { + number: 15, + title: "Client reads the result", + callout: { label: "Request", value: "DescribeWorkflowExecution" }, + events: [], + routes: [ + { from: "Client", to: "Frontend" }, + { from: "Frontend", to: "History" }, + { from: "History", to: "Persistence" }, + { from: "Frontend", to: "Client", return: true }, + ], + note: "While open, Clients can Query or Signal; after close, Frontend reads the result from History.", + }, +]; diff --git a/src/components/Demos/index.js b/src/components/Demos/index.js index ee16ecda50..d87cdebc17 100644 --- a/src/components/Demos/index.js +++ b/src/components/Demos/index.js @@ -1,3 +1,4 @@ export { default as RetrySimulator } from './RetrySimulator/RetrySimulator' export { default as ServerlessWorkerDemo } from './ServerlessWorker/ServerlessWorkerDemo' -export { default as StandaloneActivityDemo } from './StandaloneActivity/StandaloneActivityDemo' \ No newline at end of file +export { default as StandaloneActivityDemo } from './StandaloneActivity/StandaloneActivityDemo' +export { default as TemporalLifecycleDemo } from './TemporalLifecycle/TemporalLifecycleDemo' \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js index f6662e2e3d..2133521f74 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -6,4 +6,4 @@ export * from './Quickstart' export * from './ToolTipTerm'; export { default as HomePageHero } from './elements/HomePageHero'; -export { default as PhotoCarousel } from './elements/PhotoCarousel'; +export { default as PhotoCarousel } from './elements/PhotoCarousel'; \ No newline at end of file diff --git a/src/css/custom.css b/src/css/custom.css index cd237c661a..5457b05c38 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -1860,3 +1860,17 @@ code { .sidebar-integrations:has(.menu__list > .menu__list-item .menu__link--active) > .menu__list-item-collapsible > .menu__caret { display: flex; } + +/* About the SDKs: expandable walkthrough — transparent background */ +.sdk-walkthrough-details, +.sdk-walkthrough-details[open] { + background: transparent; + border: none; + padding: 0; + margin: 1rem 0 0; +} + +.sdk-walkthrough-details summary { + background: transparent; + cursor: pointer; +} diff --git a/static/img/encyclopedia/architecture/overall_architecture.png b/static/img/encyclopedia/architecture/overall_architecture.png new file mode 100644 index 0000000000..40a128e7ac Binary files /dev/null and b/static/img/encyclopedia/architecture/overall_architecture.png differ diff --git a/static/img/encyclopedia/architecture/temporal-clients-and-server-dark.png b/static/img/encyclopedia/architecture/temporal-clients-and-server-dark.png new file mode 100644 index 0000000000..8f0734ae34 Binary files /dev/null and b/static/img/encyclopedia/architecture/temporal-clients-and-server-dark.png differ diff --git a/static/img/encyclopedia/architecture/temporal-clients-and-server.png b/static/img/encyclopedia/architecture/temporal-clients-and-server.png new file mode 100644 index 0000000000..2aa158807e Binary files /dev/null and b/static/img/encyclopedia/architecture/temporal-clients-and-server.png differ diff --git a/static/img/encyclopedia/architecture/temporal-server-internals-dark.png b/static/img/encyclopedia/architecture/temporal-server-internals-dark.png new file mode 100644 index 0000000000..338b424a36 Binary files /dev/null and b/static/img/encyclopedia/architecture/temporal-server-internals-dark.png differ diff --git a/static/img/encyclopedia/architecture/temporal-server-internals.png b/static/img/encyclopedia/architecture/temporal-server-internals.png new file mode 100644 index 0000000000..36d64b4092 Binary files /dev/null and b/static/img/encyclopedia/architecture/temporal-server-internals.png differ diff --git a/static/img/encyclopedia/architecture/your-environment-and-temporal-service-dark.png b/static/img/encyclopedia/architecture/your-environment-and-temporal-service-dark.png new file mode 100644 index 0000000000..2355a3f86e Binary files /dev/null and b/static/img/encyclopedia/architecture/your-environment-and-temporal-service-dark.png differ diff --git a/static/img/encyclopedia/architecture/your-environment-and-temporal-service.png b/static/img/encyclopedia/architecture/your-environment-and-temporal-service.png new file mode 100644 index 0000000000..b074d56dfb Binary files /dev/null and b/static/img/encyclopedia/architecture/your-environment-and-temporal-service.png differ diff --git a/vercel.json b/vercel.json index 94cfbc02f8..ed3cead0b7 100644 --- a/vercel.json +++ b/vercel.json @@ -2162,6 +2162,21 @@ "destination": "/develop/go/workers/run-worker-process#connect-to-temporal-cloud", "permanent": true }, + { + "source": "/encyclopedia/temporal-sdks", + "destination": "/encyclopedia/architecture/temporal-sdks", + "permanent": true + }, + { + "source": "/encyclopedia/architecture/temporal-client", + "destination": "/encyclopedia/temporal-client", + "permanent": true + }, + { + "source": "/temporal-client", + "destination": "/encyclopedia/temporal-client", + "permanent": true + }, { "source": "/cloud/users", "destination": "/cloud/manage-access/users",