Aracılığıyla paylaş


Gözlemciler

Basit bir ileti/yanıt deseninin yeterli olmadığı ve istemcinin zaman uyumsuz bildirimler alması gereken durumlar vardır. Örneğin, bir kullanıcı bir arkadaşı tarafından yeni bir anlık ileti yayımlandığında bildirim almak isteyebilir.

İstemci gözlemcileri, istemcileri zaman uyumsuz olarak bilgilendirmeye olanak tanıyan bir mekanizmadır. Gözlemci arabirimlerinin öğesinden IGrainObserverdevralması ve tüm yöntemlerin , , Task<TResult>Task, ValueTaskveya ValueTask<TResult>döndürmesi voidgerekir. Yöntemden bir özel durum oluşturulursa uygulama kilitlenmelerine neden olabileceğinden, uygulama üzerinde kullanımını async void teşvik ettiğinden dönüş türü void önerilmez. Bunun yerine, en iyi efor bildirim senaryoları için gözlemcinin arabirim yöntemine uygulamayı OneWayAttribute göz önünde bulundurun. Bu, alıcının yöntem çağrısı için bir yanıt göndermesine neden olur ve yöntemin gözlemciden yanıt beklemeden hemen çağrı alanına dönmesine neden olur. Bir tanecik, herhangi bir taneli arabirim yöntemi gibi çağırarak bir gözlemci üzerinde bir yöntem çağırır. Çalışma Orleans zamanı, isteklerin ve yanıtların teslim edilmesini sağlar. Gözlemciler için yaygın bir kullanım örneği, uygulamada bir olay gerçekleştiğinde bildirim almak üzere bir istemciyi listelemektir Orleans . Bu tür bildirimleri yayımlayan bir dilim, gözlemci eklemek veya kaldırmak için bir API sağlamalıdır. Ayrıca, mevcut aboneliğin iptal edilmesine izin veren bir yöntemi kullanıma sunma genellikle kullanışlıdır.

Tahıl geliştiricileri, gözlemlenen tahıl türlerinin geliştirilmesini basitleştirmek için gibi ObserverManager<TObserver> bir yardımcı program sınıfı kullanabilir. Hatadan sonra gerektiğinde otomatik olarak yeniden etkinleştirilen taneciklerden farklı olarak, istemciler hataya dayanıklı değildir: başarısız olan bir istemci asla kurtarılamayabilir. Bu nedenle yardımcı program, ObserverManager<T> yapılandırılan süre sonunda abonelikleri kaldırır. Etkin olan istemciler, aboneliklerini etkin tutmak için zamanlayıcıya yeniden abone olmalıdır.

Bir bildirime abone olmak için istemcinin önce gözlemci arabirimini uygulayan yerel bir nesne oluşturması gerekir. Daha sonra gözlemci fabrikasında CreateObjectReferencenesnesini bir taneli başvuruya dönüştürmek için 'adlı bir yöntem çağırır ve bu yöntem bildirimli dilimdeki abonelik yöntemine geçirilebilir.

Bu model, zaman uyumsuz bildirimler almak için diğer dilimler tarafından da kullanılabilir. Tahıllar arabirimleri de uygulayabilir IGrainObserver . İstemci aboneliği örneğinden farklı olarak, abone olan tanecik yalnızca gözlemci arabirimini uygular ve kendisine bir başvuru geçirir (örn. this.AsReference<IMyGrainObserverInterface>()). Tahıllar zaten adreslenebilir olduğundan buna gerek CreateObjectReference() yoktur.

Kod örneği

İstemcilere düzenli aralıklarla ileti gönderen bir dilimimiz olduğunu varsayalım. Kolaylık olması için örneğimizdeki ileti bir dize olacaktır. İlk olarak istemcide iletiyi alacak arabirimini tanımlarız.

Arabirim şöyle görünür

public interface IChat : IGrainObserver
{
    Task ReceiveMessage(string message);
}

Tek özel şey, arabirimin öğesinden IGrainObserverdevralması gerektiğidir. Şimdi bu iletileri gözlemlemek isteyen tüm istemciler IChatuygulayan bir sınıf uygulamalıdır.

En basit örnek şu şekilde olabilir:

public class Chat : IChat
{
    public Task ReceiveMessage(string message)
    {
        Console.WriteLine(message);
        return Task.CompletedTask;
    }
}

