Integrate generate script with task service (#426)

* Support generate script for backup

* change

* update task service data contract for Generate Script

* more changes

* update test

* add comments

* Add missing files

* update stub backup operation for testing

* pr comments

* remove empty space

* Fix tests

* Add unit/integration tests and isCancelable to TaskInfo

* address pr comments

* pr comments - fix tests

* fix minor issue

* fix minor issues

* remove unused variable
This commit is contained in:
Kate Shin
2017-08-09 19:59:40 -07:00
committed by GitHub
parent 6696b7e72f
commit cd870e6f15
26 changed files with 845 additions and 386 deletions

View File

@@ -20,6 +20,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices.Contracts
/// </summary>
public SqlTaskStatus Status { get; set; }
/// <summary>
/// Task execution mode
/// </summary>
public TaskExecutionMode TaskExecutionMode { get; set; }
/// <summary>
/// Database server name this task is created for
/// </summary>
@@ -30,7 +35,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices.Contracts
/// </summary>
public string DatabaseName { get; set; }
/// <summary>
/// Task name which defines the type of the task (e.g. CreateDatabase, Backup)
/// </summary>
@@ -52,5 +56,9 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices.Contracts
/// </summary>
public string Description { get; set; }
/// <summary>
/// Defines if the task can be canceled
/// </summary>
public bool IsCancelable { get; set; }
}
}

View File

@@ -18,10 +18,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices.Contracts
public SqlTaskStatus Status { get; set; }
/// <summary>
/// Database server name this task is created for
/// Progress message
/// </summary>
public string Message { get; set; }
/// <summary>
/// Script for the task execution
/// </summary>
public string Script { get; set; }
/// <summary>
/// The number of millisecond the task was running
/// </summary>

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Microsoft.SqlTools.ServiceLayer.TaskServices
{
/// <summary>
/// Defines interface for task operations
/// </summary>
public interface ITaskOperation
{
/// <summary>
/// Execute a task
/// </summary>
/// <param name="mode">Task execution mode (e.g. script or execute)</param>
void Execute(TaskExecutionMode mode);
/// <summary>
/// Cancel a task
/// </summary>
void Cancel();
}
/// <summary>
/// Defines interface for scriptable task operations
/// </summary>
public interface IScriptableTaskOperation: ITaskOperation
{
/// <summary>
/// Script for the task operation
/// </summary>
string ScriptContent { get; set; }
}
}

View File

