Как вносить изменения или исправления в Uber Cadence Workflow, не нарушая детерминизм?

Какова рекомендуемая практика для обновления запущенных рабочих процессов?

Если уже есть запущенные исполнения, созданные с использованием предыдущей реализации рабочего процесса, то любое изменение кода или обновление логики рабочего процесса приводит к "Недетерминированной ошибке" из Cadence, поскольку он не может воспроизвести историю для существующих выполнений рабочего процесса с использованием обновленной реализации.

Каковы некоторые стратегии, чтобы иметь дело с обновлениями, не нарушая существующие рабочие процессы?

1 ответ

Решение

GetVersion используется для безопасного внесения обратно несовместимых изменений в определения рабочих процессов. Не разрешается обновлять код рабочего процесса, пока рабочие процессы выполняются, поскольку это нарушит детерминизм. Решение состоит в том, чтобы иметь как старый код, который используется для воспроизведения существующих рабочих процессов, так и новый, который используется при его первом запуске. GetVersion возвращается maxSupported версия, когда выполняется впервые. Эта версия записывается в историю рабочего процесса как событие маркера. Даже если maxSupported версия изменена, версия, которая была записана, возвращается при воспроизведении. DefaultVersion константа содержит версию кода, которая ранее не была версионной. Например, изначально рабочий процесс имеет следующий код:

err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)

это должно быть обновлено до

err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)

Обратно совместимый способ выполнить обновление

v :=  GetVersion(ctx, "fooChange", DefaultVersion, 1)
if v  == DefaultVersion {
    err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
}

Затем бар должен быть изменен на баз:

v :=  GetVersion(ctx, "fooChange", DefaultVersion, 2)
if v  == DefaultVersion {
    err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else if v == 1 {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

Позже, когда нет рабочих процессов, выполняющих DefaultVersion, соответствующая ветвь может быть удалена:

v :=  GetVersion(ctx, "fooChange", 1, 2)
if v == 1 {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

В настоящее время не существует поддерживаемого способа полного удаления вызова GetVersion после его появления. Сохраните его, даже если останется одна ветка:

GetVersion(ctx, "fooChange", 2, 2)
err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)

Необходимо как GetVersion выполняет проверку версии по истории рабочего процесса и не принимает решения, если код рабочего процесса не совместим с ней.

У Java есть подобный API Workflow.getVersion.

Другие вопросы по тегам