Tanecik kalıcılığı

Tanecikler, ilişkili birden çok adlandırılmış kalıcı veri nesnesine sahip olabilir. Bu durum nesneleri, istekler sırasında kullanılabilir olacak şekilde, grain etkinleştirmesi sırasında depolamadan yüklenir. Tanecik kalıcılığı, herhangi bir veritabanı için depolama sağlayıcılarının kullanılana genişletilebilir bir eklenti modeli kullanır. Bu kalıcılık modeli basitlik için tasarlanmıştır ve tüm veri erişim desenlerini kapsayacak şekilde tasarlanmaz. Tanecikler, tanecik kalıcılık modelini kullanmadan veritabanlarına doğrudan da erişebilirsiniz.

Yukarıdaki diyagramda UserGrain'in profil durumu ve Sepet durumu vardır ve her biri ayrı bir depolama sisteminde depolanır.

Hedefler

  1. Her grain için birden çok adlandırılmış kalıcı veri nesnesi.
  2. Her biri farklı bir yapılandırmaya sahip olan ve farklı bir depolama sistemi tarafından desteklandırılan birden çok yapılandırılmış depolama sağlayıcısı.
  3. Depolama sağlayıcılar topluluk tarafından geliştiriliyor ve yayımlayabiliyor.
  4. Depolama sağlayıcılar, kalıcı destek deposuna tanecik durum verilerini depolama konusunda tam denetime sahip olur. Corollary: Çünkü kapsamlı bir ORM depolama çözümü sağlamamaktadır, bunun yerine özel depolama sağlayıcılarının gerektiğinde ve gerektiğinde belirli ORM gereksinimlerini desteklemesini sağlar.

Paketler

Hub'lar için hub'lar NuGet. Resmi olarak bakımı yapılan paketler şunlardır:

API

Tanecikler, seri hale getirilebilir durum türünün IPersistentState<TState>TState nerede olduğunu kullanarak kalıcı durumlarıyla etkileşime geçmelerini sağlar:

public interface IPersistentState<TState> where TState : new()
{
    TState State { get; set; }
    string Etag { get; }
    Task ClearStateAsync();
    Task WriteStateAsync();
    Task ReadStateAsync();
}

örnekleri, IPersistentState<TState> oluşturucu parametreleri olarak tanecik içine yer almaktadır. Bu parametrelere, ekli olan durum PersistentStateAttribute adını ve bunu sağlayan depolama sağlayıcısının adını tanımlamak için bir özniteliğiyle açıklama ekilebilir. Aşağıdaki örnek, oluşturucuya iki adlandırılmış durum kullanarak bunu UserGrain gösterir:

public class UserGrain : Grain, IUserGrain
{
    private readonly IPersistentState<ProfileState> _profile;
    private readonly IPersistentState<CartState> _cart;

    public UserGrain(
        [PersistentState("profile", "profileStore")] IPersistentState<ProfileState> profile,
        [PersistentState("cart", "cartStore")] IPersistentState<CartState> cart)
    {
        _profile = profile;
        _cart = cart;
    }
}

Her ikisi de aynı türde olsa bile farklı tanecik türleri yapılandırılmış farklı depolama sağlayıcıları kullanabilir; Örneğin, farklı Azure Depolama hesaplarına bağlı iki farklı Azure Depolama örneği.

Okuma durumu

Tanecik etkinleştirildiğinde tanecik durumu otomatik olarak okunur, ancak gerekli olduğunda değişen tanecik durumlarının yazması açıkça tetiklenir.

Bir tanecik, bu tanecik için arka depodan en son durumu açıkça yeniden okumak isterse, grain yöntemini çağırması ReadStateAsync gerekir. Bu, depolama sağlayıcısı aracılığıyla kalıcı depodan tanecik durumunu yeniden yükler ve TaskReadStateAsync() tanecik durumunun önceki bellek içinde kopyasının üzerine yazılır ve gelen tamamlandığında değiştirilir.

Durumunun değerine özelliği kullanılarak erişilir State . Örneğin, aşağıdaki yöntem yukarıdaki kodda bildirilen profil durumuna erişmektedir:

public Task<string> GetNameAsync() => Task.FromResult(_profile.State.Name);

