Недавно, когда я проводил свой первый в истории семинар для ZIO с замечательной командой в Scalac , у нас был шанс построить чисто функциональный автоматический выключатель с использованием ZIO Ref
, который представляет собой модель изменяемой эталонной модели, которую можно обновлять атомарно.
Автоматический выключатель защищает доступ к внешней службе, такой как база данных, сторонний API или микросервис. Как только слишком много запросов к сервису перестают работать, автоматический выключатель отключается и сразу же сбрасывает все запросы, пока автоматический выключатель не сможет сброситься.
Автоматические выключатели не только защищают внешние службы от перегрузки (давая им возможность восстановления после сбоя), но и помогают сохранить локальные ресурсы (такие как сокеты, потоки и т. П.), Которые в противном случае были бы потрачены впустую на потерю стоимости.
В отличие от политик повторов, которые определяют, как повторяются отдельные запросы, автоматические выключатели обмениваются глобальными знаниями в системе, поэтому различные волокна могут действовать более разумно и согласованно.
Автоматические выключатели часто моделируются как имеющие три состояния: разомкнутый, замкнутый и полуоткрытый. Логика автоматического выключателя (возможно, с помощью параметров конфигурации) отвечает за переход между состояниями на основе проверки состояния запросов.
На семинаре ZIO изучение различных возможностей автоматических выключателей дало мне понять: я действительно не люблю автоматические выключатели. Я нахожу произвольную природу числа состояний и условий переключения глубоко беспокоящими.
Я думаю, что мы можем сделать лучше, чем автоматические выключатели, и повеселиться, пока мы на этом! Итак, в этом посте я собираюсь поставить задачу для всех вас, поклонников функционального программирования в Scala: создать лучший автоматический выключатель!
Соревнование
Вместо автоматического выключателя я хочу, чтобы вы создали кран , который непрерывно регулирует поток запросов через кран.
Поток корректируется на основе наблюдаемых отказов, которые соответствуют требованиям (т. Е. Соответствуют определенному пользователем предикату).
Если вы хотите использовать ZIO для реализации Tap
, то ваш API должен соответствовать следующему интерфейсу:
Если вы хотите использовать Cats IO или Monix для реализации Tap
, тогда ваш API должен соответствовать следующему интерфейсу (или его полиморфному эквиваленту):
Ваша реализация Tap
должна удовлетворять следующему требованию:
Отвод должен непрерывно регулировать процент задач, которые он пропускает, пока не найдет максимальную скорость потока, которая удовлетворяет определенной пользователем максимальной границе ошибки.
Таким образом, если вы создаете tap
с максимальной частотой ошибок 1% , и внезапно 50% всех задач перестают tap
работать, то поток будет уменьшаться до тех пор, пока частота отказов не стабилизируется на уровне 1%.
По мере восстановления службы частота отказов упадет ниже 1 процента, что приведет к увеличению потока крана и пропуску большего количества задач.
Как только служба полностью восстановится, частота отказов достигнет 0 процентов (или в пределах некоторого расстояния от этой цели), и в этот момент касание пропустит все задачи.
Ваша реализация должна быть чисто функциональной и параллельной. Бонусные баллы за демонстрацию вашего знания примитивов параллелизма, таких как Ref
, Promise
( Deferred
) и так далее.
Победители
Основной причиной работы над этой задачей является поиск решений для параллелизма в функциональном Scala. Это забавный маленький проект, который проведет вас в большом туре по современным, чисто функциональным системам эффектов в Scala.
Тем не менее, я хочу дать вам немного дополнительной мотивации для работы над этой проблемой!
Если вы разместите свой код в Gist, чтобы весь мир мог учиться на вашем решении, тогда я буду продвигать ваше решение и куплю вам напиток в следующий раз, когда мы окажемся в одном городе!
Наконец, если ваше решение входит в тройку лучших, которые я получу в течение следующих двух недель, я свяжусь с вами в Linkedin и напишу краткое, честное подтверждение ваших навыков в функциональной Scala.
Готов? На ваших отметках, получить набор, иди!