【问题标题】:How to handle unavailable services using service remoting如何使用服务远程处理不可用的服务
【发布时间】:2017-05-16 17:14:52
【问题描述】:

我正在使用service remoting 将服务 A 与服务 B 连接起来。在部署时,我注意到服务 A 可以在服务 B 仍在启动时调用服务 B 中的方法。在这种情况下,AddStringToDictionary 会抛出 NullReferenceException,因为尚未调用 RunAsync

public interface IServiceB : IService
{
    Task AddStringToDictionary(string key, string value);
}

internal sealed class ServiceB : StatefulService, IServiceB
{
    private IReliableDictionary<string, string> myDictionary;

    public ServiceB(StatefulServiceContext context)
        : base(context)
    { 
        // StateMananger is null here.
    }

    public async Task AddStringToDictionary(string key, string value) 
    {
        using (var tx = StateManager.CreateTransaction())
        {
            // myDictionary is null if this is called before RunAsync.
            await this.myDictionary.SetAsync(tx, key, value);
            await tx.CommitAsync();
        }
    }

    protected override async Task RunAsync(CancellationToken cancellationToken) 
    {
        this.myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<string, string>>("myDictionary");
    }
}

我知道我可以在AddStringToDictionary 中使用StateManager.GetOrAddAsync 方法,但我可能想要初始化更多的字段。构造函数也没有用,因为StateManager 尚不存在。我目前的解决方案是添加一个字段:

private bool serviceAvailable = false;

我在RunAsync 的末尾将此字段设置为true。然后每个公共方法都会调用ThrowIfServiceUnavailable()

private void ThrowIfServiceUnavailable()
{
    if (!serviceAvailable)
    {
        throw new ServiceUnavailableException();
    }
}

public async Task AddStringToDictionary(string key, string value) 
{
    ThrowIfServiceUnavailable();
    ...
}

目前我每次调用远程方法时都必须处理ServiceUnavailableException。我的问题是:有没有更好的方法来处理这种情况,或者这是一个好的解决方案?是否可以将我的自定义异常添加到ServiceProxy 的瞬态异常中以重试?

【问题讨论】:

    标签: c# azure-service-fabric


    【解决方案1】:

    Here's 在服务初始化时阻止调用的实现。它使用ManualResetEventSlim 来阻止。 它使用SemaphoreSlim 来强制对异步操作进行单线程访问。

    所有服务操作调用await WaitForInitializeAsync(CancellationToken.None); 而这个方法的实现是:

    private async Task WaitForInitializeAsync(CancellationToken cancellationToken)
    {
        if (_initializer.IsSet) return;
        await Task.Run(() => InitializeAsync(cancellationToken), cancellationToken);
       _initializer.Wait(cancellationToken);
    }
    

    InitializeAsync 的实现:

    private async Task InitializeAsync(CancellationToken cancellationToken)
    {
       if (_initializer.IsSet) return;
       try
       {
          _semaphore.Wait(cancellationToken);
          if (_initializer.IsSet) return;
          [initializer logic here]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多