Normal işlem sırasında çağrısı yapmak ReadStateAsync() gerek yoktur; durum etkinleştirme sırasında otomatik olarak yüklenir. Ancak, ReadStateAsync() harici olarak değiştirilen durumu yenilemek için kullanılabilir.

Hata işleme mekanizmalarının ayrıntıları için aşağıdaki Hata Modları bölümüne bakın.

Yazma durumu

Durum özelliği aracılığıyla State değiştirilebilir. Değiştirilen durum otomatik olarak kalıcı olmaz. Bunun yerine geliştirici, yöntemini çağırarak durumunun ne zaman kalıcı olduğuna karar WriteStateAsync verir. Örneğin, aşağıdaki yöntem üzerinde bir özelliği güncelleştirilir State ve güncelleştirilmiş durumu devam eder:

public async Task SetNameAsync(string name)
{
    _profile.State.Name = name;
    await _profile.WriteStateAsync();
}

Kavramsal olarak, Runtime Çalışma Zamanı herhangi bir yazma işlemleri sırasında kullanmak üzere grain state data nesnesinin derin bir kopyasını alır. Çalışma zamanı, beklenen mantıksal yalıtım semantiklerinin korunması şartıyla bazı durumlarda derin kopyanın bir veya daha büyük bir kopyasının gerçekleştirilemesini önlemek için iyileştirme kurallarını ve heuristics'ı kullanabilir.

Hata işleme mekanizmalarının ayrıntıları için aşağıdaki Hata Modları bölümüne bakın.

Durumu temizle

yöntemi ClearStateAsync , depolamada tanecik durumunu temizler. Sağlayıcıya bağlı olarak, bu işlem isteğe bağlı olarak grain durumunu tamamen silebilir.

Başlarken

Bir tanecik kalıcılığı kullanamadan önce siloda bir depolama sağlayıcısının yapılandırılması gerekir.

İlk olarak, biri profil durumu, biri de sepet durumu için depolama sağlayıcılarını yapılandırabilirsiniz:

var host = new HostBuilder()
    .UseOrleans(siloBuilder =>
    {
        siloBuilder.AddAzureTableGrainStorage(
            name: "profileStore",
            configureOptions: options =>
            {
                // Use JSON for serializing the state in storage
                options.UseJson = true;

                // Configure the storage connection key
                options.ConnectionString =
                    "DefaultEndpointsProtocol=https;AccountName=data1;AccountKey=SOMETHING1";
            })
            .AddAzureBlobGrainStorage(
                name: "cartStore",
                configureOptions: options =>
                {
                    // Use JSON for serializing the state in storage
                    options.UseJson = true;

                    // Configure the storage connection key
                    options.ConnectionString =
                        "DefaultEndpointsProtocol=https;AccountName=data2;AccountKey=SOMETHING2";
                });
    })
    .Build();

Artık depolama sağlayıcısı adıyla yapılandırıldığından, bu "profileStore"sağlayıcıya bir taneden erişebilirsiniz.

Kalıcı durum, bir tanecik için iki birincil şekilde eklenebilir:

  1. Grain'in IPersistentState<TState> oluşturucus una ekleme.
  2. 'den devralınarak Grain<TGrainState>.

Bir tanecik için depolama eklemenin önerilen yolu, ilişkili bir öznitelikle IPersistentState<TState> tanecik oluşturucus una eklemektir [PersistentState("stateName", "providerName")] . hakkında ayrıntılı bilgi için aşağıya bakın. Bu hala desteklemektedir ancak eski bir yaklaşım olarak kabul edilir.

Tanecikimizin durumunu tutmak için bir sınıf bildir:

[Serializable]
public class ProfileState
{
    public string Name { get; set; }

    public Date DateOfBirth
}

Tanenin IPersistentState<ProfileState> oluşturucus una ekleme:

public class UserGrain : Grain, IUserGrain
{
    private readonly IPersistentState<ProfileState> _profile;

    public UserGrain(
        [PersistentState("profile", "profileStore")]
        IPersistentState<ProfileState> profile)
    {
        _profile = profile;
    }
}

Not

Profil durumu, oluşturucuya eklemesi zamanında yüklenmez, bu nedenle o anda buna erişim geçersizdir. Durum çağrılmadan önce OnActivateAsync yüklenir.

Artık tanecik kalıcı bir durumuna sahip olduğu için durumu okumak ve yazmak için yöntemler ekleyebiliriz:

