开发者

Design pattern for reporting/monitoring progress of long processes

Anyone can suggest a good Design Pattern for reporting/monitoring status/progress of long processes. Basically, I have a codebase that receives a "data-context" object:

public class DataContext : IDataContext
{
    pulbic Dictionary<string, objects> Properties { get; private set; }

    // Additional properties removed for simplicity...
}

Based on the provided context, a Task (not TPL-Task) object is created, with various subtasks. During execution, the DataContext object is passed to the various sub-tasks, which can retrieve or update it.

For example, let's say that the main task is a "Copy files" task. The DataContext will have properties like the SourceFolder and TargetFolder, and perhaps a FilterFiles property (e.g. *.docx). Our main task will be a CopyFilesTasks, and it will have a "pipeline" of subtasks - Scan Folders, Scan Files, Filter Files, Copy Files, etc....

What I am looking for, is the best way to allow the task/sub-tasks to report their progress to the caller/executer. In our example above, the changes in progress might be just "Copied file ABC.docx...", or perhaps something a bit more "complex", like "Scanning folder XYZ..."

I have considered the following options:

  1. INotifyPropertyChanged: add a "Progress" property to DataContext

    public string Progress { get; set { _progress = value; RaisePropertyChanged("Progress"); }

    and have the code that created the DataContext object register to the PropertyChanged event. However, this seems like a too-simplistic approach...

  2. ILog (using whatever logging framework you prefer): use an ILog instance in the various tasks/sub-tasks, and have the main-task executioner add it's own listener to the logging framework. However this seemed like bending the logging mechanism to do things it was not supposed to do.

  3. Udi Dahan's DomainEvents: The executioner of the task can regard the DataContext as a "domain", and therefore we can try to implement an "EventHa开发者_如何学JAVAndler" for a "ProgressChanged" event. In theory, this can be even used for more refined events, that happen in specific sub-tasks... But once again, it feels like forcing the concept...

My concerns include things like:

  • Progress might not be the only "event" that needs to be monitored - in our example above, we might want things more defined, like FolderHandled, FileCopied, etc., but we might not know the exact events when executing the tasks (remember - the subtasks are created based on the DataContext, and might result in different tasks being executed).
  • The context of running the tasks is not yet defined. For now, I'm just planning to run the tasks from the command-line application, so outputting to the command-line is needed for debugging. Later on, when I move this to a service, I might want to have a "listener" update a database with the task's progress (for example).


You can declare arguments for each possible operation type, say FileOperationEventArgs for file operation, DatabaseUpdateEventArgs for database operation etc.

public class FileOperationEventArgs : EventArgs
{
    public readonly string SourceFolder;
    public readonly string TargetFolder;

    public FileOperationEventArgs(string sourceFolder, string targetFolder)
    {
        SourceFolder = sourceFolder;
        TargetFolder = targetFolder;
    }
}

public class DatabaseUpdateEventArgs : EventArgs
{
    public readonly int RowsUpdated;

    public DatabaseUpdateEventArgs(int rowsUpdated)
    {
        RowsUpdated = rowsUpdated;
    }
}

OperationProgress class declares events for each operation type.

public class OperationProgress
{
    public event EventHandler<FileOperationEventArgs> FileCopied;
    public event EventHandler<DatabaseUpdateEventArgs> DatabaseUpdated;

    public void OnFileCopied(FileOperationEventArgs a)
    {
        if(FileCopied != null)
            FileCopied(this, a);
    }

    public void OnDatabaseUpdated(DatabaseUpdateEventArgs a)
    {
        if (DatabaseUpdated != null)
            DatabaseUpdated(this, a);
    }
}

OperationProgress will be specified when DataContext is created.

public class DataContext : IDataContext
{
    public Dictionary<string, object> Properties { get; private set; }
    public OperationProgress Progress { get; private set; }

    public DataContext(OperationProgress progress)
    {
        Progress = progress;
    }
}

Subtask implementation can update the progress.

public class FileCopySubTask
{
    public void Execute(DataContext context)
    {
        context.Progress.OnFileCopied(new FileOperationEventArgs("c:/temp1", "c:/temp2"));
    }
}


Consider BackgroundWorkers. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx They have their own reportprogress event on a separate UI thread.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