Service Fabric:将枚举类移动到不同的项目
Posted
技术标签:
【中文标题】Service Fabric:将枚举类移动到不同的项目【英文标题】:Service Fabric: Move an enum class to different project 【发布时间】:2020-12-22 07:19:42 【问题描述】:最近为了解决循环依赖,我们需要将枚举类移动到不同命名空间下的不同项目。有一些参与者和有状态的服务将这个枚举值的实例保持在它们的可靠状态。
枚举类是这样的:
namespace com.libA
public enum Foo
None = 0,
Foo1 = 1,
Foo2 = 2,
我们想把它移到另一个名称空间为com.libB
的项目中。这些枚举值存储在参与者和有状态服务中的可靠状态中,并按如下方式获取:
Foo foo = await this.StateManager.GetStateAsync<Foo>("FooKey").ConfigureAwait(false);
其中一个存储Foo
值的actor 服务是一个非常长寿的actor。理论上,它可以在快乐的路径中存活到无穷大,并且永远不会从外部调用删除。我们尝试了简单的重构 > 移动并尝试了我们的非生产环境。这开始在我们的非生产环境中导致SerializationException
。错误消息说:
Expecting element 'Foo' from namespace 'http://schemas.datacontract.org/2004/07/com.libB'.. Encountered 'Element' with name 'Foo', namespace 'http://schemas.datacontract.org/2004/07/com.libA'.
这些异常发生在旧演员中获取 Foo
的值之前。
我的问题是:
-
我们如何将
Foo
移动到命名空间com.libB
?两阶段升级会有所帮助吗?
是否有可能在不丢失/损坏数据的情况下这样做?
【问题讨论】:
【参考方案1】:您可以将带有命名空间的DataContract
属性添加到您的类型。
由于您已经在生产环境中运行,您可以使用错误中的命名空间来解决问题。
例子:
[DataContract(Name = "Foo", Namespace = "http://schemas.datacontract.org/2004/07/com.libA")]
public enum Foo
// ...
更好的方法可能是制定升级计划。
-
让2种共存
在检索状态时,有一个 try 机制,使用旧类型检索,如果失败并出现序列化异常,请尝试使用新类型。
当保持状态时,将其转换为新命名空间中的新类型,如果它是旧类型。 (添加一些日志记录,以便您验证发生的转换)
部署到测试,看看它是否工作,如果可以部署到生产中
移除旧类型,移除转换码
部署到测试,看看它是否有效,如果可以部署到生产环境。
【讨论】:
我们将尝试两阶段升级。【参考方案2】:一种选择是为所有使用Foo
的类型创建custom serializerwrappingDataContractSerializer
,在反序列化期间修复/忽略命名空间。
在IReliableStateManager.TryAddStateSerializer 用于注册一个 给定类型 T 的自定义序列化程序。此注册应 发生在 StatefulServiceBase 的构建中,以确保 在恢复开始之前,所有 Reliable Collections 都可以访问 相关的序列化程序来读取他们的持久数据。
IStateSerializer<OrderKey>.Read(BinaryReader reader)
中,将序列化的数据读取为XML
根据需要更改 XML 命名空间
将 XML 提供给 DataContractSerializer
以创建对象
返回对象
【讨论】:
以上是关于Service Fabric:将枚举类移动到不同的项目的主要内容,如果未能解决你的问题,请参考以下文章
使用 Azure DevOps 部署具有不同名称的 Service Fabric 服务
将NodeJ部署到Service Fabric Cluster
Service Fabric SfDevCluster目录从默认的C盘移动