Патч ECOS - это некоторая работа, которую нужно выполнить один раз после запуска системы.
Патчи могут быть использованы для автоматической или ручной миграции.
Патчи ECOS - это артефакты с типом 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 патча нужно реализовать интерфейс 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. Результат выполнения команды мы кладем в БД.
Если при выполнении патча возникла ошибка, то мы сохраняем эту ошибку в БД и через некоторое время повторяем попытку применить патч.