0

I have a complicated review application submission process that does several steps.

ReviewService.CreateReview()

  • CheckReservedTimeslotIsAvailable
  • ProcessPayment
  • CreateMeeting
  • InsertReview
  • UpdateFinancialJournal
  • FinalizeDocuments
  • Notify

All these steps are coded inside the CreateReview() method and is becoming un-readable, hard to manage. Also the current implementation doesn't have the support of rollbacks.

So the idea is to create an Orchestrator class and build the sequence of steps. The orchestrator ensures a successful review is created if all steps are completed. If any of the step fails to complete then all of the completed preceding functions are rolled back to ensure data integrity. This is pretty much the same as Saga pattern (Orchestrated) but with slight change the steps are not micro services.

Is this the right pattern to use? Or Command pattern would be a good option? Please advise.

BaseOrchestrator ... using System; using System.Collections.Generic;

/// <summary>
/// Facilitates runnning of the pipeline operations.
/// </summary>
/// <typeparam name="T">The type of object orchestrator is executed on.</typeparam>
public abstract class BaseOrchestrator<T> : IOrchestrator<T>
{
    protected T data;

    protected List<Action> Steps;

    protected int rejectReason;

    public BaseOrchestrator<T> Begin(Action stepToExecute)
    {
        RegisterStepToExecute(stepToExecute);
        return this;
    }

    public BaseOrchestrator<T> Step(Action stepToExecute)
    {
        RegisterStepToExecute(stepToExecute);
        return this;
    }

    public BaseOrchestrator<T> End(Action stepToExecute)
    {
        RegisterStepToExecute(stepToExecute);
        return this;
    }

    public BaseOrchestrator<T> WithRollback(Action stepToExecute)
    {
        RegisterStepToExecute(stepToExecute);
        return this;
    }

    protected BaseOrchestrator<T> RegisterStepToExecute(Action stepToExecute)
    {
        Steps.Add(stepToExecute);
        return this;
    }

    public BaseOrchestrator<T> StepBuilder()
    {
        Steps = new List<Action>();
        return this;
    }

    /// <inheritdoc/>
    public void Execute(T data)
    {
        ...
    }
}

...

Manas
  • 23
  • 4

1 Answers1

0

The Command pattern is better in this situation since you're building the query as you go. You don't have to deal with data in multiple databases and consequently 2PC. Whereas if you go with Saga, you are committing transactions on each method which doesn't really benefit you much and might add more complexity in the long run.

Suppose transient network issues arise and one method fails and rolling back works on the first two rollbacks, but then fails on the next?

  • creating a command class for each step would decentralize the flow and requires to create another CommandManger class to handle the undo action calls. The desire is to keep the overall flow control centralized, I think an Orchestrator class would be a better fit. Saga orchestrated pattern is to handle distributed transactions, but in this scenario it is not useful. So, I just took the concept of an orchestrator without the distributed transactions but unsure it is the right pattern name. – Manas Aug 28 '21 at 07:28
  • If the desire is to keep it centralized, then orchestration would suit your needs. You'll end up with tight coupling, though, and additions/removals of steps may be cumbersome. Also, you'll still need to create an orchestration service to handle all of this, so your point about needing to create another class is moot. It sounds overall like you need to refactor this, to be honest. – Daniel Cazares Aug 29 '21 at 00:25
  • Daniel, I agree with all your suggestions. considering all project factors, I have opted the orchestrator approach and developed a BaseOrchestrator class to execute a pipeline of operations. Using this approach I have refactored all the workflow based transactions providing the rollback feature. Do you see any problems in isolating all workflow logic into one orchestrator? – Manas Sep 03 '21 at 05:58