Sunucuda, bir sonraki adımda bu sohbet iletilerini istemcilere gönderen bir Grain'imiz olmalıdır. Grain ayrıca istemcilerin bildirimlere abone olması ve aboneliklerini kaldırması için bir mekanizmaya sahip olmalıdır. Abonelikler için grain, yardımcı program sınıfının ObserverManager<TObserver>bir örneğini kullanabilir.

Not

ObserverManager<TObserver> sürüm 7.0'ın bir parçasıdır Orleans . Eski sürümler için aşağıdaki uygulama kopyalanabilir.

class HelloGrain : Grain, IHello
{
    private readonly ObserverManager<IChat> _subsManager;

    public HelloGrain(ILogger<HelloGrain> logger)
    {
        _subsManager =
            new ObserverManager<IChat>(
                TimeSpan.FromMinutes(5), logger);
    }

    // Clients call this to subscribe.
    public Task Subscribe(IChat observer)
    {
        _subsManager.Subscribe(observer, observer);

        return Task.CompletedTask;
    }

    //Clients use this to unsubscribe and no longer receive messages.
    public Task UnSubscribe(IChat observer)
    {
        _subsManager.Unsubscribe(observer);

        return Task.CompletedTask;
    }
}

İstemcilere Notify ileti göndermek için örneğin yöntemi ObserverManager<IChat> kullanılabilir. yöntemi bir Action<T> yöntem veya lambda ifadesi alır (burada T türü IChat buradadır). Arabirimdeki herhangi bir yöntemi çağırarak istemcilere gönderebilirsiniz. Bizim örneğimizde tek bir yöntemimiz ReceiveMessagevardır ve sunucudaki gönderme kodumuz şöyle görünür:

public Task SendUpdateMessage(string message)
{
    _subsManager.Notify(s => s.ReceiveMessage(message));

    return Task.CompletedTask;
}

Artık sunucumuz gözlemci istemcilerine ileti göndermek için bir yönteme, abone olmak/abonelikten çıkmak için iki yönteme sahiptir ve istemci, ayrıntılı iletileri gözlemleyebilecek bir sınıf uygulamıştır. Son adım, daha önce uyguladığımız Chat sınıfı kullanarak istemcide bir gözlemci başvurusu oluşturmak ve abone olduktan sonra iletileri almasına izin vermektir.

Kod şöyle görünür:

//First create the grain reference
var friend = _grainFactory.GetGrain<IHello>(0);
Chat c = new Chat();

//Create a reference for chat, usable for subscribing to the observable grain.
var obj = _grainFactory.CreateObjectReference<IChat>(c);

//Subscribe the instance to receive messages.
await friend.Subscribe(obj);

Artık sunucudaki dilimimiz yöntemini her çağırışında SendUpdateMessage , abone olunan tüm istemciler iletiyi alır. İstemci kodumuzda değişkendeki Chat c örnek iletiyi alır ve konsola gönderir.

Önemli

geçirilen CreateObjectReference nesneler bir WeakReference<T> aracılığıyla tutulur ve bu nedenle başka bir başvuru yoksa çöp toplanır.

Kullanıcılar, toplanmasını istemedikleri her gözlemci için bir başvuru tutmalıdır.

Not

Gözlemciyi barındıran bir istemci başarısız olabileceğinden ve kurtarmadan sonra oluşturulan gözlemcilerin farklı (rastgele) kimlikleri olduğundan gözlemciler doğal olarak güvenilir değildir. ObserverManager<TObserver> etkin olmayan gözlemcilerin kaldırılabilmesi için yukarıda açıklandığı gibi gözlemciler tarafından düzenli olarak yeniden abonelik yapılmasına dayanır.

Yürütme modeli

uygulamaları IGrainObserver bir çağrısıyla IGrainFactory.CreateObjectReference kaydedilir ve bu yönteme yapılan her çağrı, bu uygulamaya işaret eden yeni bir başvuru oluşturur. Orleans , bu başvuruların her birine gönderilen istekleri tek tek yürüterek tamamlar. Gözlemciler yeniden giriş yapılmaz ve bu nedenle bir gözlemciye yapılan eşzamanlı istekler tarafından Orleansaraya alınmaz. Eşzamanlı olarak istek alan birden çok gözlemci varsa, bu istekler paralel olarak yürütülebilir. Gözlemci yöntemlerinin yürütülmesi veya ReentrantAttributegibi AlwaysInterleaveAttribute özniteliklerden etkilenmez: yürütme modeli bir geliştirici tarafından özelleştirilemez.