同步方法中的 Thread.Sleep 或 Task.Delay,同时具有同步和异步调用方



我有一个同步方法:

public void DoStuff() {  
    DoThings(); 
    GraphClient.SetExtendedProperty(user, propertyName, value);     // this method occasionally throws an exception
    DoOtherThings();
}

Call3rdPartyMethod使用 Azure Ad Graph 客户端 API 进行 REST API 调用,如果我尝试在 Active Directory 上设置扩展属性的值并且找不到该值,则会引发异常。 这通常发生在将新用户添加到目录中并且扩展属性功能在我想设置值之前没有扩展用户架构(似乎需要几秒钟(。

我用我自己的包装器替换了 SetExtendedProperty 调用,该包装器包含繁忙等待循环中的调用,因此:

public void TrySetProperty(GraphObject user, string propertyName, string value)
{
   var exceptions = new List<Exception>();
   for (int retry = 0; retry < 5; retry++)
   {
      try
      { 
          if (retry > 0)
              Thread.Sleep(1000);
              GraphClient.SetExtendedProperty(user, propertyName, value);
      }
      catch (Exception ex)
      { 
          exceptions.Add(ex);
      }
   }
   throw new AggregateException(exceptions);
  }
}

问题是我希望能够从同步和异步方法调用TrySetProperty

public void DoStuff() {  
    DoThings(); 
    TrySetProperty(user, propertyName, value);
    DoOtherThings();
}
public Task DoOtherStuffAsync() {
    await DoAsyncThings();
    TrySetProperty(user, propertyName, value);
    await DoOtherAsyncThings();
}

我不能将 SetExtendedProperty 更改为异步,并且我担心如果我从异步方法调用它,我不应该使用 Thread.Sleep - 而是 Task.Delay((。 谁能建议?

我会推荐:

  • 如果可能,制作完全异步版本。REST API 自然是异步的,但一些客户端库仍然过时(即只有同步方法(。
  • 如果可能,仅公开异步版本(因为操作自然是异步的(。如果您必须支持同步 API(例如,为了向后兼容(,那么请在我关于棕地异步的文章中使用布尔参数 hack。
  • 将 Polly 用于重试逻辑。

假设您有一个完全异步版本的GraphClient.SetExtendedProperty工作,那么您的代码可能如下所示:

private static readonly Policy syncPolicy = Policy.Handle<Exception>().WaitAndRetry(5, _ => TimeSpan.FromSeconds(1));
private static readonly Policy asyncPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1));
private static async Task TrySetProperty(GraphObject user, string propertyName, string value, bool sync)
{
    if (sync)
        syncPolicy.Execute(() => GraphClient.SetExtendedProperty(user, propertyName, value));
    else
        await asyncPolicy.ExecuteAsync(() => GraphClient.SetExtendedPropertyAsync(user, propertyName, value));
}
public static Task TrySetPropertyAsync(GraphObject user, string propertyName, string value) =>
    TrySetProperty(user, propertyName, value, sync: false);
public static void TrySetProperty(GraphObject user, string propertyName, string value) =>
    TrySetProperty(user, propertyName, value, sync: true).GetAwaiter().GetResult();

如果你的TrySetProperty逻辑真的那么简单(即,它实际上只在GraphClient上调用一个方法(,那么你可以取消布尔参数hack来简化代码:

private static readonly Policy syncPolicy = Policy.Handle<Exception>().WaitAndRetry(5, _ => TimeSpan.FromSeconds(1));
private static readonly Policy asyncPolicy = Policy.Handle<Exception>().WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1));
public static async Task TrySetPropertyAsync(GraphObject user, string propertyName, string value)
{
  await asyncPolicy.ExecuteAsync(() => GraphClient.SetExtendedPropertyAsync(user, propertyName, value));
}
public static void TrySetProperty(GraphObject user, string propertyName, string value)
{
  syncPolicy.Execute(() => GraphClient.SetExtendedProperty(user, propertyName, value));
}

最新更新