Work Sequences Using Lambdas

Occasionally I'll run into some code that I want to "undo" in case the entire thing doesn't go as planned. Normally placing this code into a separate class and then performing each work item one at a time works pretty well. You have to keep track of your progress so you know where to rollback from but overall it isn't a very complicated process.

I had pretty much the same scenario the other day, but this time I thought I'd approach it a little differently. Instead of writing the sequence management into the class I was using I decided to see if I could come up with the same concept using lambdas instead.

The idea is to make some reusable code that can be used within a class to handle sequences of code. Let's look at a sample of how you might use this code - We're going to pretend this code is part of a class responsible for moving some data around. If one transfer fails then all of the work should be reverted.

string path = Path.Combine("\\\\server\\share\\", this.FileName);

//creating a default sequence
WorkSequence work = new WorkSequence();

//when a rollback takes place
work.Error += (sequence, item, index) => {
    string name = item.GetPerformMethod().Name;
    Console.WriteLine("Failed item {0}", name);
};

//when the work finished
work.Complete += (sequence) => {
    Console.WriteLine("Finished work!");
};

//1. calling a method without a rollback step
work.Add(this.GenerateLibrary);

//2. calling a method that has an undo step
work.Add(this.CreatePackage, this.RemoveTempCacheFile);

//3. calling methods that have arguments
work.Add(() => this.Transfer(path), () => File.Delete(path));

//4. calling a method using different credentials
work.Add(this.Archive, new ImpersonationContext("domain\\name", "passw0rd"));

//5. starts executing the work
work.Perform();

//6. or an async call
work.PerformAsync((sequence) => {
    Console.WriteLine("Finished in sequence");
});

The general idea for this code is to set the work that you need to do and then an optional 'rollback' option in case there is a problem. You'll notice that none of the methods accept arguments. Instead, you can provide an action that invokes the action and then provides the arguments (in #3).

As each item is fired an index is used to keep track of the position in the sequence. That way, if there is an error, only the work that has actually executed will have the rollback method fired.

Finally, you can either invoke the process and wait for all of the work to complete or fire it up in an asynchronously. You can provide a callback method or assign an event to fire off once the work has completed.

Not sure if there is a built in class to handle this kind of work but I've found it useful so far - Enjoy!

April 19, 2010

Work Sequences Using Lambdas

Post titled "Work Sequences Using Lambdas"