当前位置: 首页 > 知识库问答 >
问题:

什么是使用时间/节奏版本控制 API 的好方法/模式

费明诚
2023-03-14

版本控制 API 功能强大。但是,使用它的模式,代码将很快变得混乱并且难以阅读和维护。

随着时间的推移,产品需要快速发展以引入新的业务/需求。有什么建议可以明智地使用此API。

共有1个答案

万俟浩
2023-03-14

如果可能的话,我建议在节奏/时间工作流程中使用全局版本提供程序设计模式。

版本控制API非常强大,可以让您以确定的方式更改现有工作流执行的行为(向后兼容)。在现实世界中,您可能只关心添加新行为,并且可以只将此新行为引入新启动的工作流执行。在这种情况下,可以使用全局版本提供程序统一整个工作流的版本控制。

关键的想法是我们正在对整个工作流进行版本控制(这就是为什么它被称为< code > GlobalVersionProvider )。每次添加新版本,我们都会更新版本提供者,提供新版本。

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import io.temporal.workflow.Workflow;

import java.util.HashMap;
import java.util.Map;

public class GlobalVersionProvider {

    private static final String WORKFLOW_VERSION_CHANGE_ID = "global";

    private static final int STARTING_VERSION_USING_GLOBAL_VERSION = 1;
    private static final int STARTING_VERSION_DOING_X = 2;
    private static final int STARTING_VERSION_DOING_Y = 3;
    private static final int MAX_STARTING_VERSION_OF_ALL =
            STARTING_VERSION_DOING_Y;

    // Workflow.getVersion can release a thread and subsequently cause a non-deterministic error.
    // We're introducing this map in order to cache our versions on the first call, which should
    // always occur at the beginning of an workflow
    private static final Map<String, GlobalVersionProvider> RUN_ID_TO_INSTANCE_MAP =
            new HashMap<>();

    private final int versionOnInstantiation;

    private GlobalVersionProvider() {
        versionOnInstantiation =
                Workflow.getVersion(
                        WORKFLOW_VERSION_CHANGE_ID,
                        Workflow.DEFAULT_VERSION,
                        MAX_STARTING_VERSION_OF_ALL);
    }

    private int getVersion() {
        return versionOnInstantiation;
    }

    public boolean isAfterVersionOfUsingGlobalVersion() {
        return getVersion() >= STARTING_VERSION_USING_GLOBAL_VERSION;
    }

    public boolean isAfterVersionOfDoingX() {
        return getVersion() >= STARTING_VERSION_DOING_X;
    }

    public boolean isAfterVersionOfDoingY() {
        return getVersion() >= STARTING_VERSION_DOING_Y;
    }

    public static GlobalVersionProvider get() {
        String runId = Workflow.getInfo().getRunId();

        GlobalVersionProvider instance;
        if (RUN_ID_TO_INSTANCE_MAP.containsKey(runId)) {
            instance = RUN_ID_TO_INSTANCE_MAP.get(runId);
        } else {
            instance = new GlobalVersionProvider();
            RUN_ID_TO_INSTANCE_MAP.put(runId, instance);
        }

        return instance;
    }

    // NOTE: this should be called at the beginning of the workflow method
    public static void upsertGlobalVersionSearchAttribute() {
        int workflowVersion = get().getVersion();
        Workflow.upsertSearchAttributes(
                ImmutableMap.of(
                        WorkflowSearchAttribute.TEMPORAL_WORKFLOW_GLOBAL_VERSION.getValue(),
                        workflowVersion));
    }

    // Call this API on each replay tests to clear up the cache
    @VisibleForTesting
    public static void clearInstances() {
        RUN_ID_TO_INSTANCE_MAP.clear();
    }
}

请注意,由于临时/节奏 Java SDK 中的错误,工作流 .getVersion 可能会释放一个线程,并随后导致非确定性错误。我们引入此映射是为了在第一次调用时缓存我们的版本,这应该始终发生在工作流执行开始时。

在每个重播测试上调用清除实例 API 以清除缓存。

因此在工作流代码中:

public class HelloWorldImpl{

    private GlovalVersionProvider globalVersionProvider;

    @VisibleForTesting
    public HelloWorldImpl(final GlovalVersionProvider versionProvider){
       this.globalVersionProvider = versionProvider;
    }

    public HelloWorldImpl(){
       this.globalVersionProvider = GlobalVersionProvider.get();
    }

