RestorePoint - aceryan-consulting/aceryansoft.codeflow GitHub Wiki

Have you ever made nightmares :scream: after restarting production processes from the beginning and waiting for 6 hours ?

Have you ever get the answer , it is a working production process so managers don't want any changes ?

If you are old enough to know the filling of these answers, RestorePoint syntax is made for you.

Don't you remember this kind of production code ?

 public class RestorePointCodeFlow
{
	public void Run()
	{ 
		var restorecodeFlow = new CodeFlow();
		restorecodeFlow.StartNew(cfg => cfg.WithContext(() => new CodeFlowContext()))
		.Call((ctx, inputs) =>
		{
			//legacy code to run a dark code logic 
			// of course the previous developers didn't care about software craftsmanship. 
			// of course managers think that the code is working so don't change anything. 
			Thread.Sleep(TimeSpan.FromHours(4));
		})
		.Call((ctx, inputs) =>
		{
			if(DateTime.Now.Hour <= 6) // seriously after 4 hours of shit, i need to restart everything from the beginning ... 
			{
				throw new Exception("Aliens are not wake up yet, try again after 6 AM"); 
			}
			Thread.Sleep(TimeSpan.FromHours(2));
		})
		.Call((ctx, inputs) =>
		{
			var random = new Random().Next(1, 10);
			if (random<=6) // we don't give a shit about your feelings, restart the program from the beginning ... 
			{
				// seriously after 6 hours , what the F
				throw new Exception("Another team deliver breaking changes and they don't care about your processes");
			}
			Thread.Sleep(TimeSpan.FromHours(2));
		})
		.Call((ctx, inputs) =>
		{           
			Thread.Sleep(TimeSpan.FromSeconds(10)); // you can now save the results to database and publish the results 
			//the process took 14 hours, you relaunched it 3 times 
			//finally the business don't really care because it is 8 PM. 
			// all you have left is a prayer for tomorrow. 
		})
		.Close();

		restorecodeFlow.Execute();
	}         
}  

The idea behind RestorePoint is to help you restart your process where it fails. To achieve this noble goal, the framework only required that you specify a process id, where to restart and a way of saving and loading your context states.

I remember asking to one of my colleague why one production process was taken more than 6 hours on 4 physical servers with 250 Go of RAM on each ones. For me this time was not expected to compute basic operations (jointures, additions, etc ...). I end up thinking that may be some developers in the project was trying to send a man on the moon or computing the size and shape of the universe :worried: .

No need to talk too much, just read bellow to see how easily the code handle our deep distress.

public class RestorePointCodeFlow
{
	public void Run(string requestId = "", bool rerunMode = false, string restorePoint = "")
	{ 
		var restorecodeFlow = new CodeFlow();
		restorecodeFlow.StartNew(cfg =>
		{
			cfg.WithContext(() =>
			{
				var context = new CodeFlowContext();
				context.RequestId = string.IsNullOrEmpty(requestId) ? context.RequestId : requestId; // requestId is the last failed process id 
				return context;
			})
			.RerunMode(rerunMode) // set to true to rerun the process 
			.RestorePointId(restorePoint); // set to the point where the codeflow should restart, for instance "restore.after.6hours.and.aliens.are.wake.up"
		}) 
		.Call((ctx, inputs) =>
		{
			//legacy code to run a dark code logic 
			// of course the previous developers didn't care about software craftsmanship. 
			// of course managers think that the code is working so don't change anything. 
			Thread.Sleep(TimeSpan.FromHours(4));
		})
		.RestorePoint("restore.after.4hours.of.dark.code", SaveRestorePointContextState, LoadRestorePointContextState)
		.Call((ctx, inputs) =>
		{
			if(DateTime.Now.Hour <= 6) // seriously after 4 hours of shit, i need to restart everything from the beginning ... 
			{
				throw new Exception("Aliens are not wake up yet, try again after 6 AM"); 
			}
			Thread.Sleep(TimeSpan.FromHours(2));
		})
		.RestorePoint("restore.after.6hours.and.aliens.are.wake.up", SaveRestorePointContextState, LoadRestorePointContextState)
		.Call((ctx, inputs) =>
		{
			var random = new Random().Next(1, 10);
			if (random<=6) // we don't give a shit about your feelings, restart the program from the beginning ... 
			{
				// seriously after 6 hours , what the F
				throw new Exception("Another team deliver breaking changes and they don't care about your processes");
			}
			Thread.Sleep(TimeSpan.FromHours(2));
		})
		.RestorePoint("restore.after.8hours.and.another.team.fix.breaking.release.changes", SaveRestorePointContextState, LoadRestorePointContextState)
		.Call((ctx, inputs) =>
		{           
			Thread.Sleep(TimeSpan.FromSeconds(10)); // you can now save the results to database and publish the results 
			//the process took 14 hours, you relaunched it 3 times 
			//finally the business don't really care because it is 8 PM. 
			// all you have left is a prayer for tomorrow. 
		})
		.Close();

		restorecodeFlow.Execute();
	}

	private void SaveRestorePointContextState(string reqId, string pointId, object[] inputs, ICodeFlowContext ctx)
	{
		//save execution context to any persistent store
	}

	private ICodeFlowContext LoadRestorePointContextState(string reqId, string pointId)
	{
		//load execution context from any persistent store
		throw new NotImplementedException(); // left as an exercice to the reader. 
	}
}

Continue reading: Extensibility