@@ -30,6 +30,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
private SqlTaskStatus status = SqlTaskStatus.NotStarted;
private DateTime stopTime;
public event EventHandler<TaskEventArgs<TaskScript>> ScriptAdded;
public event EventHandler<TaskEventArgs<TaskMessage>> MessageAdded;
public event EventHandler<TaskEventArgs<SqlTaskStatus>> StatusChanged;
@@ -119,7 +120,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
/// <returns></returns>
internal async Task<TaskResult> RunAndCancel()
{
AddMessage(SR.Task_InProgress, SqlTaskStatus.InProgress, true);
AddMessage(SR.TaskInProgress, SqlTaskStatus.InProgress, true);
TaskResult taskResult = new TaskResult();
Task<TaskResult> performTask = TaskToRun(this);
@@ -129,15 +130,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
{
if (TaskToCancel != null)
{
AutoResetEvent backupCompletedEvent = new AutoResetEvent(initialState: false);
Task<TaskResult> cancelTask = Task.Run(() => CancelTaskAsync(TokenSource.Token, backupCompletedEvent));
AutoResetEvent onCompletedEvent = new AutoResetEvent(initialState: false);
Task<TaskResult> cancelTask = Task.Run(() => CancelTaskAsync(TokenSource.Token, onCompletedEvent));
completedTask = await Task.WhenAny(performTask, cancelTask);
// Release the cancelTask
if (completedTask == performTask)
{
backupCompletedEvent.Set();
onCompletedEvent.Set();
}
}
else
@@ -145,7 +146,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
completedTask = await Task.WhenAny(performTask);
}
AddMessage(completedTask.Result.TaskStatus == SqlTaskStatus.Failed ? completedTask.Result.ErrorMessage : SR.Task_Completed,
AddMessage(completedTask.Result.TaskStatus == SqlTaskStatus.Failed ? completedTask.Result.ErrorMessage : SR.TaskCompleted,
completedTask.Result.TaskStatus);
taskResult = completedTask.Result;
@@ -174,16 +175,16 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
/// </summary>
/// <param name="backupOperation"></param>
/// <param name="token"></param>
/// <param name="backupCompletedEvent"></param>
/// <param name="onCompletedEvent"></param>
/// <returns></returns>
private async Task<TaskResult> CancelTaskAsync(CancellationToken token, AutoResetEvent backupCompletedEvent)
private async Task<TaskResult> CancelTaskAsync(CancellationToken token, AutoResetEvent onCompletedEvent)
{
// Create a task for backup cancellation request
TaskResult result = new TaskResult();
WaitHandle[] waitHandles = new WaitHandle[2]
{
backupCompletedEvent,
onCompletedEvent,
token.WaitHandle
};
@@ -371,6 +372,26 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
IsCancelRequested = true;
}
/// <summary>
/// Add script result of the operation
/// </summary>
/// <param name="script">Script content</param>
/// <param name="errorMessage">Error occured during script</param>
/// <param name="status">Status of the script</param>
/// <returns></returns>
public TaskScript AddScript(SqlTaskStatus status, string script, string errorMessage = null)
{
var newScript = new TaskScript
{
Status = status,
Script = script,
ErrorMessage = errorMessage
};
OnScriptAdded(new TaskEventArgs<TaskScript>(newScript, this));
return newScript;
}
/// <summary>
/// Adds a new message to the task messages
/// </summary>
@@ -430,6 +451,8 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
ServerName = TaskMetadata.ServerName,
Name = TaskMetadata.Name,
Description = TaskMetadata.Description,
TaskExecutionMode = TaskMetadata.TaskExecutionMode,
IsCancelable = TaskMetadata.IsCancelable,
};
}
@@ -465,6 +488,15 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
}
}
private void OnScriptAdded(TaskEventArgs<TaskScript> e)
{
var handler = ScriptAdded;
if (handler != null)
{
handler(this, e);
}
}
private void OnMessageAdded(TaskEventArgs<TaskMessage> e)
{
var handler = MessageAdded;

View File

@@ -0,0 +1,29 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.TaskServices
{
/// <summary>
/// Task execution mode
/// </summary>
public enum TaskExecutionMode
{
/// <summary>
/// Execute task
/// </summary>
Execute,
/// <summary>
/// Script task
/// </summary>
Script,
/// <summary>
/// Execute and script task
/// Needed for tasks that will show the script when execution completes
/// </summary>
ExecuteAndScript
}
}

View File

@@ -17,6 +17,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
/// </summary>
public string Name { get; set; }
/// <summary>
/// Task execution mode (e.g. execute or script)
/// </summary>
public TaskExecutionMode TaskExecutionMode { get; set; }
/// <summary>
/// The number of seconds to wait before canceling the task.
/// This is a optional field and 0 or negative numbers means no timeout
@@ -41,6 +46,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
/// <summary>
/// Data required to perform the task
/// </summary>
public object Data { get; set; }
public object Data { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
namespace Microsoft.SqlTools.ServiceLayer.TaskServices
{
/// <summary>
/// Task script message
/// </summary>
public class TaskScript
{
/// <summary>
/// Status of script
/// </summary>
public SqlTaskStatus Status { get; set; }
/// <summary>
/// Script content
/// </summary>
public string Script { get; set; }
/// <summary>
/// Error occurred during script
/// </summary>
public string ErrorMessage { get; set; }
}
}

View File

@@ -116,6 +116,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
if (sqlTask != null)
{
TaskInfo taskInfo = sqlTask.ToTaskInfo();
sqlTask.ScriptAdded += OnTaskScriptAdded;
sqlTask.MessageAdded += OnTaskMessageAdded;
sqlTask.StatusChanged += OnTaskStatusChanged;
await serviceHost.SendEvent(TaskCreatedNotification.Type, taskInfo);
@@ -131,7 +132,6 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
{
TaskId = sqlTask.TaskId.ToString(),
Status = e.TaskData
};
if (sqlTask.IsCompleted)
@@ -141,6 +141,23 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices
await serviceHost.SendEvent(TaskStatusChangedNotification.Type, progressInfo);
}
}
private async void OnTaskScriptAdded(object sender, TaskEventArgs<TaskScript> e)
{
SqlTask sqlTask = e.SqlTask;
if (sqlTask != null)
{
TaskProgressInfo progressInfo = new TaskProgressInfo
{
TaskId = sqlTask.TaskId.ToString(),
Status = e.TaskData.Status,
Script = e.TaskData.Script,
Message = e.TaskData.ErrorMessage,
};
await serviceHost.SendEvent(TaskStatusChangedNotification.Type, progressInfo);
}
}
private async void OnTaskMessageAdded(object sender, TaskEventArgs<TaskMessage> e)
{