Saturday, February 06, 2010

Retry Component

Last Friday, I finished a project of reading data from a service and saving the data to a network drive. The project is a console application based on a framework of DI. that is, dependency injection. The whole process is divided into several small tasks, and each task is corresponding to a component, or a library in .Net. Each one does one job and does it well. Together, the components are plugged in to a main controller, where a work flow of components is laid out in a logic as expected. In addition to this clear and well defined structure, there are many other advantages as well, for example, easy maintenance and reusability.

The application will run on daily base to prepare data for one department. I demoed the application to my project team leader. He was very happy to see how the demo run. After the demo, he asked me a question: how about retry? Is there a way to run this application on a retry style if the required data are failed to deliver to the network drive? I have worked on several cases to read required data from SQL servers. All those application have the retry feature. For example, one applications gets the required data first, if the returned data is empty, then the application will quit immediately. If the required data are not empty, the application then gets the data and saves them to the server.

However, for this case, the data source and destination are not at the same place. Therefore, the application will always get the data from source when it runs. I have to work out a way for the retry. In other words, I have to define or create some key references to check if the retry is needed.

Since the job will run on daily base, I come out two keys to check: date and status. For the date, there is one as expected date, and another as actual last date; same for the status, one as expected status and another actual last status. The actual value has to match to the expected value. For example, a user can set up the expected date today and the expected status as a string of "ProcessOK". When those conditions are true or the actual values match the expected values, the application will not read data from source; otherwise, it will read data and continue the remaining steps. After all is done, the actual values will be updated.

All those expected and actual information are defined and saved in an XML configuration file. The expected date can be a script of C# code like "DateTime.Parse(DateTime.Now.ToShortString())", which will always to get today's date. The expected status is static as well. Therefore, only two actual values have to be updated by the application when a complete run is finished.

Here are the pseudo codes of the retry logic:

   bool retry = method call to an instance of Retry with the logic:
!(actual_last_date is set) ||
!(actual_last_status is set) ||
(expected_date != actual_last_date) ||
(expected_status != actual_last_status);
if (retry)
save actual_last_date
save actual_last_status

The Retry class is a component in a library project. The Retry class implements an interface of ICommuncationChannel in a framework library:
  interface ICommunicationChannel<TData, TValue>
    TData Request(TValue value);

so that it can be requested to return a result of retry. A configuration class is also defined in the Retry component library. The config class is simple class with property definitions corresponding to the expected values and the actual values. An instance of the config is wired to the XML configuration.

After one day hard-thinking and coding, I got the component completed, added the DI mapping and XML mapping for Retry's config, and almost finished the main controller with Retry component in the logic.

The reason that I decided to save the actual last results the XML configuration file is that those values can be easily parsed out by another PowerShell script project to get the job status. I have done a monitor process based on PS and Growl for sending notification messages. With the retry feature, I can bring an additional benefit: adding these actual values to the monitor process so that the notification message will include the information.