Temporal Blog 09月30日 19:16
Temporal Workflows提升分布式系统开发体验
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

Temporal通过其核心抽象——Workflow,为分布式系统开发提供了类似数据库事务的开发体验。Workflow确保平台级的容错和应用程序级的正确性,简化了复杂的分布式任务管理。以发送月度提醒邮件为例,传统函数执行需要分散在多个服务中处理,涉及定时任务、消息队列和数据库操作,并需自行处理失败重试、重复执行等问题。而Temporal Workflow可以直接运行,自动处理这些问题,提供类似普通函数的简洁定义方式,大幅提升开发效率和可靠性。

Temporal的核心抽象是Workflow,它作为执行单元、可靠性和可扩展性的基础,为分布式系统开发提供了平台级的容错和应用程序级的正确性保证,类似于数据库事务对应用程序的正确性保证。

传统分布式系统开发(如AWS Lambda+SQS示例)需要将任务拆分到多个服务(定时任务、消息队列、数据库),并自行处理失败重试、重复执行等复杂问题,导致实现复杂且难以维护。

Temporal Workflow允许开发者以简洁的函数定义方式(如伪代码所示)直接运行任务,自动处理分布式环境中的容错、重试和幂等性问题,提供类似普通函数的直观开发体验,大幅降低开发难度。

Temporal Workflow执行与普通函数执行不同,它确保任务可靠执行至完成或直至取消,无需开发者关心底层分布式系统的复杂性,提供了类似数据库事务的开发体验和安心感。

For the past 45 years, the database community has enjoyed an unparalleled developer experience: database transactions mitigate failure in totality on a platform level, guaranteeing correctness on an application level.

Despite many advancements in the past 20 years, the distributed systems community has not enjoyed an equivalent developer experience: There has not been an abstraction that mitigates failure in totality on a platform level, guaranteeing correctness on an application level.

However, Temporal changes this!

Introduction#

Temporal's core abstraction—its unit of execution, reliability, and scalability—is the Workflow. Therefore understanding the Workflow is key to understanding Temporal in general. In this blog post we dive deep into the world of Temporal Workflows.

You may think of a Temporal Workflow Definition (the Workflow code) as a regular function definition—in fact, that is the developer experience that Temporal provides to its users—but a Workflow Execution provides stunning improvements over a regular function execution.

Let's get to know Workflow Executions and contrast them to regular function executions with a straightforward example: sending reminder emails.

Our use case requires that our application send a reminder email once a month to any user who signed up for a trial period to upgrade their plan. In pseudocode our use case can be expressed as:

function send monthly reminder (user) do  while user has not signed up do    send reminder to user    sleep for 1 month  endend

Regular Functions#

The pseudocode looks fairly straightforward; in fact, the pseudocode looks less like an implementation and more like a specification. Could we use the pseudo code as a blueprint for a regular function definition?

No, not at all:

In a typical environment we cannot just invoke a function and expect the resulting function execution to reliably execute to completion—or as in this case, execute indefinitely until cancelation.

As a result, we have to "break up" the process of Send Reminder Email into many different pieces, scattered across the tech stack: A cron job here, a message in a queue there, maybe a row in some database table, you know, for good measure.

On top of that, now we need to worry about failures, retries, duplication, and idempotence.

An implementation on top of services like AWS Lambda Functions and like AWS Simple Queueing Service might look like:

// Lambda function is bound to:// a. input queue "Reminder"// b. output queue "Reminder"// We assume that:// - messages are never lost// - messages may be duplicated// - messages are retried on failurefunction SendReminderEmail(event, context) : Message {  // UserSignup, SendEmail, Get, Set will throw an  // Exception on failure  // event.user Current user  // event.iter Current iteration to limit retries (here 2)  if (!UserSignedUp(event.user)) {    // Retrieve the k/v pair for this user and iteration    let kv = Get(`$(event.user)-${event.iter}`, 0);    // Try at most twice    if(kv.val < 2) {      // Conditionally set the key. If the tag does not       // match we are racing with another instance of      // SendReminderEmail      if (Set(kv.key, kv.val + 1, kv.tag)) {        // This does not prevent us from calling SendEmail        // twice. Do you see why?        SendEmail(user);      }    }    else {      throw;    }  }  return {    message: { user: event.user, iter: event.iter + 1},    after: "30 days"  }}// Start by queueing the message {user: "<User>", iter: 0} on// the message queue "Reminder"

Listing 2 looks nothing like the pseudocode in Listing 1.

Listing 2 does not tell the story of our use case—while not overly long or verbose, it is obscure and hard to reason about.

Temporal Workflows#

Obviously we cannot use the pseudocode as a blueprint for a regular Function Definition. However, could we use the pseudo code as a blueprint for a Temporal Workflow Definition?

Well, yes, yes we can!

import { proxyActivities, sleep } from '@temporalio/workflow';const { sendReminderEmail, hasSignedUp } = proxyActivities({  scheduleToCloseTimeout: '10 seconds',  retry: { maximumAttempts: 2 }});async function SendReminderEmail(user: string) {  while(!await hasSignedUp(user)) {    try {      await sendReminderEmail(user);    } catch(e) {      // Thanks to Temporal's retry policy, we already       // tried twice, better luck next month 🍀    }    await sleep("30 days");  }}

In Temporal we can just invoke a Workflow Definition, and the resulting Workflow Execution reliably executes to completion—or as in this case, execute indefinitely until cancelation.

Temporal Workflow Executions are to distributed systems what transactions are to databases: A great developer experience and (or maybe because of) peace of mind.

Doubts? Disbelief? Check out these posts to explore how Temporal implements this game-changing execution model:

Photo by Simon Berger on Unsplash

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Temporal 分布式系统 Workflow 容错 开发体验
相关文章