Задачка от Жака Фреско, на решение дается тридцать минут.
Вам необходимо реализовать сервис, который существует в нескольких репликах и каждая реплика постоянно борется за лидерство. Реплика, которая становится лидером, должна каждые leader-timeout
секунд писать файл в директорию file-dir
а также удалять старые файлы, если количество файлов в директории больше, чем storage-capacity
. Для выбора лидера необходимо использовать эфемерные ноды ZooKeeper. Сервис должен представлять собой стейт машину, которая в зависимости от действий меняет свое состояние. Список состояний следующий:
Init
- Начинается инициализация, проверка доступности всех ресурсовAttempter
- Пытаемся стать лидером - раз вattempter-timeout
пытаемся создать эфемерную ноду в зукипереLeader
- Стали лидером, нужно писать файлик на диск(симуляция полезной деятельности)Failover
- Что-то сломалось, попытка приложения починить самого себяStopping
- Graceful shutdown - состояние, в котором приложение освобождает все свои ресурсы
stateDiagram-v2
[*] --> Init
Init --> Attempter : Инициализация успешна, начинаем
Init --> Failover : Произошел сбой, стал недоступен зукипер
Attempter --> Failover : Произошел сбой, стал недоступен зукипер
Leader --> Failover : Произошел сбой, стал недоступен зукипер
Attempter --> Leader : Смогли создать эфемерную ноду в зукипере
Init --> Stopping : Получили `SIGTERM`
Attempter --> Stopping : Получили `SIGTERM`
Leader --> Stopping : Получили `SIGTERM`
Failover --> Stopping : Получили `SIGTERM`
На данный момент реализован базовый скелет проекта. Ниже рассмотрены важные директории
.
├── README.md
├── cmd
│ └── election - тут расположен основной main из которого собирается основной бинарь
└── internal
├── commands - тут расположены хэндлеры кобра команд
│ └── cmdargs - тут расположены структуры для хранения аргументов кобра команд
├── depgraph - структура графа зависимостей - предоставляет DI контейнер с ленивой инициализацией
└── usecases - основные юзкейсы
└── run - юзкейс, который будет запускать стейт машину
└── states
└── empty - стейт для примера, в итоговом сервисе использоваться не должен
Конфигурирование проекта должно осуществляться с помощью флагов в командной строке, или с помощью переменных окружения, которые повторяют функциональность флагов. Название переменных получаем из названия флага, переводя его в верхний регистр, заменой всех знаков минуса на знак подчеркивания а также добавлением в начале названия бинарника в верхнем регистре. Пример: --some-flag
--> ELECTION_SOME_FLAG
.
Список необходимых настроек:
zk-servers
([]string
) - Массив с адресами зукипер серверов. Пример:--zk-servers=foo1.bar:2181,foo2.bar:2181
leader-timeout
(time.Duration
) - Периодичность записи лидером файлика на диск. Пример:--leader-timeout=10s
attempter-timeout
(time.Duration
) - Периодичность с которой атемптер пытается стать лидером. Пример:--attempter-timeout=10s
file-dir
(string
) - Директория, в которую лидер должен записывать файлики. Пример:--file-dir=/tmp/election
storage-capacity
(int
) - Максимальное количество файлов в директорииfile-dir
. Пример:--storage-capacity=10
- Наличие подробного логирования
- Архитектура, разбиение на слои
- Желательно наличие метрик
- Текущее состояние
- Время в текущем состоянии
- Количество изменений состояния
- Graceful shutdown
- Тестируемость - должна быть возможность протестировать любой слой кроме мейна и кобра команд. Особенно уделите внимание стейтам, в которых есть таймауты(например ожидание когда можно будет записать файл на диск или попытаться стать лидером). Подумайте насчет абстракции поверх стандартных таймеров