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) が見つかると予想されますが、そうではありません。すべての状態がそのレプリカにフラッシュされることを期待します。

ステートフル サービスが内部状態をプライマリ レプリカにフラッシュするために何かする必要がありますか?

私が読んだところによると、これはすべてサービス ファブリックによって処理され、(トランザクションで) commit を呼び出すだけで十分であるかのように聞こえます。(Service Fabric Explorer->Application View で) プライマリ レプリカを見つけると、トランザクションをコミットすると (ステップ スルーするときに) RemoteReplicator_xxx LastACKProcessedTimeUTC が更新されていることがわかります。

どんな助けでも大歓迎です。

ありがとうございました!

-マーク

4

2 に答える 2

4

これは、Visual Studio の既定のローカル開発エクスペリエンスの機能です。F5 キーを押した後に出力ウィンドウをよく見ると、次のようなメッセージが表示されます。

Service Fabric デプロイ中の Visual Studio 出力ウィンドウ

デプロイ スクリプトは、同じ種類とバージョンの既存のアプリが既に登録されていることを検出したため、それを削除して新しいアプリをデプロイします。その際、古いアプリケーションに関連付けられたデータは削除されます。

これに対処するには、いくつかのオプションがあります。

本番環境では、アプリケーションのアップグレードを実行して、状態を維持しながら更新されたコードを安全にロールアウトします。しかし、開発ボックスで迅速なイテレーションを行いながら常にバージョンを更新するのは面倒です。

別の方法は、プロジェクト プロパティの [開始時にデータを保持する] を [はい] に切り替えることです。これにより、生成されたアプリケーション パッケージのすべてのバージョンが (ソース内のバージョンに影響を与えることなく) 自動的にバンプされ、ユーザーに代わってアプリのアップグレードが実行されます。

ここに画像の説明を入力

アップグレード パスに固有のシステム チェックがいくつかあるため、この展開オプションは、デフォルトの削除と置換よりも少し時間がかかる可能性があることに注意してください。ただし、テスト データを再作成するのにかかる時間を考慮すると、多くの場合、無駄になります。

于 2015-11-19T17:25:29.877 に答える
3

ReliableDictionary は、参照のコレクションではなく、オブジェクトのコレクションを保持していると考える必要があります。つまり、「オブジェクト」をディクショナリに追加するときは、オブジェクトを完全に手放していると考える必要があります。もうこのオブジェクトの状態を変更してはなりません。ReliableDictionary に「オブジェクト」を要求すると、内部オブジェクトへの参照が返されます。参照はパフォーマンス上の理由から返され、オブジェクトの状態を自由に読み取ることができます。(CLR が読み取り専用オブジェクトをサポートしていれば素晴らしいことですが、そうではありません。) ただし、内部データ構造を変更することになるため、オブジェクトの状態を変更 (またはオブジェクトの状態を変更するメソッドを呼び出す) してはなりません。ディクショナリの状態が破損しています。

オブジェクトの状態を変更するには、返された参照が指すオブジェクトのコピーを作成する必要があります。これは、オブジェクトをシリアライズ/デシリアライズするか、その他の手段 (まったく新しいオブジェクトを作成し、古い状態を新しいオブジェクトにコピーするなど) によって行うことができます。次に、NEW OBJECT をディクショナリに書き込みます。Service Fabric の将来のバージョンでは、ReliableDictionary の API を改善して、この必要な使用パターンをより見つけやすくする予定です。

于 2015-11-23T04:37:02.413 に答える