public class UserGrain : Grain, IUserGrain
    {
    private readonly IPersistentState<ProfileState> _profile;

    public UserGrain(
        [PersistentState("profile", "profileStore")]
        IPersistentState<ProfileState> profile)
    {
        _profile = profile;
    }

    public Task<string> GetNameAsync() => Task.FromResult(_profile.State.Name);

    public async Task SetNameAsync(string name)
    {
        _profile.State.Name = name;
        await _profile.WriteStateAsync();
    }
}

Kalıcılık işlemleri için hata modları

Okuma işlemleri için hata modları

Depolama sağlayıcısı tarafından ilgili grain için durum verileri ilk kez okundu sırasında döndürülen hatalar söz konusu tanecik için etkinleştirme işlemi başarısız olur; böyle bir durumda, bu tanecikin yaşam döngüsü geri çağırma yöntemine çağrı olmaz. Etkinleştirmeye neden olan özgün grain isteği, aynı tanecik etkinleştirmesi sırasındaki diğer hatalarda olduğu gibi çağıranın hatasına döndürülür. Belirli bir tane için durum verilerini okurken depolama sağlayıcısı tarafından karşılaşılan hatalar, 'den bir özel durumla sonuçlandır.ReadStateAsync()Task Grain, Tıpkı Bazı'dakiler gibi Task özel durumu işlemeyi veya yoksaymayı Task seçebilir.

Eksik/hatalı depolama sağlayıcısı yapılandırması nedeniyle silo başlatma zamanında yüklenamayan bir taneye ileti gönderme girişimi kalıcı hata döndürür BadProviderConfigException.

Yazma işlemleri için hata modları

Belirli bir tane için durum verileri yazarken depolama sağlayıcısı tarafından karşılaşılan hatalar, tarafından bir özel durum oluşturur WriteStateAsync()Task. Genellikle, bu, bu grain yöntemi için son dönüşe doğru şekilde zincirlenmiş olması şartıyla, WriteStateAsync()TaskTask tanecik çağrı özel durumu istemci çağıranı geri atacak anlamına gelir. Ancak bazı gelişmiş senaryolarda, bu tür yazma hatalarını özel olarak işlemek için ayrıntılı kod yazmak, aynı diğer hataları işleyene kadar mümkündür Task.

Hata işleme / kurtarma kodu yürüten tanecikler, yazma hatasını başarıyla işle olduklarının işaret etmek için özel durumları /Taskhatalıları yakalamalı ve bunları yeniden atamaz.

Öneriler

JSON serileştirme veya başka bir sürüme karşı serileştirme biçimi kullanma

Kod geliştikçe bu genellikle depolama türlerini de içerir. Bu değişiklikleri karşılamak için uygun bir seri hale getirici yapılandırıldı. Çoğu depolama sağlayıcısında, serileştirme UseJson biçimi olarak JSON kullanmak için bir seçenek veya benzer kullanılabilir. Zaten depolanmış olan veri sözleşmelerini geliştiren verilerin yine de yüklenilebilir olduğundan emin olmak.

<GrainTState kullanarak> bir taneye depolama ekleme

Önemli

Bir Grain<T> taneciklere depolama eklemek için Grain<T> olarak kabul edilir: daha önce açıklandığı gibi kullanılarak tanecik IPersistentState<T> depolama eklenmiştir.

'den devralınan Grain<T> tanecik sınıfları ( T burada kalıcı olması gereken uygulamaya özgü bir durum veri türüdir) durumları belirtilen depolamadan otomatik olarak yüklenir.

Bu tür tanecikler, bu StorageProviderAttribute tanecik için durum verilerini okumak/yazmak üzere kullanmak üzere bir depolama sağlayıcısının adlandırılmış örneğini belirten bir ile işaretlenir.

[StorageProvider(ProviderName="store1")]
public class MyGrain : Grain<MyGrainState>, /*...*/
{
  /*...*/
}

Temel Grain<T> sınıf, çağrı yapılacak alt sınıflar için aşağıdaki yöntemleri tanımladı:

protected virtual Task ReadStateAsync() { /*...*/ }
protected virtual Task WriteStateAsync() { /*...*/ }
protected virtual Task ClearStateAsync() { /*...*/ }

