Which is the best way to design a Subscription Lifecycle workflow? Having several signals inside one workflow or to have small workflows?

Hi Team,

I am designing and subscription lifecycle workflow which solves lots of use cases like waiting until expiry and notifying and deleting subscription.

I am using workflow signals to modify or alter the processing of lifecycle incase of force termination or altering subscription end date etc.,

There are few other logic including Tier or Channel conversion and other additional use cases which may not alter the lifecycle but needs persisting application tables.

Is it good to include scenarios in a single lifecycle workflow or to have small workflows performing additional stuffs related to subscription?

Small snippet of code for reference,

`public class SubscriptionWorkflowImpl implements SubscriptionWorkflow {

TierConversionMessage tier;
boolean wakeUpTimeUpdated;
boolean tierConversion;
boolean terminationRequested;
private long wakeUpTime;
int gracePeriodInDays;
boolean convertToPaid;

@SignalMethod
public void convertTier(TierConversionMessage request) {
	tierConversion = true;
	tier = request;
}

@SignalMethod
public void forceCleanup() {
	terminationRequested = true;
}

@SignalMethod
public void convertToPaid() {
	convertToPaid = true;
}

public void execute(SubscriptionMessage subscription) {

	this.wakeUpTime = subscription.getEndDate();

	while (true) {
		Duration sleepInterval = Duration.ofMillis(this.wakeUpTime - Workflow.currentTimeMillis());

		Workflow.await(sleepInterval, () -> signalled());

		if (terminationRequested) {
			activities.performForceCleanup(customerId);
			// This marks end of lifecycle
		} else if (wakeUpTimeUpdated) {
			activities.alterSubscriptionEndDate(customerId, newTime);
			continue;
		} else if (tierConversion) {
			activities.convertTier(customerId, tier);
			continue;
		} else if (convertToPaid) {
			activities.upgradeFromTrialToPaid(customerId);
			continue;
		} else {
			activities.performProductExpiry(subscription);
		}

		// Wait for grace period to expire and go ahead with termination
		Duration gracePeriodEndDate = Duration.ofMillis(subscription.getEndDate().getTime())
				.plus(Duration.ofDays(gracePeriodInDays));

		Workflow.await(gracePeriodEndDate, () -> signalled());

		if (terminationRequested) {
			activities.performForceCleanup(customerId);
			// This marks end of lifecycle
		} else if (wakeUpTimeUpdated) {
			activities.alterSubscriptionEndDate(customerId, newTime);
			continue;
		} else if (tierConversion) {
			activities.convertTier(customerId, tier);
			continue;
		} else if (convertToPaid) {
			activities.upgradeFromTrialToPaid(customerId);
			continue;
		} else {
			activities.performForceCleanup(customerId);
		}
	}
}`

I would start from a single workflow as it allows to share data easily between different parts. In your case, you can change all these boolean flags to an enum and use switch statement. Also don’t repeat that logic twice, move it into a separate method.

If your subscription can last for a long time we recommend calling continue as new periodically to avoid unbounded growth of the workflow execution history. See how HelloPeriodic sample does it.

2 Likes