What is the best practice to design a Lifecycle workflow?

Hi Team,

Kindly let me know if there are any best practices to design a Lifecycle workflow.

As we have complex use cases to perform and the requirements can vary to the greater extent in the future as well. Can you please suggest a suitable design?

Basic requirements are,

  • The lifecycle workflow must stay active until a successful completion and should not get closed on an event of any exceptions
  • It performs a backup where it exports data from several different micro services and uploads it
  • It performs a cleanup of data which involves calling several REST APIs.

Designing in the way as shown in the snippet below, brings in lot of complexities to maintain the code.
Are there any alternatives to the inner loops to perform retry of a block in case of failures?

Below snippet has backup step as a child workflow and methods to perform cleanup put in the main workflow,
Please advice on when to go for a child workflow vs code to be part of main workflow?

  while (true) {
  try {
	if (state == null) {
		state = State.ACTIVE;
		// Wait for ever till mark for cleanup flag is set by a signal.
		Workflow.await(() -> markedForCleanup || forceCleanup);
		state = State.MARKED_FOR_CLEANUP;
	}

	// Perform Backup
	while (true) {

		// Trigger a backup child workflow
		boolean backupResult = backupChildWF.execute(envKey);

		if (backupResult) {
			break;
		} else {
			Workflow.sleep(Duration.ofDays(DEFAULT_SLEEP_FOR_RETRY));
			continue;
		}
	}	

	// Perform Cleanup
	while (true) {

		// This invokes activity methods within performCleanup
		boolean performCleanup = performCleanup(envKey);

		if (performCleanup) {
			break;
		} else {
			Workflow.sleep(Duration.ofDays(DEFAULT_SLEEP_FOR_RETRY));
			continue;
		}
	}

	// All done, close the workflow
	state = State.CLEANUP_COMPLETED;
	return;
  } catch (Exception e) {
	state = State.ATTEMPT_RETRY;
    continue;
  }
}
1 Like

Workflows change the way we should think about retries. Explicit retries of workflows are very rarely needed as they are to guard against bugs in your code, not from intermittent failures.

For example, why are you retrying the backup workflow? It is not expected to fail ever for retryable errors. It has to handle all of them itself. For activity failures, specify appropriate retry policies in activity options, eliminating need to retry them from the workflow code.

Even if you decide that retrying the whole workflow is a good idea (it is not) then you can specify retry policy when starting a child workflow and it is going to be retried automatically. So no need to retry it from the lifecycle workflow code.

Sometimes there is a need to retry a sequence of activities or even complex function that incorporates multiple activity and child workflow calls. In this case, retrying from the workflow code makes sense. But no need to write retry loops in this case as you can use built-in Workflow.retry function. See the fileprocessing sample for a valid application of this function.

Designing in the way as shown in the snippet below, brings in lot of complexities to maintain the code.

Even if all the above features weren’t available nothing prevents you from using the standard Java programming techniques to simplify your code. For example, you can always roll out your own version of a Retryer class that would allow providing a nice interface to retries. Or you can write some generic state machine class that would encapsulate all those error-prone assignments and awaits on specific states.

1 Like

Thank you so much!