Workflow entry point methods must follow certain coding rules so that Cadence will be able to do its magic. You must code your workflow methods such that they are absolutely deterministic and repeatable. Your workflows must make the same decisions the first time it's invoked as it would if Cadence had to restart the workflow and replay operations from history to restore the workflow to its latest state.
You'll need to follow these rules:
Never reference static global propeties or methods whose values may change of the course of the workflow execution or that may change if the workflow is relocated from one machine to another. Use activtities instead for these. Activtities record their result to workflow history the first time they're called and return the same result from history on subsequent calls.
Never call non-deterministic methods that return things like GUIDs or random numbers directly from your workflow code. These will typically return different results on subsequent calls and this would break the workflow repeatability requirement. Instead, use methods like NewGuidAsync, NextRandomAsync or NextRandomBytesAsync. These methods ensure the result is recorded to history on the first call and returned from history on subseqent calls.
Never perform network, I/O, database or network operations directly from workflow code. These operations are generally not deterministic: network packets get lost, database content can change, REST APIs can be down or modified, and files can be modified or deleted out from under you. Perform these operations in activities so they'll be recorded to history.
Never use things like Now to obtain the current time and date. This is a variation of rule #1. This property will likely return a different value every time it's called. Use UtcNowAsync or call an activity.
Workflows must never create and execute additional tasks in parallel. You must immediately await all async methods in your workflow. Not doing this implicitly starts a parallel task and the completion order of tasks (or any multi-thread operation) is non-deterministic. You can run activities and child workflows in parallel though via NewActivityFutureStub and NewChildWorkflowFutureStubTWorkflowInterface.
Workflows must not execute code on new threads.
You'll need to take care when releasing updated workflow code because the history for workflows already in flight may not match up with the changed algorithm. You can use GetVersionAsync in your upgraded workflow to detect whether to implement the original algorithm for a workflow execution or to implement the new algorithm.
A workflow stub may only be used execute a single workflow entry point method. Reusing a stub will fail with an exception. The reason for this is that the stub will remain attached to the running workflow so that you can signal or query it by calling signal or query methods.
Activity stubs work differently, these do allow you to reuse a stub by allowing calls to multiple activity methods. This makes sense because activities don't have anything equivalent to signals or queries.