我有一个用thrift编写的API。例如:
service Api {
void invoke()
}
它做了些什么。我想更改行为以执行其他操作,但仍然保留旧行为的客户端的旧行为。
处理新API版本的最佳做法是什么?
答案 0 :(得分:5)
Thrift支持软版本控制,因此完成您的服务版本2是完全有效的,如下所示:
service Api {
void invoke(1: string optional_arg1, 2: i32 optional_arg2) throws (1: MyError e)
i32 number_of_invokes()
}
由于新添加的参数在技术上是可选的,因此任意客户端请求可能包含也可能不包含它们,或者可能只包含部分请求(例如,指定arg1
但不指定arg2
)。例外情况稍有不同,旧客户端会引发某种通用意外异常或类似情况。
甚至可以完全删除过时的函数,在这种情况下,旧客户端在尝试调用(现在不存在的)已删除函数时会收到异常。
上述所有内容在向成员,例外等添加成员字段方面同样如此。建议注销旧的已删除成员字段,而不是从IDL文件中删除声明。用于防止人们在以后的版本中重复使用旧字段ID,旧函数名称或旧枚举值。
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
。一旦使用包含required
成员的结构发布API,您将需要携带此成员,直到删除整个结构。稍后添加新的required
字段也是如此。否则你冒着破坏性变化的风险,因为混合新旧客户端和服务器迟早会产生一种情况,即一端绝对需要某个required
成员字段,但另一端无法提供,只是因为它没有知道任何事情。
这不是普通字段或optional
字段的问题,因为Thrift旨在跳过未知字段(类型ID包含在线数据中),只是忽略缺少的字段。相反,对required
字段应用其他检查以确保它们出现在有线数据中。
虽然软版本控制是一个很好的工具,但是由于需要兼容而导致累积负担。此外,在某些情况下,您的API将进行重大更改,故意不会向后兼容。在这种情况下,建议将新服务设置在不同的端点。
或者,Thrift 0.9.2引入的multiplex protocol可用于在同一端点上提供多个服务和/或服务版本(即套接字,http URI,......)
答案 1 :(得分:0)
对于您的特定场景,您可以添加一个新方法(命名为其他方式)来执行新操作。将来,出于这个原因,我会避免命名方法invoke
或类似方法。您的服务现在将有一个方法invoke
执行一些未知的操作,另一个方法(希望更好地命名)可以完成它所说的功能。这可能会导致您的用户感到困惑,但一切仍然有效。