Versioning 什么';保存旧文件(api)版本控制的最佳实践是什么?
我有一个用thrift编写的API。例如:Versioning 什么';保存旧文件(api)版本控制的最佳实践是什么?,versioning,thrift,Versioning,Thrift,我有一个用thrift编写的API。例如: service Api { void invoke() } 它有作用。我想改变行为来做其他事情,但仍然为期望旧行为的客户保留旧行为 处理新API版本的最佳实践是什么?软版本控制 Thrift支持软版本控制,因此完全可以对您的服务进行如下版本2: service Api { void invoke(1: string optional_arg1, 2: i32 optional_arg2) throws (1: MyError e) i
service Api {
void invoke()
}
它有作用。我想改变行为来做其他事情,但仍然为期望旧行为的客户保留旧行为
处理新API版本的最佳实践是什么?软版本控制
Thrift支持软版本控制,因此完全可以对您的服务进行如下版本2:
service Api {
void invoke(1: string optional_arg1, 2: i32 optional_arg2) throws (1: MyError e)
i32 number_of_invokes()
}
由于新添加的参数在技术上是可选的,因此任意客户端请求可能包含或不包含这些参数,或者可能只包含部分参数(例如,指定arg1
,但不指定arg2
)。异常有点不同,旧客户机将引发某种一般的意外异常或类似异常
甚至可以完全删除过时的函数,在这种情况下,旧客户机在尝试调用(现在不存在)已删除的函数时会出现异常
在向结构、异常等添加成员字段方面,上述所有情况都是类似的。建议注释掉旧的已删除成员字段和函数,以防止人们重新使用旧的字段ID,而不是从IDL文件中删除声明,较新版本中的旧函数名或旧枚举值
struct foobar {
// API 1.0 fields
1: i32 foo
//2: i32 bar - obsolete with API 2.0
// API 2.0 fields
3: i32 baz
}
必需的
是永久的
您需要注意的是关键字required
的使用。一旦发布了包含required
成员的结构的API,您将需要携带该结构,直到整个结构被删除。以后添加新的必填
字段也是如此。否则,您就有破坏更改的风险,因为新旧客户机和服务器的混合迟早会产生这样一种情况:一端绝对期望某个必需的成员字段,而另一端却无法交付,因为它对该字段一无所知
这对于普通或可选
字段不是问题,因为Thrift设计用于跳过未知字段(类型ID包含在wire数据中),而忽略缺少的字段。相反,对必需的字段进行额外检查,以确保它们存在于导线数据中
端点
尽管软版本控制是一个很好的工具,但由于需要兼容,它以累积负担为代价。此外,在某些情况下,您的API将经历突破性的更改,故意不向后兼容。在这种情况下,建议在不同的端点设置新服务
或者,Thrift 0.9.2引入的可用于在同一端点(即套接字、http URI等)上提供多个服务和/或服务版本。对于您的特定场景,您只需添加一个新方法(命名为其他方法)即可完成新任务。在将来,我将避免命名方法invoke
或类似的方法。您的服务现在将有一个方法invoke
,该方法执行一些未知的操作,另一个方法(希望命名更好)执行它所说的操作。这可能会导致您的用户感到困惑,但一切仍然有效