Разработка API для тайм-аутов: TimeoutException или логическое возвращение без параметра? - PullRequest
2 голосов
/ 24 ноября 2011

Сценарий RPC поверх очередей сообщений - поскольку базовый механизм является асинхронным, клиенты должны указать, сколько времени они хотят ждать ответа, прежде чем истечет время ожидания.Как клиент, какой из этих двух фрагментов кода вы бы предпочли использовать?

Самое главное: как пользователь метода GetResponseTo (), , почему вы бы предпочли один другому?Как ваш выбор делает ваш код более расширяемым, более читабельным, более тестируемым и т. Д.?

try
{
    IEvent response = _eventMgr.GetResponseTo(myRequest, myTimeSpan);
    // I have my response!
}
catch(TimeoutException te)
{
    // I didn't get a response to 'myRequest' within 'myTimeSpan'
}

ИЛИ

IEvent myResponse = null;

if (_eventMgr.GetResponseTo(myRequest, myTimeSpan, out myResponse)
{
    // I got a response!
}
else
{
    // I didn't get a response... :(
}

Для вашей информации, вот текущийреализация GetResponseTo ():

public IEvent GetResponseTo(IEvent request, TimeSpan timeout)
{
    if (null == request) { throw new ArgumentNullException("request"); }

    // create an interceptor for the request
    IEventInterceptor interceptor = new EventInterceptor(request, timeout);

    // tell the dispatcher to watch for a response to this request
    _eventDispatcher.AddInterceptor(interceptor);

    // send the request
    _queueManager.SendRequest(request);

    // block this thread while we wait for a response.  If the timeout elapses,
    // this will throw a TimeoutException
    interceptor.WaitForResponse();

    // return the intercepted response
    return interceptor.Response;
}

Ответы [ 5 ]

1 голос
/ 24 ноября 2011

Ни первое, ни второе, я бы хотел использовать Task Parallel Library , которая является рекомендуемым способом выполнения всех асинхронных задач, начиная с .NET 4.5:

Task<IEvent> task = _eventMgr.GetResponseToAsync(myRequest);

if (task.Wait(myTimeSpan))
{
    // I got a response!
}
else
{
    // I didn't get a response... :(
}
1 голос
/ 24 ноября 2011

Вы можете использовать класс AutoResetEvent, который будет обрабатывать сантехнику для второго.

Старайтесь избегать вашего первого фрагмента кода, так как исключения дорогие

0 голосов
/ 25 января 2012

Я решил использовать параметр out.

Я хотел пометить кого-то другого в качестве ответа, но я не могу этого сделать.Я пытался реализовать подход, основанный на TPL, но не смог этого сделать, основываясь на вопросе / ответе, который я связал в своих комментариях.

Я не хочу запутывать свою модель событий, вводя еще больше концепций, как предполагает @sll.

И хотя @dasheddot предпочитает версию исключения, @sll имеет хорошее замечание, что кто-то, пытающийся отправить кучу запросов и получить кучу ответов в цикле, может столкнуться с проблемойс большим количеством исключений.

// potentially 10 exceptions?  meh... let's not go down this road.
for(int i=0;i<10;i++)
{
  try
  {
     IEvent response = _eventMgr.GetResponseTo(myRequest, myTimeSpan);

     // I have my response!
  }
  catch(TimeoutException te)
  {
     // I didn't get a response to 'myRequest' within 'myTimeSpan'
  } 
}
0 голосов
/ 24 ноября 2011

Лично я предпочел бы версию исключения.Если я укажу тайм-аут, я считаю, что это исключение, тогда, если я не смогу получить результат в течение указанного промежутка времени.Я не думаю, что уведомление на основе событий - лучшее решение здесь.Следующая логика зависит от результата, поэтому она не имеет смысла для меня.Но если вы хотите также предоставить асинхронные методы, задача Task - хорошая идея, как указано в dtb

0 голосов
/ 24 ноября 2011

Исключения тяжелые и грязные, каждый вызов метода API должен быть заключен в команду try / catch / finally, чтобы обработать пользовательское исключение. Этот подход не подходит для разработчиков, поэтому мне он не нравится.

Учитывая, что GetResponse() сам вызов является синхронным для потребителя API - возвращать значение операции довольно нормально, но я бы предложил ввести нечто более абстрактное и информативное, чем простое состояние bool, чтобы вы могли возвращать любое предоставленное состояние базовой системой обмена сообщениями это может быть пользовательский код ошибки, сообщение или даже объект. Так как это API - поместите также интерфейс:

enum OperationStatus
{
   Unknown,
   Timeout,
   Ok
}

// pretty simple, only message and status code
interface IOperationResult<T>
{
      OperationStatus Status { get; }
      string Message { get; }
      T Item { get; }      
}


class GetResponseResult : IOperationResult<IEvent>
{
   ...
} 

class EventManager
{
     public IOperationResult<IEvent> GetResponseTo(
                                      IRequest request, 
                                      TimeSpan timeInterval)
    {    
        GetResponseResult result;  

        // wait for async request                 
        // ...

        if (timeout)
        {
          result = new GetResponseResult 
                        { 
                           Status = OperationStatus.Timeout,
                           Message = underlyingMessagingLib.ErrorMessage
                        };
        }
        else
        {
          result = new GetResponseResult 
                        { 
                           Status = OperationStatus.Ok,
                           Item = response
                        };
        }

        return result;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...