Обработка ошибок и обратной связи при выполнении массовых операций в многоуровневой архитектуре

StackOverflow https://stackoverflow.com/questions/1340062

Вопрос

Допустим, у вас есть метод бизнес -логики, который может выполнить некоторые операции по ряду объектов. Может быть, вы хотите позвонить в веб -сервис, выбирающий номер лотереи, один раз для каждого человека, выбранного из списка. В Java код может выглядеть примерно так:

Set<Person> selectedPeople = ... // fetch list of people
for ( Person person : selectedPeople ) {
    String lotteryNumber = callLotteryNumberWebService( person );
    // ...
}

Обратите внимание, что веб-сервис номера лотереи может иметь побочные эффекты, например, запись, что этот человек запросил номер лотереи (возможно, взимает с их учетной записи), поэтому даже если вызов веб-службы не удастся для одного человека, это могло быть успешным для других. Эта информация (номера лотереи) необходимо вернуть на более высокий уровень (представление).

Если бы это был случай, когда проходила одна операция, метод бизнес -логики мог бы вернуть одно значение (скажем, номер лотереи) или бросить исключение с любыми деталями сбоя. Но для массовых операций было бы возможно, чтобы некоторые операции добились успеха, а некоторые потерпели неудачу.

Это похоже на тип проблемы, которая возникнет во многих приложениях, и должен быть чистый способ справиться с ней. Итак, как лучше всего вернуть этот тип информации от уровня бизнес -логики к другому уровню в приложении (например, представление), предпочтительно общим образом, который можно использовать для различных типов данных и операций?

Это было полезно?

Решение

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

  • Список ошибок и затронутые объекты домена. Базовый объект домена или что-то с постоянным идентификатором может быть полезен для повторного использования. Например, набор ошибок, относящихся к объектам домена.
  • Вы можете ввести (aop, di) в объект человека какой -то объект/сообщение об ошибке. Например, if (человек. Ошибки) {...}
  • Вы можете обернуть коллекцию человека в сообщение с заголовком, телом, информацией об ошибках
  • Все ваши объекты домена могут включать сбор ошибок, доступный через интерфейс; или человек поддерживает интерфейс ihaserrors. Вы можете сделать это общим и использовать базовый объект ошибки, поддерживающий предупреждения и проверку и всевозможные вещи.

Если вы находитесь в подлинной многоуровневой (а не многослойной) системе, то у вас может быть архитектура на основе сообщений, которая может легко приспособить какую-то общую ошибку/предупреждение/механизм проверки. SOA/Ajax Systems поддается этому.

Рад углубить немного глубже, если у вас есть какие -то конкретные вопросы.

Другие советы

Этот вопрос подчеркивает важные различия между соответствующим использованием обработки исключений, транзакций и идеей рабочий процесс "компенсация" Вот что спрашивает, когда правильно заявил:

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

Это общая проблема, сначала некоторые фон о транзакционном подходе, который вы в настоящее время пытаетесь:

Транзакции данных первоначально смоделировались после учета двойного входа-один кредит и соответствующий списание средств нужно было записано вместе или вообще не. По мере того, как транзакции становятся все больше, они становятся все более проблематичными для правильного реализации и труднее справиться с неудачей. Когда вы начинаете нести идею одной транзакции по границам системы, вы, скорее всего, приближаетесь к ней неправильно. Это может быть сделано, но требует сложных и обязательно более высоких координаторов транзакций с более высокой задержкой. В определенных масштабах транзакции являются неправильным мышлением, и компенсация начинает иметь гораздо больше смысла.

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

Например, если вы заказываете книгу от Amazon, они, вероятно, не «блокируют» запись, пока она находится в вашей корзине, или даже использует строгие транзакции, чтобы определить, является ли книга еще в том, когда заказ подтвержден. Они все равно продадут его вам и отправят его, когда смогут. Если им не удастся получить его в течение нескольких недель, они, вероятно, отправят вам электронное письмо, в котором говорится, что они пытаются удовлетворить ваши потребности, и вы можете продолжать ждать, пока они получит его в магазине, или вы может отменить ваш заказ. Это называется компенсацией и необходимо во многих реальных бизнес-процессах.