    @Override
    public void start(final Request request) {
        if (globalVersionProvider.isAfterVersionOfUsingGlobalVersion()) {
            GlobalVersionProvider.upsertGlobalVersionSearchAttribute();
        }
        ...
        ...
        if (globalVersionProvider.isAfterVersionOfDoingX()) {
            // doing X here
            ...
        }       
        ...
        if (globalVersionProvider.isAfterVersionOfDoingY()) {
            // doing Y here
            ...
        }       
        ...      
}
    

对于每个新版本

    < li >添加新常量< code > STARTING _ VERSION _ XXXX < li >添加新的API ` public boolean isafterversion of XXX() < li >更新< code > MAX _ STARTING _ VERSION _ OF _ ALL < li >将新的API应用到要添加新逻辑的工作流代码中 < li >以" helloworldworkflowreplaytest-version-x-description . JSON "的模式维护重放测试JSON。确保始终为引入工作流的每个新版本添加新的重放测试。

要删除旧代码路径(版本),请添加新版本以不执行旧代码路径,然后稍后使用Search属性查询,例如

全局版本

  • 您可以终止或重置工作流,而不是等待工作流关闭

弃用代码路径DoingX的示例:

因此在工作流代码中:

public class HelloWorldImpl implements Helloworld{
    ...
    @Override
    public void start(final Request request) {
        ...
        ...
        if (globalVersionProvider.isAfterVersionOfDoingX() && !globalVersionProvider.isAfterVersionOfNotDoingX()) {
            // doing X here
            ...
        }       
          
}
    

###Golang中的TODO示例

  • 通过在工作流代码中的任何位置使用本地临时版本控制API来防止意大利面代码
  • 提供搜索属性以查找特定版本的工作流。这将填补Temporal Java SDK缺少TemporalChangeVersion功能的空白
  • 即使Cadence Java/Golang SDK也有CadenceChangeVersion,这个全局版本搜索属性在查询中也要好得多,因为它是一个整数而不是关键字
  • 提供模式以轻松维护重播测试
  • 提供一种方法来测试不同的版本,而不缺少此功能

不应该有任何坏处。使用这种模式不会阻止您直接在工作流中使用原始版本API。你可以把这种模式和其他模式结合在一起。

 类似资料:
  • 你可以把一个版本控制系统(缩写VCS)理解为一个“数据库”,在需要的时候,它可以帮你完整地保存一个项目的快照。当你需要查看一个之前的快照(称之为“版本”)时,版本控制系统可以显示出当前版本与上一个版本之间的所有改动的细节。 版本控制与项目的种类,使用的技术和基础框架并无关系: 无论是设计开发一个HTML网站或者是一个苹果应用,它的工作原理都是一样的。 你可以选择任何你喜欢的工具来工作,它并不关心你

  • 如果我有一个长期的活动,比如 我希望能够从工作流程中取消它(而不会取消整个工作流程),然后我将如何做到这一点? 我曾希望您可以在上下文Done通道上接收,然后在工作流中创建一个可取消的上下文,但这显然无济于事。

  • Eggjs resfulApi 路由版本控制 插件:egg-router-plus 文档:https://github.com/eggjs/egg-router-plus 安装:cnpm i -S egg-router-plus 配置 插件配置 // {app_root}/config/plugin.js exports.routerPlus = { enable: true, pa

  • 问题内容: 我想知道如何使用pygame绘制图像。我知道如何加载它们。我做了一个空白的窗口。当我使用时,它不会绘制图像,而是将屏幕留空。 问题答案: 这是一个典型的布局:

  • 在开发项目中使用版本控制系统有很多好处。本章节将向你介绍其中的一些细节。 协同合作 试想一下,如果没有版本控制系统,当你需要处理那些共享文件夹中的文件时,你必须告知办公室里的所有人,你正在对哪些文件进行编辑;与此同时,其他人必须要避免与操作相同的文件。这是一个不现实和完全错误的流程。当你花了很长时间完成你的编辑后,可能这些文件早已经被团队里的其他开发成员修改或者删除了。 如果使用了版本控制系统,每

  • 问题内容: Web服务REST API版本是否存在任何已知的操作方法或最佳做法? 我注意到,AWS通过端点的URL进行版本控制。这是唯一的方法还是有其他方法可以实现相同的目标?如果有多种方法,每种方法的优点是什么? 问题答案: 这是一个很好且棘手的问题。URI设计主题同时是REST API的最突出部分,因此,对于该API的用户可能是长期的承诺。 由于应用程序的发展以及在较小程度上其API的存在是不