> [!note] Durable Execution > "Durable Execution" is the market categorization that Temporal is trying to define itself as. > [!quote] > The intention is that a Workflow Definition should be written to never fail due to intermittent issues; an Activity is designed to handle such issues. # Workflows and Activities - **Workflows** - Sequence of activities. Runs with high availability. Has automatic retry behavior. - **Activities** - Plain old code. ## Workflows ![[Temporal - Workflow]] ## Activities ![[Temporal - Activities]] # On Timeouts and Cancellation > [!TODO] Mostly thinking about the [[TypeScript]] SDK; # Benefits of this architecture ## [[Serialization]] By default, JSON is used as the universal serialization format. A custom [data converter](https://docs.temporal.io/dataconversion) can be plugged in. This is useful for the following: - **encryption** - for every activities and workflows, their request and response payloads are stored in the temporal server. This wouldn't fly for an enterprise customer, especially if they're using their cloud offering. - supporting custom formats such as [[Protocol Buffers]]. ## Cross-language interaction > [!thought] Temporal heavily reduces the need to have an [[RPC]] framework. Within its architecture, the best way to achieve cross-language interaction is by writing workflows and activities in different languages. Thinking of activities and sub-workflows as RPCs roughly map to the mental model. However, as every Temporal operation needs to transit through the Temporal server and undergo persistence, it is not a good general RPC replacement in a high-traffic environment. However, in a business logic heavy environment (where [[Event Sourcing]] is desirable in the first place), it is a perfect RPC replacement. ## [[Protocol Buffers]] support https://cludden.github.io/protoc-gen-go-temporal/ - using the Proto's `service` to define services is quite nice. ## No need for [[Observability|Tracing]] Temporal's timeline view is quite powerful and convenient. The best part about this is that no additional work is needed to capture this. Temporal already has the view of workflows and its activities and sub-workflows. It is already rich in semantics. Whereas tracing is fully auxiliary. Span contexts aren't needed for the program, yet they need to be passed around to construct the trace view. It's easy to accidentally break the chain, making tracing useless, without breaking the application. # Gotchas > [!note] see also: [[Temporal - thoughts on developer experience]]. Just like any abstraction, there are [[Leaky Abstraction|leaks]] to it. - [[#Deterministic Constraint]] - workflows need to be deterministic. I do wonder how easy it is to enforce this in a language like TypeScript. - Temporal's Workflow-Activity split forces the code to be organized in a specific way. # On Coding Structure - need to decide which code goes in the workflow vs the activity - workflows cannot perform even very simple non-hermetic operations. - activities cannot have sub-activities; this is different from RPCs where RPCs are free to have sub-RPCs. However, as activities are "plain old code", it can do anything (it can even spin up a temporal workflow if needed). - granularity of activities; how granular activities should be? this has impact on workflow history limits. ## Workflow History Limits [limits](https://docs.temporal.io/workflows#limits) - 51200 events - 50MB - Number of incomplete / pending operations (activities, child workflows, signals, and cancellations) As every activity invocation (parameters and return values) are recorded in - activity payloads; activities cannot return large payloads as it will negatively impact workflow history limits. Thus, the pattern of "upload to a blob store, return a pointer to it". - However, because workflow cannot access the blob store, if there are needed metadata workflow must - forever workflow - must use continue-as-new to truncate the history. # Per-Language SDKs # [[Go]] Most natural, as some constructs (channels and selectors) have go equivalent. Go also benefits from the following: - As its execution model is efficient, no concept of "executors". - Go programs don't like global state / [[Dynamic Scoping|threadlocal]], it uses `workflow.Context` to manage state directly. ## [[TypeScript]] - in many ways, better than Go. - Activities are "plain old code" - Workflows must be written in the sandboxed environment. The sandbox is maintained as a separate webpack. ## [[Python]] - https://docs.temporal.io/encyclopedia/python-sdk-sandbox - sandboxed execution. - https://docs.temporal.io/encyclopedia/python-sdk-sync-vs-async Python provides 3 (!!!) executors - `asyncio` - `ThreadPoolExecutor` - `ProcessPoolExecutor` # Other [link](https://github.com/noahlt/til/blob/main/systems/2024-08-02-temporal.md) - discussion with [[Noah Tye]] that he organized;