Как я могу версию рабочих процессов Cadence? - PullRequest
0 голосов
/ 19 апреля 2020

Рабочие процессы Cadence должны быть детерминированными c, что означает, что рабочий процесс должен давать точно такие же результаты, если он выполняется с теми же входными параметрами.

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

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

Это особенно важно в тех случаях, когда рабочие процессы могут работать в течение длительного времени, например, дней, недель или даже месяцы!

1 Ответ

0 голосов
/ 19 апреля 2020

По-видимому, это, вероятно, один из самых распространенных вопросов, которые задает новый разработчик Cadence. Рабочие процессы каденции должны быть детерминированными c алгоритмами . Если алгоритм рабочего процесса не детерминирован c, работники Cadence будут подвержены риску возникновения недетерминированных c рабочего процесса ошибок при попытке воспроизведения истории (ie. При восстановлении после сбоя работника).

Существует два способа решения этой проблемы:

  • Создание нового рабочего процесса : это самый наивный подход для управления версиями рабочих процессов. Подход настолько прост, насколько это звучит: в любое время, когда вам нужно внести изменения в алгоритм вашего рабочего процесса, вы делаете копию своего исходного рабочего процесса и редактируете его так, как хотите, присваиваете ему новое имя, например MyWorkflow_V2, и начинаете использовать для всех новых экземпляры идут вперед. Если ваш рабочий процесс не очень продолжителен, ваши рабочие процессы в какой-то момент «истощатся», и вы сможете полностью удалить старую версию. С другой стороны, этот подход может очень быстро превратиться в кошмар обслуживания по очевидным причинам.
  • Использование API GetVersion () для разветвления логи рабочего процесса c: у клиента Cadence есть функция с именем GetVersion, который сообщает вам, какая версия рабочего процесса запущена в данный момент. Вы можете использовать информацию, возвращаемую этой функцией, чтобы решить, какую версию алгоритма вашего рабочего процесса необходимо использовать. Другими словами, в вашем рабочем процессе работают как старый, так и новый алгоритмы, работающие бок о бок, и вы можете выбрать правильную версию для своих экземпляров рабочего процесса, чтобы обеспечить их детерминированную работу.

Ниже приведено пример подхода, основанного на GetVersion (). Предположим, вы хотите изменить следующую строку в вашем рабочем процессе:

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

на

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

Это серьезное изменение, так как вместо него выполняется действие bar Foo . Если вы просто внесете это изменение, не беспокоясь о детерминизме, ваши рабочие процессы не будут воспроизводиться, если они в этом нуждаются, и они застрянут с ошибкой nondeterministi c workflow . Правильный способ сделать это изменение правильно - это обновить рабочий процесс следующим образом:

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

Функция GetVersion принимает 4 параметра:

  • ctx - стандарт объект контекста
  • «fooChange» - это читаемый человеком ChangeID или семантичное c изменение, которое вы вносите в свой алгоритм рабочего процесса, который нарушает детерминизм
  • DefaultVersion - это константа, которая просто означает Версия 0 . Другими словами, самая первая версия. Он передается как параметр minSupportedVersion в функцию GetVersion
  • 1 - это maxSupportedVersion , который может обрабатываться текущим кодом рабочего процесса. В этом случае наш алгоритм может поддерживать версии рабочих процессов от DefaultVersion до Версия 1 (включительно).

Когда новый экземпляр этого рабочего процесса достигает GetVersion () Вызов выше в первый раз, функция вернет параметр maxSupportedVersion , чтобы вы могли запустить последнюю версию вашего алгоритма рабочего процесса. В то же время, он также запишет этот номер версии в историю рабочего процесса (внутренне известный как Marker Event ), чтобы он запомнился в будущем. При дальнейшем воспроизведении этого рабочего процесса клиент Cadence будет продолжать возвращать тот же номер версии, даже если вы передадите другой параметр maxSupportedVersion (ie. Если ваш рабочий процесс имеет еще больше версий).

Если вызов GetVersion обнаружен во время воспроизведения истории, и в истории нет события маркера, которое было зарегистрировано ранее, функция вернет DefaultVersion , при условии, что «FooChange» никогда не существовало в контексте этого экземпляра рабочего процесса.

В случае, если вам нужно сделать еще одно критическое изменение на том же шаге вашего рабочего процесса, вам просто нужно изменить приведенный выше код следующим образом:

v :=  GetVersion(ctx, "fooChange", DefaultVersion, 2) // Note the new max version
if v  == DefaultVersion {
   err = workflow.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else if v == 1 {
   err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else { // This is the Version 2 logic
   err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

Когда вы можете отказаться от поддержки Версия 0 , вы изменяете приведенный выше код следующим образом:

v :=  GetVersion(ctx, "fooChange", 1, 2) // DefaultVersion is no longer supported
if v == 1 {
   err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else { 
   err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

После этого изменения, если ваш код рабочего процесса выполняется для старого экземпляра рабочего процесса с DefaultVersion версия, клиент Cadence выдаст ошибку и остановит выполнение.

В конце концов, вы, вероятно, захотите избавиться от всех предыдущих версий и поддерживать только последнюю версию. Один из вариантов - просто избавиться от вызова GetVersion и оператора if в целом и просто иметь одну строку кода, которая делает правильные вещи. Однако на самом деле лучше оставить вызов GetVersion () по двум причинам:

  1. GetVersion () дает вам лучшее представление о том, что пошло не так, если ваш работник попытается воспроизвести историю старый экземпляр рабочего процесса. Вместо того чтобы исследовать причину root таинственной недетерминированной ошибки рабочего процесса c, вы будете знать, что причиной сбоя является управление версиями рабочего процесса в этом месте.
  2. Если вам нужно внести более серьезные изменения в на том же шаге алгоритма рабочего процесса вы сможете повторно использовать тот же идентификатор изменения и продолжить, следуя тому же шаблону, что и выше.

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

GetVersion(ctx, "fooChange", 2, 2) // This acts like an assertion to give you a proper error
err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...