2017-02-13 16 views
1

У меня есть синхронный метод:Thread.Sleep или Task.Delay в синхронном методе как с синхронизацией и асинхронными вызывающей

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

Call3rdPartyMethod делает вызов REST API с помощью Azure Ad Graph Client 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(). Может ли кто-нибудь посоветовать?

+0

никогда не смешивайте блокирующий код с асинхронным ждет. Это тупик, ожидающий случиться. Я бы предложил написать все ваши методы в асинхронном стиле без кода блокировки, затем используя [эту технику] (http://stackoverflow.com/a/5097066/14357), чтобы позволить себе синхронный вызов асинхронного метода. – spender

+0

@Botonomary 'retry', чтобы избежать задержки с первой попытки, но вставьте задержку перед каждой следующей попыткой. –

+0

удалил мой ответ, потому что @spender прав, это нехорошее предложение для смешивания методов асинхронного и синхронизирующего методов таким образом. –

ответ

1

Я бы рекомендовал:

  • Создание полностью асинхронную версию, если это возможно. API REST, естественно, асинхронны, но некоторые клиентские библиотеки все еще устарели (т. Е. Имеют только синхронные методы).
  • Экспортировать только асинхронную версию, если возможно (так как операция естественно асинхронна). Если вы должны поддерживать синхронные API (например, для обратной совместимости), используйте boolean argument hack in my article on brownfield async.
  • Используйте 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), то вы можете сделать прочь с логическим аргументом хак для простого кода:

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)); 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^