Bu yöntemlerin davranışı, daha önce tanımlanmış olan karşılıklarına IPersistentState<TState> karşılık gelecektir.

Depolama sağlayıcısı oluşturma

Durum kalıcılığı API'lerinde iki parça vardır: veya Grain<T>aracılığıyla parçaya açık API IPersistentState<T> ve ortalanması gereken depolama sağlayıcısı API'si IGrainStorage : Depolama sağlayıcılarının uygulaması gereken arabirim:

/// <summary>
/// Interface to be implemented for a storage able to read and write Orleans grain state data.
/// </summary>
public interface IGrainStorage
{
    /// <summary>Read data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">State data object to be populated for this grain.</param>
    /// <returns>Completion promise for the Read operation on the specified grain.</returns>
    Task ReadStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);

    /// <summary>Write data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">State data object to be written for this grain.</param>
    /// <returns>Completion promise for the Write operation on the specified grain.</returns>
    Task WriteStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);

    /// <summary>Delete / Clear data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">Copy of last-known state data object for this grain.</param>
    /// <returns>Completion promise for the Delete operation on the specified grain.</returns>
    Task ClearStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);
}

Bu arabirimi uygulayarak ve bu uygulama kaydederek özel bir depolama sağlayıcısı oluşturun. Mevcut bir depolama sağlayıcısı uygulaması örneği için bkz. AzureBlobGrainStorage.

Depolama sağlayıcı semantiği

Opak bir sağlayıcıya özgü Etag değer (stringEtag sağlayıcısı tarafından durum okunduğunda doldurulan tanecik durum meta verilerinin bir parçası olarak ayarlanmış olabilir. Bazı sağlayıcılar bunu kullanmaz null gibi bırakmayı Etagseçebilir.

Depolama sağlayıcısı bir kısıtlama ihlali algılayan EtagEtagTaskInconsistentStateException bir yazma işlemi gerçekleştirme girişimi, yazma işleminin geçici hatayla hataya neden olması ve temel depolama özel durumu sarmalanmasına neden olabilir.

public class InconsistentStateException : OrleansException
{
    public InconsistentStateException(
    string message,
    string storedEtag,
    string currentEtag,
    Exception storageException)
        : base(message, storageException)
    {
        StoredEtag = storedEtag;
        CurrentEtag = currentEtag;
    }

    public InconsistentStateException(
        string storedEtag,
        string currentEtag,
        Exception storageException)
        : this(storageException.Message, storedEtag, currentEtag, storageException)
    {
    }

    /// <summary>The Etag value currently held in persistent storage.</summary>
    public string StoredEtag { get; }

    /// <summary>The Etag value currently held in memory, and attempting to be updated.</summary>
    public string CurrentEtag { get; }
}

Bir depolama işlemiyle ilgili diğer hata koşulları , döndürülen hatanın , temel alınan depolama sorununa işaret eden bir özel durumla birlikte bozuk olarak neden olması gerekir. Çoğu durumda, bu özel durum, grende bir yöntemi çağırarak depolama işlemini tetikleyen arayana geri alınabilir. Çağıranın bu özel durumun serisini çıkarıp seri durumdan çıkaramayacağını düşünmek önemlidir. Örneğin, istemci özel durum türünü içeren özel Kalıcılık kitaplığını yüklemeyebilir. Bu nedenle, özel durumları çağırana geri yayabilecek özel durumlara dönüştürmeniz önerilir.

Veri eşleme

Tek tek depolama sağlayıcılarının, grestate – blob (çeşitli biçimler/seri hale getirilmiş formlar) veya alana göre sütun için en iyi seçenekleri nasıl depolayacağına karar verilmelidir.

Depolama sağlayıcısını kaydetme

Bir Gren oluşturulduğunda, Orleans Runtime hizmet sağlayıcısından ( IServiceProvider ) bir depolama sağlayıcısını çözmeyecektir. Çalışma zamanı bir örneğini IGrainStorage çözmeyecektir. Depolama sağlayıcısı adlandırılmışsa ( IGrainStorage Örneğin, özniteliği aracılığıyla [PersistentState(stateName, storageName)] ), adlandırılmış bir örneği çözümlenir.

Adlandırılmış bir örneğini IGrainStorage kaydetmek için, IGrainStorageörneğini izleyen genişletme yöntemini burada kullanın AddSingletonNamedService .