В больших проектах чаще нужно думать "а так ли нужна эта интеграция или можно как-то иначе?" и "отказоустойчивость в 95% в конкретном случае - это нормально?"
Ведь часто интеграции не нужны, а достижение 100% отказоустойчивости стоит дороже, чем проблемы, возникающие при 95%.
Недельный перерыв и уменьшение нагрузки были согласованы и спланированы, конечно.
Еще на старте было понятно, что мы будем уставать в таком ритме и нужно сбавлять темп к концу такого забега.
И да, вы правы — гнать в конце уже не так эффективно, с учётом того что образовательные активности сезонны и эксперимент ограничен временем.
Спасибо за MessageBus и ADR, интересно было почитать — там еще кучка разных интересных постов, включая reddit.
Быть может, что-нибудь да переведу, один пост уже, как оказалось, хорошо переведен JustRoo — https://habrahabr.ru/post/260769/
Так как внизу довольно бурное обсуждение про запрет и разрешение наркоты, отвечу сюда, чтоб оно просто было повыше, а не внизу.
Для усиления эффекта можно сначала почитать комментарии ниже, а потом уже посмотреть видео :)
С чего более разумным? Более разумным будет, если после коллекции будет идти идентификатор сущности из этой коллекции, а не совершенно левая по отношению к этому списку сущность или их коллекция.
Повторюсь, что я имел в виду только лишь само название итогового URI и его интерпретацию с точки зрения разработки, ни о каком явном применении речи не шло. Так как ну по сути своей, разницы между /users?filter={some-filter-name-or-id} и GET /userfilter/{id}/users нет никакой.
Но мне в любом случае непонятна такая логика, когда у фильтра что-то есть дочернее. Может, у нас разные понятия фильтров или я чего-то не знаю из реализации проекта.
Где конкретно два запроса, с юзерфильтрами? why not? Мое замечание было лишь по поводу того, что название ресурса было не совсем логичным.
Если система создана с условием, что пользователи системы могут создавать пользовательские фильтры и сохранять их, например, какая-нибудь там финансовая система с фильтром финансовых показателей по куче полей — решили прикрутить фичу «сохранить фильтр под названием», то пусть, никто не запрещает. Только тогда логика должна быть такая, что есть несколько ресурсов — фильтры и список финансовых показателей, т.е. какие-нибудь там /filters и /finance-results
Делаете POST на /filters с теми полями, которые вам разрешил сервер, получаете например имя фильтра или его id в случае успешного создания или 400 ошибку в случае плохого. Впоследствии, фильтр можно будет изменить по запросу PUT/PATCH /filters/{filter-id-or-name}. И там уже снова, либо шибки валидации, либо 404, в случае, когда фильтр с таким названием или идентификатором не найден.
Затем варианта два с половиной:
— Либо делаем просто GET /finance-results и получаем например первые 10 записей сверху
— Либо делаем запрос типа GET /finance-results?filter={filter-id-or-name}, который уже применяет фильтр, указанный пользователем в запросе.
— Если же вдруг по каким-то причинам фильтра не существует, или клиент указал неправильное название фильтра — там уже на усмотрение тех, кто создает систему, но я бы вернул либо пустой список, либо ошибку, что фильтра не существует, вот и все.
Если же вопрос про два запроса был про гугл… Не знаком с Google BigQuery, но в таком сценарии, как вы описываете, ничего плохо я, опять же, не вижу.
Формально, в данном случае, вы создаете сущность Job с неким query и возвращает он вам также Job (только в случае успешной валидации), только по мере обработки этой сущности, Job либо заполнен остальными полями (результат выполнения Query), либо нет. Если же создание Job не прошло валидацию, состояния никакого здесь нет — просто вернул список ошибок и все, клиент при этом может делать все что угодно, но логичным действием, конечно же, будет новый запрос на создание Job с исправлениями (а не запрос на какой-нибудь адрес проверки статуса Job, который не создан), и гугл снова его независимо от других запросов на создание его провалидирует.
Затем вы успешно создали валидное задание с каким-то запросом для гугла. Гугл в своей очереди эти запросы выполняет и ему в общем-то, плевать кто конкретно создал этот Job и правильный ли в этом Job указан query, вернет ли он что-то или же нет, ему также не требуется никаких знаний о предыдущих и будущих запросах.
Я понял про что вы, но состояния здесь нет. Это аналогично примеру выше, с постом и комментами.
Если мы не создадим фильтр (сервер вернул ошибку при создании), то и второго запроса быть не должно, вот и все.
Нет разницы между успешным созданием поста и отправкой на него комментария через секунду и отправкой комментария через год — что в первом, что во втором случае между созданием поста и отправкой комментария не возникнет состояния, это будет 2 (с постом 3) абсолютно независимых запроса.
Эмм?
Вас почти ничего не спасет от изменения списка при фильтрации пользователей, на то он и список, чтобы изменяться и идемпотентность GET тут не причем, тем более что идемпотентность имеет несколько другой смысл (отсутствие любых сайд-эффектов), а не просто «сделал запрос и получил всегда абсолютно идентичный предыдущему запросу ответ».
Под почти ничего имею в виду использование в запросе временных границ, которые каким-либо образом ограничивают выборку новых записей. Старые записи, конечно же, могут пропасть.
Да и каким образом это близко к нарушению stateless?
— на метод логина отправляем данные (по сути это не логин, а создание нового токена, POST /tokens, если удобно).
— проверяем логин-пароль, если все ок — отдаем сущность нового токена, которым затем подписываем каждый запрос.
— при последующих запросах просто проверяем наличие переданного в запросе токена где-либо и достаем из токена идентификатор пользователя — это не ломает stateless, токен такая же сущность, что и статья и другие, и если они не найдены — возвращаем ошибку, либо работаем с ними, если все ок.
— чтобы сделать логаут — DELETE /tokens/{token}
Так популярно и пусть.
Это же не отменяет того, что я написал выше — нет смысла делать что-то, из чего это сделать напрямую нельзя.
Путаница — может быть, я уже понял это исходя из диалога. Проблема — пока не вижу её из того, что вы пишете относительно «как в рамках рестфул реализовать привычную сессионную аутентификацию, когда клиент один раз отправляет..»
В больших проектах чаще нужно думать "а так ли нужна эта интеграция или можно как-то иначе?" и "отказоустойчивость в 95% в конкретном случае - это нормально?"
Ведь часто интеграции не нужны, а достижение 100% отказоустойчивости стоит дороже, чем проблемы, возникающие при 95%.
Еще на старте было понятно, что мы будем уставать в таком ритме и нужно сбавлять темп к концу такого забега.
И да, вы правы — гнать в конце уже не так эффективно, с учётом того что образовательные активности сезонны и эксперимент ограничен временем.
А можете вот это чуть больше раскрыть? Интересно. И да — спасибо за статью.
Быть может, что-нибудь да переведу, один пост уже, как оказалось, хорошо переведен JustRoo — https://habrahabr.ru/post/260769/
upd: протупил, и так же видно стату с 12 года и далее..)
Для усиления эффекта можно сначала почитать комментарии ниже, а потом уже посмотреть видео :)
http://www.ted.com/talks/johann_hari_everything_you_think_you_know_about_addiction_is_wrong
Но мне в любом случае непонятна такая логика, когда у фильтра что-то есть дочернее. Может, у нас разные понятия фильтров или я чего-то не знаю из реализации проекта.
Если система создана с условием, что пользователи системы могут создавать пользовательские фильтры и сохранять их, например, какая-нибудь там финансовая система с фильтром финансовых показателей по куче полей — решили прикрутить фичу «сохранить фильтр под названием», то пусть, никто не запрещает. Только тогда логика должна быть такая, что есть несколько ресурсов — фильтры и список финансовых показателей, т.е. какие-нибудь там /filters и /finance-results
Делаете POST на /filters с теми полями, которые вам разрешил сервер, получаете например имя фильтра или его id в случае успешного создания или 400 ошибку в случае плохого. Впоследствии, фильтр можно будет изменить по запросу PUT/PATCH /filters/{filter-id-or-name}. И там уже снова, либо шибки валидации, либо 404, в случае, когда фильтр с таким названием или идентификатором не найден.
Затем варианта два с половиной:
— Либо делаем просто GET /finance-results и получаем например первые 10 записей сверху
— Либо делаем запрос типа GET /finance-results?filter={filter-id-or-name}, который уже применяет фильтр, указанный пользователем в запросе.
— Если же вдруг по каким-то причинам фильтра не существует, или клиент указал неправильное название фильтра — там уже на усмотрение тех, кто создает систему, но я бы вернул либо пустой список, либо ошибку, что фильтра не существует, вот и все.
Если же вопрос про два запроса был про гугл… Не знаком с Google BigQuery, но в таком сценарии, как вы описываете, ничего плохо я, опять же, не вижу.
Формально, в данном случае, вы создаете сущность Job с неким query и возвращает он вам также Job (только в случае успешной валидации), только по мере обработки этой сущности, Job либо заполнен остальными полями (результат выполнения Query), либо нет. Если же создание Job не прошло валидацию, состояния никакого здесь нет — просто вернул список ошибок и все, клиент при этом может делать все что угодно, но логичным действием, конечно же, будет новый запрос на создание Job с исправлениями (а не запрос на какой-нибудь адрес проверки статуса Job, который не создан), и гугл снова его независимо от других запросов на создание его провалидирует.
Затем вы успешно создали валидное задание с каким-то запросом для гугла. Гугл в своей очереди эти запросы выполняет и ему в общем-то, плевать кто конкретно создал этот Job и правильный ли в этом Job указан query, вернет ли он что-то или же нет, ему также не требуется никаких знаний о предыдущих и будущих запросах.
Всё просто — получил, выполнил, вернул.
Если мы не создадим фильтр (сервер вернул ошибку при создании), то и второго запроса быть не должно, вот и все.
Нет разницы между успешным созданием поста и отправкой на него комментария через секунду и отправкой комментария через год — что в первом, что во втором случае между созданием поста и отправкой комментария не возникнет состояния, это будет 2 (с постом 3) абсолютно независимых запроса.
Вас почти ничего не спасет от изменения списка при фильтрации пользователей, на то он и список, чтобы изменяться и идемпотентность GET тут не причем, тем более что идемпотентность имеет несколько другой смысл (отсутствие любых сайд-эффектов), а не просто «сделал запрос и получил всегда абсолютно идентичный предыдущему запросу ответ».
Под почти ничего имею в виду использование в запросе временных границ, которые каким-либо образом ограничивают выборку новых записей. Старые записи, конечно же, могут пропасть.
Да и каким образом это близко к нарушению stateless?
GET /users?filter=some-filter-name-or-id
VolCh на токенах ситуация примерно аналогичная
— на метод логина отправляем данные (по сути это не логин, а создание нового токена, POST /tokens, если удобно).
— проверяем логин-пароль, если все ок — отдаем сущность нового токена, которым затем подписываем каждый запрос.
— при последующих запросах просто проверяем наличие переданного в запросе токена где-либо и достаем из токена идентификатор пользователя — это не ломает stateless, токен такая же сущность, что и статья и другие, и если они не найдены — возвращаем ошибку, либо работаем с ними, если все ок.
— чтобы сделать логаут — DELETE /tokens/{token}
Это же не отменяет того, что я написал выше — нет смысла делать что-то, из чего это сделать напрямую нельзя.
Путаница — может быть, я уже понял это исходя из диалога. Проблема — пока не вижу её из того, что вы пишете относительно «как в рамках рестфул реализовать привычную сессионную аутентификацию, когда клиент один раз отправляет..»