/// <summary> /// Process a task and update the status /// </summary> /// <param name="task">The task item to process</param> /// <param name="token">The cancellation token, if any</param> /// <returns></returns> public virtual async Task <TransformationProcessTaskStatus> ProcessTaskAsync(PageTransformationTask task, CancellationToken token = default) { if (task == null) { throw new ArgumentNullException(nameof(task)); } var logger = ServiceProvider.GetRequiredService <ILogger <LongRunningTransformationProcessBase> >(); var pageTransformator = ServiceProvider.GetRequiredService <IPageTransformator>(); // Retrieve the status for the task var taskStatus = await GetTaskStatusAsync(task.Id, token).ConfigureAwait(false); // Check if task has been already processed if (taskStatus.State != TransformationTaskExecutionState.Pending) { // Skip return(taskStatus); } // Retrieve current process status var status = await GetStatusAsync(token).ConfigureAwait(false); // Process is not running, skip the task if (status.State != TransformationExecutionState.Running) { // Mark task as aborted taskStatus = TransformationProcessTaskStatus.CreateNormal(Id, task.Id, taskStatus.CreationDate, taskStatus.StartDate, DateTimeOffset.Now, TransformationTaskExecutionState.Aborted); await ChangeTaskStatusAsync(taskStatus, token).ConfigureAwait(false); return(taskStatus); } try { // Mark task as running taskStatus = TransformationProcessTaskStatus.CreateNormal(Id, task.Id, taskStatus.CreationDate, DateTimeOffset.Now, null, TransformationTaskExecutionState.Running); await ChangeTaskStatusAsync(taskStatus, token).ConfigureAwait(false); // Run the actual transformation task await pageTransformator.TransformAsync(task, token).ConfigureAwait(false); // Mark task as completed taskStatus = TransformationProcessTaskStatus.CreateNormal(Id, task.Id, taskStatus.CreationDate, taskStatus.StartDate, DateTimeOffset.Now, TransformationTaskExecutionState.Completed); await ChangeTaskStatusAsync(taskStatus, token).ConfigureAwait(false); return(taskStatus); } catch (Exception ex) { logger.LogError(ex, "Error while transforming task {id}", task.Id); // Mark task as faulted taskStatus = TransformationProcessTaskStatus.CreateFaulted(Id, task.Id, taskStatus.CreationDate, taskStatus.StartDate, DateTimeOffset.Now, ex); await ChangeTaskStatusAsync(taskStatus, token).ConfigureAwait(false); return(taskStatus); } }
/// <summary> /// Allows to write the task status /// </summary> /// <param name="status">The status to write</param> /// <param name="token">The cancellation token, if any</param> /// <returns></returns> public Task WriteTaskStatusAsync(TransformationProcessTaskStatus status, CancellationToken token = default) { if (status == null) throw new ArgumentNullException(nameof(status)); taskStatuses.AddOrUpdate(status.Id, status, (k, o) => status); return Task.CompletedTask; }
/// <summary> /// Raises the task progress, if a TaskProgress function is defined /// </summary> /// <param name="status">The status to notify</param> protected virtual Task RaiseTasksProgressAsync(TransformationProcessTaskStatus status) { if (TasksProgress != null) { return(TasksProgress(status)); } return(Task.CompletedTask); }
/// <summary> /// Sets the status of a task /// </summary> /// <param name="status">The process task status</param> /// <param name="token">Cancellation token to use, if any</param> protected virtual async Task ChangeTaskStatusAsync(TransformationProcessTaskStatus status, CancellationToken token) { if (status == null) { throw new ArgumentNullException(nameof(status)); } // Save the new state await TransformationStateManager .WriteTaskStatusAsync(status, token) .ConfigureAwait(false); await RaiseTasksProgressAsync(status).ConfigureAwait(false); }
private async Task Run(ISourceProvider sourceProvider, PnPContext targetContext, CancellationToken token) { try { // Iterate through each task await foreach (var task in transformationDistiller.GetPageTransformationTasksAsync(sourceProvider, targetContext, token)) { var taskStatus = TransformationProcessTaskStatus.CreateNormal(Id, task.Id, DateTimeOffset.Now, DateTimeOffset.Now, null, TransformationTaskExecutionState.Running); try { // Save the task status to pending await ChangeTaskStatusAsync(taskStatus).ConfigureAwait(false); // Execute the actual transformation task await pageTransformator.TransformAsync(task, token).ConfigureAwait(false); // Save the task status to completed taskStatus = TransformationProcessTaskStatus.CreateNormal(Id, task.Id, taskStatus.CreationDate, taskStatus.StartDate, DateTimeOffset.Now, TransformationTaskExecutionState.Completed); await ChangeTaskStatusAsync(taskStatus).ConfigureAwait(false); } catch (Exception ex) { logger.LogError(ex, "Error while transforming task {id}", task.Id); // Save the task status to faulted taskStatus = TransformationProcessTaskStatus.CreateFaulted(Id, task.Id, taskStatus.CreationDate, taskStatus.StartDate, DateTimeOffset.Now, ex); await ChangeTaskStatusAsync(taskStatus).ConfigureAwait(false); } } // Mark the process as completed await ChangeProcessStateAsync(TransformationExecutionState.Completed).ConfigureAwait(false); } catch (OperationCanceledException) { // Mark the process as aborted and ignore this kind of error await ChangeProcessStateAsync(TransformationExecutionState.Aborted).ConfigureAwait(false); } catch (Exception ex) { logger.LogError(ex, "The entire process has failed"); // Mark the process as faulted await ChangeProcessStateAsync(TransformationExecutionState.Faulted).ConfigureAwait(false); } }
/// <summary> /// Starts the Transformation Process /// </summary> public override async Task StartProcessAsync(ISourceProvider sourceProvider, PnPContext targetContext, CancellationToken token = default) { // Check if process is already running var status = await GetStatusAsync(token).ConfigureAwait(false); if (status.State != TransformationExecutionState.Pending) { throw new InvalidOperationException("Process cannot be started twice!"); } var transformationDistiller = ServiceProvider.GetRequiredService <ITransformationDistiller>(); // Change state to running await ChangeProcessStatusAsync(TransformationExecutionState.Running, token).ConfigureAwait(false); try { await foreach (var task in transformationDistiller.GetPageTransformationTasksAsync(sourceProvider, targetContext, token).WithCancellation(token)) { // Mark task as pending await ChangeTaskStatusAsync(TransformationProcessTaskStatus.CreatePending(Id, task.Id, DateTimeOffset.Now), token) .ConfigureAwait(false); // Queue item await EnqueueTaskAsync(task, token).ConfigureAwait(false); } } catch (OperationCanceledException) { // Change state to aborted await ChangeProcessStatusAsync(TransformationExecutionState.Aborted, token).ConfigureAwait(false); throw; } catch (Exception) { // Change state to faulted await ChangeProcessStatusAsync(TransformationExecutionState.Faulted, token).ConfigureAwait(false); throw; } }
private Task ChangeTaskStatusAsync(TransformationProcessTaskStatus status) { tasksStatuses[status.Id] = status; return(RaiseTasksProgressAsync(status)); }