Это же элементарно, Ватсон. Неужели вы никогда не подключались к существующему проекту? Обилие таких нюансов ни разу не идёт на пользу скорости погружения нового человека в проект
Отличный пример, но читаемость ни разу не выросла. На code review я за такое бью по рукам.
Тернарное выражение
>> # Вместо этого:
>> if got_even_number():
... state = "Even"
... else:
... state = "Odd"
...
>> # Характерный для Python способ:
>> state = "Even" if got_even_number() else "Odd"
Тернарный оператор — очень скользкая дорожка. Чаще я сталкиваюсь с таким:
state = "Long description in case of `got_even_number` returns 1" \
if got_even_number() else \
"Another long description used when `got_even_number` returns 0"
В данном примере обычный if предпочтительнее. А ещё лучше обойтись вообще без if:
states = (
"Another long description used when `got_even_number` returns 0",
"Long description in case of `got_even_number` returns 1",
)
number = got_even_number()
state = states[number]
И после этого "Linux это не система, а ворох разнородных поделок, смотанных изолентой". То ли дело windows — сам разберись, какой dll не хватает, сам скачай её с варезника, сам подкинь. Просто, понятно, логично
Это не упрощение. Это усложнение — лишний слой абстракции, скрывающий под капотом реальные аргументы команды. За это придется платить.
Всё смешалось: люди, кони. Речь идёт о предоставлении единого интерфейса к разным сервисам — или упрощении интерфейса. Был ли упрощён интерфейс? Был.
Ценой чего был упрощён интерфейс? Верно, ценой абстракции — усложнения реализации
А вот мысль "За это придется платить." прошу пояснить: за годы работы в саппорте понял, что игра в угадайку — неблагодарное занятие
По сути, мысль можно свести к следующему...
По сути, так любую здравую мысль можно свести к абсурду. Гротеск такой гротеск.
C-программисты — в make, Java — в maven goal, JS — в scripts в package.json, а питонисты пусть для manage.py модули пишут.
Перевожу на русский язык: "я не знаю, зачем нужен make, maven, package.json и manage.py, но соберу в одну кучу и покажу, какой я дофига умный". Возможно, повезёт в следующий раз
Только вот под лишним слоем абстракции всегда теряется понимание внутренних процессов и во время траблшутинга наступает час расплаты… Я уже это в мире Windows видел, где люди управляют серверами мышкой и не отдупляют, что у них вообще происходит.
И снова всё смешалось. Абстракция не есть сокрытие реализации, и сравнение с Windows ошибочно.
А давайте откажемся от файловых систем — они скрывают реализацию хранения данных на носителях. Давайте к каждому носителю обращаться напрямую — ведь за слои абстракций над носителями приходится платить! Давайте обращаться к цилиндрам на HDD. К чёрту файловые системы — эти абстракции так легко рушатся, а при траблшутинге никто дупля не отрезает, что на самом деле происходит и где на самом деле данные хранятся на диске
Вы прослушали миниатюру "Гротеск". Или, может, не всё ли равно, как носители работают внутри, если нам важен интерфейс — хранилище?
Выводы:
Абстракции не всегда есть "зло, за которое придётся платить"
Абстракции хороши, будучи применёнными к месту и в нужном объёме
В самом начале, как раз, указан пример требований (очередь с приоритетом и отложенным перезапуском не обработанных из-за исключений задач) и отмечены ограничения применимости.
Тут следует оговориться: я щупал MQ только через API Celery (по ссылке выше его кстати отнесли к MQ, хотя формально он пользователь MQ): https://github.com/kai3341/celery-pool-asyncio/blob/master/celery_pool_asyncio/executors.py#L108
Из всего этого важно: accept_callback, callback (on_success), timeout_callback, error_callback. Всё это позволяет в полном объёме обработать исключения. API Celery также умеет в отложенную доставку.
сколько в этой очереди новых задач и сколько повторных?
Смотрю в DEBUG-лог Celery. Перед попаданием таски в пул в stdout печатается само сообщение. Там фигурирует 'retries': 0. Здесь тело интересующего нас сообщения инкапсулировано в структуру, передающую также метаданные.
Тогда давайте разделим очередь на две: в одну пишем новые, в другую — упавшие с задержкой. Отлично. Как теперь балансировать нагрузку на воркеры? 50% на новые, 50% на упавшие? А если упавших мало, то 50% мощностей будут простаивать? Брать задачи из каждой очереди по очереди?
Если мне не изменяет память, о балансировке рассказывал Олег Чуркин в докладе "50 оттенков Celery".
Как узнать, какие основные причины, по которым задачи попадают в очередь упавших? Ну, наверное, надо логи погрепать…
Ну помимо логов, в error_callback передаётся также информация об ошибке
А как быть уверенным, что в очереди находятся действительно все упавшие задачи, и какая-то не потерялась?
В этом смысл accept_callback, success_callback и error_callback. Все они предназначены в том числе и для отслеживания выполнения задач
А зачем нам тогда очередь, если у нас уже есть таблица с задачами
Допустим, Вы решаете задачу электрификации. Для того, чтобы провести линию в некий удалённый посёлок, нужно очистить площадь от деревьев, поставить столбы, на них поставить изоляторы, и уже на изоляторы положить кабель. Очистка территории от леса дело дорогое, столбы тоже дорогие. И тут вам приходит светлая мысль: А зачем нам вырезать деревья и после ставить столбы, если можно прикрутить изоляторы прямо к деревьям?
Мораль грузинский басня прост: из схожести интерфейсов не следует, что одно решение можно заменить другим.
Эти программисты так любят что-то менять в БД, они что, не понимают, что при этом каждый раз создаётся новая запись?! Давайте им запретим.
Ближайший аналог — конкатенация иммутабельных строк в python. Вам никто не запрещает выполнять их конкатенацию в цикле. Только вычислительная сложность под капотом выходит O(N!). А что пользователи? Подождут, куда денутся
активно используется ActiveMQ. И её использование в некоторых случаях не соответствует эксплуатационным требованиям
Ну так не используйте её в этих некоторых случаях.
Краткое содержание:
Статья "как плохо решить задачу неподходящими инструментами"
Комментарий "Оно просто не работает как очередь задач (MQ), потому как не соответствует требованиям MQ"
Ответ: "а тот факт, что оно не выполняет возложенных задач, никак не относится к статье"
От себя добавлю, что выбор постгреса в качестве очереди задач (помимо того, что решение попросту неэффективно) крайне неудачен ввиду особенностей реализации MVCC: постгрес на каждый update создаёт новую запись. Режим работы — минимум 1 update для каждой записи.
Прекратите собирать троллейбус из буханки хлеба, и после с умным видом рассказывать о корректности использования ржаного хлеба. Умные люди уже придумали, как правильно решать такие задачи
Изюминка ситуации в том, что в моём текущем проекте заказчик настоял на использовании БД (постгрес) в качестве резервной очереди задач. И я реализовал нечто подобное.
Разница в том, что с самого начала я знал, что творю маразм
Статья в духе "я продолжаю начинать изучать программирование". Автор копнул глубоко — в дизассемблер байткода, и в то же время безумно поверхностно:
Не рассмотрены generator expressions
Выбор между map и list/generator expression определяется в первую очередь сложностью обработки каждого элемента. Одно дело, если каждый элемент надо возвести в квадрат, и совсем другое дело, если для каждого элемента нужно сходить в базу, потом в сторонний сервис, а ещё это залогировать
Ознакомился. В проекте взаимодействуют 2 разных инстанса Celery, каждый со своим изолированным набором тасок. Прямо вот в этом месте dramatiq и huey с их глобальным app становятся непригодными
Годик поработайте на одном проекте с таким подходом — станете совсем иначе воспринимать этот "оверхед"
Это же элементарно, Ватсон. Неужели вы никогда не подключались к существующему проекту? Обилие таких нюансов ни разу не идёт на пользу скорости погружения нового человека в проект
Конечно приемлим. Здравый смысл? Не, не слышал.
Отличный пример, но читаемость ни разу не выросла. На code review я за такое бью по рукам.
Тернарный оператор — очень скользкая дорожка. Чаще я сталкиваюсь с таким:
В данном примере обычный
if
предпочтительнее. А ещё лучше обойтись вообще безif
:Нет, серьёзно, когда приложение лезет в БД, результаты бенчмарков сильно меняются
Конечно не нужна. Поэтому там из коробки пулы prefork, eventlet и gevent, и внешним пакетом был реализован пул treadpoolexecutor.
not a chance :)
ммм, ссылки на статьи почти десятилетней давности подъехали
И после этого "Linux это не система, а ворох разнородных поделок, смотанных изолентой". То ли дело windows — сам разберись, какой dll не хватает, сам скачай её с варезника, сам подкинь. Просто, понятно, логично
Всё смешалось: люди, кони. Речь идёт о предоставлении единого интерфейса к разным сервисам — или упрощении интерфейса. Был ли упрощён интерфейс? Был.
Ценой чего был упрощён интерфейс? Верно, ценой абстракции — усложнения реализации
А вот мысль "За это придется платить." прошу пояснить: за годы работы в саппорте понял, что игра в угадайку — неблагодарное занятие
По сути, так любую здравую мысль можно свести к абсурду. Гротеск такой гротеск.
Перевожу на русский язык: "я не знаю, зачем нужен make, maven, package.json и manage.py, но соберу в одну кучу и покажу, какой я дофига умный". Возможно, повезёт в следующий раз
И снова всё смешалось. Абстракция не есть сокрытие реализации, и сравнение с Windows ошибочно.
А давайте откажемся от файловых систем — они скрывают реализацию хранения данных на носителях. Давайте к каждому носителю обращаться напрямую — ведь за слои абстракций над носителями приходится платить! Давайте обращаться к цилиндрам на HDD. К чёрту файловые системы — эти абстракции так легко рушатся, а при траблшутинге никто дупля не отрезает, что на самом деле происходит и где на самом деле данные хранятся на диске
Вы прослушали миниатюру "Гротеск". Или, может, не всё ли равно, как носители работают внутри, если нам важен интерфейс — хранилище?
Выводы:
Правда чтоль? https://en.wikipedia.org/wiki/Message_queue#See_also
И правда, ни одного готового хорошего инструмента
Тут следует оговориться: я щупал MQ только через API Celery (по ссылке выше его кстати отнесли к MQ, хотя формально он пользователь MQ):
https://github.com/kai3341/celery-pool-asyncio/blob/master/celery_pool_asyncio/executors.py#L108
Из всего этого важно: accept_callback, callback (on_success), timeout_callback, error_callback. Всё это позволяет в полном объёме обработать исключения. API Celery также умеет в отложенную доставку.
Смотрю в DEBUG-лог Celery. Перед попаданием таски в пул в stdout печатается само сообщение. Там фигурирует
'retries': 0
. Здесь тело интересующего нас сообщения инкапсулировано в структуру, передающую также метаданные.Если мне не изменяет память, о балансировке рассказывал Олег Чуркин в докладе "50 оттенков Celery".
Ну помимо логов, в error_callback передаётся также информация об ошибке
В этом смысл accept_callback, success_callback и error_callback. Все они предназначены в том числе и для отслеживания выполнения задач
Допустим, Вы решаете задачу электрификации. Для того, чтобы провести линию в некий удалённый посёлок, нужно очистить площадь от деревьев, поставить столбы, на них поставить изоляторы, и уже на изоляторы положить кабель. Очистка территории от леса дело дорогое, столбы тоже дорогие. И тут вам приходит светлая мысль: А зачем нам вырезать деревья и после ставить столбы, если можно прикрутить изоляторы прямо к деревьям?
Мораль грузинский басня прост: из схожести интерфейсов не следует, что одно решение можно заменить другим.
Ближайший аналог — конкатенация иммутабельных строк в python. Вам никто не запрещает выполнять их конкатенацию в цикле. Только вычислительная сложность под капотом выходит O(N!). А что пользователи? Подождут, куда денутся
Ну так не используйте её в этих некоторых случаях.
Краткое содержание:
Статья "как плохо решить задачу неподходящими инструментами"
Комментарий "Оно просто не работает как очередь задач (MQ), потому как не соответствует требованиям MQ"
Ответ: "а тот факт, что оно не выполняет возложенных задач, никак не относится к статье"
От себя добавлю, что выбор постгреса в качестве очереди задач (помимо того, что решение попросту неэффективно) крайне неудачен ввиду особенностей реализации MVCC: постгрес на каждый update создаёт новую запись. Режим работы — минимум 1 update для каждой записи.
Прекратите собирать троллейбус из буханки хлеба, и после с умным видом рассказывать о корректности использования ржаного хлеба. Умные люди уже придумали, как правильно решать такие задачи
Изюминка ситуации в том, что в моём текущем проекте заказчик настоял на использовании БД (постгрес) в качестве резервной очереди задач. И я реализовал нечто подобное.
Разница в том, что с самого начала я знал, что творю маразм
В детстве меня пугали бабайкой. Сейчас пугают O(N^2). Интересно, что не было ни бабайки, ни O(N^2)
Статья в духе "я продолжаю начинать изучать программирование". Автор копнул глубоко — в дизассемблер байткода, и в то же время безумно поверхностно:
Спасибо.
PS: О, его отмодерировали
Неа, эту проблему решает просто внешний шедулер, и стандартного хватит. Когда появляется слово «динамика», стандартный шедулер уходит в закат
А за библиотечки спасибо — celery-redbeat выглядит поприятнее, чем redisbeat. python-redis-lock интересен тем, что он идёт в поставке с celery-redbeat
А обработку ошибок я в примерах и предложил направить в метод task. Разве что всё под рукой — в базовом классе, а не снаружи