5

我是服务结构的新手,首先查看涵盖该主题的 MSDN 文章。我首先在这里实现 Hello World 示例。

我将他们原来的 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-> 应用程序视图中),我可以看到 RemoteReplicator_xxx LastACKProcessedTimeUTC 在我提交事务后更新(单步执行时)。

任何帮助是极大的赞赏。

谢谢!

-标记

4

2 回答 2

4

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

Service Fabric 部署期间的 Visual Studio 输出窗口

部署脚本检测到已经注册了相同类型和版本的现有应用程序,因此将其删除并部署新应用程序。在此过程中,与旧应用程序关联的数据将被删除。

你有几个选择来处理这个问题。

在生产中,您将执行应用程序升级以在保持状态的同时安全地推出更新的代码。但是在你的开发盒上进行快速迭代的同时不断更新你的版本可能很乏味。

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

在此处输入图像描述

请注意,由于升级路径中固有的一些系统检查,此部署选项可能比默认的删除和替换要慢一些。但是,当您考虑重新创建测试数据所花费的时间时,通常会被洗掉。

于 2015-11-19T17:25:29.877 回答
3

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

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

于 2015-11-23T04:37:02.413 回答