Патчи Citeck
Патч - некоторая работа, которую нужно выполнить один раз после запуска системы. Патчи могут быть использованы для автоматической или ручной миграции.
Патчи Citeck - это артефакты с типом app/patch, которые подчиняются тем же правилам деплоя, что и остальные артефакты. Уникальность патча в пределах системы определяется по targetApp + id
Модель
id: String // идентификатор патча
name: MLText // имя патча
targetApp: String // целевое приложение где патч будет выполнен. По умолчанию - текущее приложение.
date: Instant // дата патча. Подробнее ниже.
manual: Boolean // ручной запуск патча. Если флаг равен true, то патч не будет выполнен автоматически.
dependsOn: String[] // зависимость от других патчей
type: String // тип патча
config: ObjectData // конфигурация патча
Типы патчей
Тип |
Конфигурация |
Описание |
---|---|---|
bean |
beanId: String - идентификатор бина для исполнения |
Запустить бин в контексте приложения.
Поддерживаются следующие интерфейсы:
|
delete |
records: RecordRef[] |
Удалить указанные записи |
mutate |
records: RecordAtts[]
record: RecordAtts
|
Произвести мутацию указанных записей;
Если в конфигурации указаны records, то используются они и поле record игнорируется;
Если в конфигурации не указаны records, то используется record.
|
Дата патча
Дата патча - это ISO8601 ZULU значение даты и времени (напр. 2022-01-01T00:00:00Z). Это время заполняется при создании патча вручную текущей датой. Точное соответствие времени не требуется, но желательно чтобы дата указывалась хотя бы с точностью до дней. Дата патча используется для нескольких вещей:
Для сортировки патчей. Патчи с меньшим временем будут исполняться раньше. Эта гарантия действует только для патчей в пределах одного приложения. Т.е. тогда когда мы описываем патчи в приложении, которые будут исполняться в рамках того же приложения. Для строгой зависимости нужно использовать поле dependsOn.
Для возможности управления исполнением патча. Решение о исполнении патча принимается на основе старого и нового значений даты:
Если старая_дата отсутствует (новый патч), то патч исполнится;
Если старая_дата >= новая_дата, то патч считается выполненным и не исполнится;
Если старая_дата < новая_дата, то патч считается обновленным и ставится в очередь на исполнение;
Таким образом, если мы хотим, чтобы уже сработавший патч перевыполнился при следующем обновлении, то мы просто увеличиваем время в date.
Использование в коде
Для описания патчей можно использовать аннотацию @EcosPatch
Для указания зависимостей можно использовать аннотацию @EcosPatchDependsOn
@Component
@EcosPatchDependsOn("other-patch")
@EcosPatch("test-patch", "2022-01-01T00:00:00Z")
class TestComponent : Callable<Any> {
override fun call(): Any {
println("Patch executed")
// Результат будет записан в БД ecos-apps, чтобы его можно было потом посмотреть.
// Из требований к результату - только возможность конвертации через Json.mapper.toString в json строку.
return "custom-result"
}
}
Stateful патчи
Для выполнения некоторой объемной работы можно использовать Stateful патчи (патчи с состоянием).
Их суть заключается в том, что при выполнении патча мы не делаем всю работу сразу, а выполняем некоторую часть работы, после чего возвращаем промежуточное состояние процесса.
Для реализации Stateful патча нужно реализовать интерфейс StatefulEcosPatch<Config>,
где Config - это произвольный тип, который представляет состояние выполнения.
Важно, чтобы инстанс этого класса можно было создать из пустого объекта ({}) т.к. это начальное состояние для патча.
Пример в коде:
@EcosPatch("stateful-patch", "2022-01-01T00:00:00Z")
class TestWithState : StatefulEcosPatch<ObjectData> {
override fun execute(state: ObjectData): PatchExecutionState<ObjectData> {
val counter = state.get("counter", 0) + 1
val completed = counter == 5
log.info { "Execute stateful patch. Counter: $counter, Completed: $completed" }
return PatchExecutionState(
ObjectData.create()
.set("counter", counter),
completed
)
}
}
Архитектура
Из приложения артефакты патчей попадают в ecos-apps по стандартному механизму деплоя артефактов и сохраняются в БД.
Далее ecos-apps периодически опрашивает таблицу патчей на наличие тех, которые можно применить (т.е. targetApp доступен и статус патча позволяет его применить).
Если патч для применения нашелся, то мы выполняем команду на выполнение патча и отправляем её в targetApp. Результат выполнения команды мы кладем в БД.
Если при выполнении патча возникла ошибка, то мы сохраняем эту ошибку в БД и через некоторое время повторяем попытку применить патч.