Должен ли один сбой завершить массовую операцию?

11

В API, над которым я работаю, есть операция массового удаления, которая принимает массив идентификаторов:

["1000", ..., "2000"]

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

try{
savepoint = conn.setSavepoint();

for(id : IDs)
    if( !deleteItem(id) ){
        conn.rollback(savepoint);
        sendHttp400AndBeDoneWithIt();
        return;
    }

conn.commit();
}

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


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

Я пытался искать в Интернете некоторые рекомендации по этому вопросу, но я пришел с пустыми руками. Итак, я прихожу к вам: что больше всего ожидается от массовых операций такого рода? Должен ли я придерживаться более строгих правил или я должен быть более терпимым?

Рат
источник
9
Это зависит. Какова стоимость того, чтобы что-то не удалялось, когда это должно быть? (Стоимость определяется как плохие данные, головная боль, нежелательное поведение, время, необходимое администратору, чтобы исправить это и т. Д.) Это приемлемо? Если вы можете жить с последствиями, не потерпев неудачу во всем, пойти на это. Если это вызовет слишком много проблем, не надо. Вы знаете свое программное обеспечение и его последствия, поэтому вам придется позвонить в суд.
Becuzz
1
@Becuzz Стоимость будет такова, что пользователь заметит один или два остатка и откроет билет об этом; текущая ситуация: «Боже, удаление не работает». К счастью, пользователь идет по коридору, так что на этот раз это не слишком большая проблема. Дело в том, что мне нравится делать правильные вещи, когда это возможно, и с 10-летней кодовой базой, Бог знает, что некоторые вещи могут быть выполнены правильно
rath
Я думаю, это также зависит от того, хотите ли вы масштабируемости или нет. Если вы не собираетесь иметь много удостоверений личности, это не должно иметь большого значения. Если вы намереваетесь иметь миллион идентификаторов, или, что еще лучше, не совсем уверены, что это не произойдет, вы можете потратить час на удаление идентификаторов, чтобы полностью сбросить его из-за одного неверного идентификатора.
imnota4
1
@ imnota4 Отличный момент, который я не учел. Пользовательский интерфейс ограничивает запрос максимум около 250, но бэкэнд не имеет ограничений. Могу ли я попросить вас опубликовать свой комментарий в качестве ответа?
рат
1
Разрешительный режим также облегчает работу администраторов, поскольку им не нужно воспроизводить ошибки со всеми стопками идентификаторов. Также может быть полезно сообщить в ответе причину каждой ошибки. Рассматривая причину, конечный пользователь мог бы решить ее без заявок «omg delete not broken».
Laiv

Ответы:

9

Можно делать «строгую» или «красивую» версию конечной точки удаления, но вы должны четко сообщить пользователю, что произошло.

Мы делаем действие удаления с этой конечной точкой. Скорее всего DELETE /resource/bulk/или что-то подобное. Я не требователен Здесь важно то, что независимо от того, решите ли вы быть строгим или милым, вы должны точно сообщить, что произошло.

Например, API, с которым я работал, имел DELETE /v1/student/конечную точку, которая принимала массовые идентификаторы. Мы регулярно отправляли запрос во время тестирования, получали 200ответ и предполагали, что все в порядке, только чтобы потом выяснить, что все в списке все еще находились в базе данных (установлено на неактивное состояние) или фактически не были удалены из-за ошибки, которая испортил будущие звонки, GET /v1/studentпотому что мы получили данные, которые мы не ожидали.

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

В итоге, независимо от того, что вы делаете, убедитесь, что вы предоставляете способ сообщить конечному пользователю, что происходит и, возможно, почему это происходит. То есть, если мы выбрали строгий формат, ответ мог бы быть 400 - DELETE failed on ID 1221 not found. Если бы мы выбрали «хорошую» версию, это могло бы быть 207 - {message:"failed, some ids not deleted", failedids:{1221, 23432, 1224}}(извините мое плохое форматирование json).

Удачи!

Адам Уэллс
источник
6
207 Multi-Statusможет быть подходящим для этого частичного ответа на неудачу
Ричард Тингл
1
ТАМ МЫ ИДЕМ! Я не мог вспомнить! Я собираюсь обновить ответ, так как это на самом деле соответствует стандартам.
Адам Уэллс
2

Нужно быть строгим и разрешительным.

Обычно насыпные грузы разбиты на 2 этапа:

  • Проверка
  • загрузка

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

После проверки данных они загружаются. Обычно он загружается партиями, если он достаточно велик, чтобы избежать длительных транзакций, или в случае сбоя его будет легче восстановить. Размер пакета зависит от размера набора данных. Если у одной только несколько 1000 записей, одна партия будет в порядке. Здесь вы можете быть несколько осторожны со сбоями, но вы можете установить порог неудачного пакета, чтобы остановить всю операцию. Может быть, если [N] пакеты не удастся, можно будет остановить всю операцию (если сервер не работает или что-то подобное). Обычно в этот момент нет сбоев, потому что данные уже были проверены, но если это было связано с проблемами среды или другими причинами, просто перезагрузите пакет (ы), который не прошел. Это делает восстановление немного легче.

Джон Рейнор
источник
Я не проверяю идентификаторы по значениям БД, я просто пытаюсь удалить их и посмотреть, как это происходит, или это займет вечность. Aborting после N неудач , кажется , очень разумное предложение, +1
Рат
2

Должен ли один сбой завершить массовую операцию?

На это нет канонического ответа. Потребности и последствия для пользователя должны быть изучены и оценены компромиссы. ОП дал некоторую необходимую информацию, но вот как я буду действовать:

Вопрос 1 : «Каковы последствия для пользователя в случае неудачного удаления?»

Ответ должен вести остальную часть дизайна / реализованного поведения.

Если, как указано в OP, пользователь просто замечает исключение и открывает сообщение об ошибке, но в остальном не затрагивается (не удаленные элементы не влияют на последующие задачи), тогда я бы пошел с разрешением с автоматическим уведомлением тебе.

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

Предоставление пользователю возможности (например, по сути, флаг игнорирования сбоев со строгим или разрешающим по умолчанию) может быть наиболее удобным для пользователя подходом.

Вопрос 2 : «Возникнут ли какие-либо проблемы с согласованностью / согласованностью данных, если последующие задачи будут выполнены с не удаленными элементами, которые все еще находятся в хранилище данных?»

Опять же, ответ будет определять лучший дизайн / поведение. Да -> Строгий, Нет -> Разрешающий, Возможно -> Строгий или Выбранный пользователем (особенно, если от пользователя можно точно определить последствия).

Кристиан Х
источник
0

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

imnota4
источник
-1

Я бы сказал, что одним из важных моментов является то, что это означает, что большая часть материала будет удалена.

Эти идентификаторы как-то логически связаны, или это просто группировка для удобства / производительности?

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

Как говорится в другом ответе: В любом случае, сообщите «пользователю», что именно произошло.

Мартин Ба
источник