Service Fabric - 有状态服务持久化

Service Fabric - Stateful Service Persistence

我是 Service Fabric 的新手,首先查看涵盖该主题的 MSDN 文章。我首先实现了 Hello World 示例 here.

我将他们原来的 RunAsync 实现更改为:

var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<int, DataObject>>("myDictionary");

while (!cancellationToken.IsCancellationRequested)
{
    DataObject dataObject;

    using (var tx = this.StateManager.CreateTransaction())
    {
        var result = await myDictionary.TryGetValueAsync(tx, 1);

        if (result.HasValue)
            dataObject = result.Value;
        else
            dataObject = new DataObject();
        //
        dataObject.UpdateDate = DateTime.Now;
        //
        //ServiceEventSource.Current.ServiceMessage(
        //    this,
        //    "Current Counter Value: {0}",
        //    result.HasValue ? result.Value.ToString() : "Value does not exist.");

        await myDictionary.AddOrUpdateAsync(tx, 1, dataObject, ((k, o) => dataObject));

        await tx.CommitAsync();
    }
    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}

我还引入了一个 DataObject 类型,并在该类型上公开了一个 UpdateDate 属性。

[DataContract(Namespace = "http://www.contoso.com")]
public class DataObject
{
    [DataMember]
    public DateTime UpdateDate { get; set; }
}

当我 运行 应用程序(visual studio 2015 中的 F5)时,在字典中找不到 dataObject 实例(键值为 1),因此我创建一个,设置 UpdateDate,将其添加到字典并提交事务。在下一个循环中,它找到 dataObject(键值为 1)并设置 UpdateDate,更新字典中的对象并提交事务。完美。

这是我的问题。当我停止并重新启动服务项目(visual studio 2015 中的 F5)时,我希望在 RunAsync 的第一次迭代中找到 dataObject(键控为 1),但事实并非如此。我希望所有状态都刷新到它的副本。

我是否必须为有状态服务执行任何操作才能将其内部状态刷新到其主副本?

从我读到的内容来看,这听起来好像所有这些都是由服务结构处理的,调用提交(在事务上)就足够了。如果我找到主副本(在 Service Fabric Explorer->Application View 中),我可以看到 RemoteReplicator_xxx LastACKProcessedTimeUTC 在我提交事务后更新(单步执行时)。

非常感谢任何帮助。

谢谢!

-马克

这是Visual Studio默认本地开发体验的功能。如果您在按 F5 后仔细观察输出 window,您将看到如下消息:

部署脚本检测到已经注册了一个相同类型和版本的现有应用程序,因此它会删除它并部署新的应用程序。这样做时,与旧应用程序关联的数据将被删除。

您有两种选择来处理这个问题。

在生产中,您将执行 application upgrade 以在保持状态的同时安全地推出更新的代码。但是,在您的开发箱上进行快速迭代的同时不断更新您的版本可能会很乏味。

另一种方法是将项目 属性 "Preserve Data on Start" 翻转为 "Yes"。这将自动更新生成的应用程序包的所有版本(不触及源中的版本),然后代表您执行应用程序升级。

请注意,由于升级路径中固有的一些系统检查,此部署选项可能比默认 remove-and-replace 慢一点。但是,当您将重新创建测试数据所花费的时间考虑在内时,这通常是浪费时间。

您需要将 ReliableDictionary 视为包含对象集合而不是引用集合。也就是说,当你向字典中添加一个“对象”时,你必须认为你正在完全移交该对象;并且您不得再更改此对象的状态。当您向 ReliableDictionary 询问“对象”时,它会返回对其内部对象的引用。出于性能原因返回引用,您可以自由读取对象的状态。 (如果 CLR 支持只读对象就好了,但它不支持。)但是,您不能像修改内部数据结构那样修改对象的状态(或调用任何会修改对象状态的方法)破坏其状态的字典。

要修改对象的状态,您必须复制返回的引用所指向的对象。您可以通过 serializing/deserializing 对象或通过其他方式(例如创建一个全新的对象并将旧状态复制到新对象)来完成此操作。然后,您将 NEW OBJECT 写入字典。在 Service Fabric 的未来版本中,我们打算改进 ReliableDictionary 的 API,使这种所需的使用模式更容易被发现。