Наконец, есть Ничего исключительного об этом. Ожидайте, что это может произойти, и используйте нормальный поток управления. Вы не должны использовать функции обработки исключений на своем языке (Хорошие правила, когда бросить исключение) Вы также не должны полагаться на специфические для инструмента (WCF?) Механизмы для просмотра или обработки исключений, которые происходят в реализации службы. Сообщение с недостатками должно быть нормальной частью вашего контракта на данные (разломы).

К сожалению, «чистым способом справиться с этим» нет никакого флага, который волшебным образом позаботится об этом, вы должны продолжать разложить проблему и справляться со всеми полученными частями. Надеемся, что эти концепции свяжут вас с тем, что сделали другие люди при решении этой проблемы.

Резюме:

  • Ваша проблема переросла концепцию транзакции -> изучить компенсацию рабочего процесса.

Удачи -

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

Я думаю, что вы действительно чрезмерно используете исключения, если вы думаете в этих терминах!

Вполне нормально возвращать значения, которые означают неудачу, а не бросают исключение. Часто это лучше. Исключения лучше всего используются, когда вы не можете восстановиться на уровне абстракции, на котором вы находитесь, но вы не должны использовать их в качестве основного средства управления, иначе ваши программы будут очень трудно читать.

Веб -сервис не возвращает исключения, возвращает коды возврата и сообщения. Я бы сохранил какое -то полезное представление, которое представляет возвращенную информацию, и вернул список их для представления или что -то еще, что будет смотреть на нее.

В идеале, призыв к вашему веб -сервису должен быть таким.

List<Person> selectedPeople = ... //fetch list of people
callLotteryNumberWebService(selectedPeople.ToArray );

Сделать вызов веб -службы для каждого человека является дорогостоящим. На конце сервера вам нужно обратить внимание на список и выполнить операцию. Код на стороне сервера может бросить 2 исключения: BulkoPerationFailedException - если есть фатальная ошибка из -за отсутствия файла DB или файла конфигурации. Дальнейшая обработка невозможна. BulkoperationException - это содержит множество исключений, относящихся к человеку. Вы можете сохранить какой -то идентификатор, чтобы уникально обратиться к каждому объекту. Ваш код будет таким:

List<Person> selectedPeople = ... // fetch list of people 

try{
    callLotteryNumberWebService(selectedPeople.ToArray);
}catch  (BulkOperationFailedException e) {
    SOP("Some config file missing/db down.No person records processed")
}catch(BulkOperationException e)  {
    UserDefinedExceptions us =  e.getExceptions()
    foreach(exception ein us)   {
        // read unique id to find which person object failed
    }
}

construct msg based on which personobject succeeded and which failed

Операция считается успешной, когда никаких исключений не брошено. Вы можете иметь пользовательские коды ошибок для сбоев вместо использования пользовательских исключений. Создание BulkoPerationException на стороне сервера сложно. Во -вторых, вам необходимо классифицировать ошибки, выброшенные со стороны сервера в BulkoPerationFailedException и BulkoperationException. Вот как я справился в одном из моих проектов

Я бы посмотрел DTOS для такого рода задачи. DTO также может включать информацию о том, успешным ли сохраняется или нет, и другие виды «метаданных».

Я бы, наверное, вернул карту результата типа Map<Person,Future<String>> от моего getLotteryNumbers<Collection<Person>> оказание услуг.

Затем я бы вышел через карту и использовал Future.get() Чтобы получить либо номер лотереи, либо исключение.

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

В этом сценарии я возвращаю Future<Thing> Что ждет, пока результаты партии будут доступны с помощью CountdownLatch.

Взгляните на параллелизм Java на практике, чтобы увидеть, как эти компоненты могут работать вместе http://jcip.net/

Другим способом, особенно для систем с высокой пропускной способностью, будет использование дизайна на основе очередей, в которых обработка объекта будет выполнять операции на объекте, а затем на основе результатов. Поместите объект в разные очереди для дополнительной обработки другими объектами, а затем двигаться дальше. Анкет Это уменьшит узкие места, которые возникнут из -за дополнительной обработки, которая потребуется, например, обработка заказа для продуктов вне склада

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top