mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-09 01:32:38 -05:00
Add functionality to shutdown Kusto process when parent process exits (#1609)
This commit is contained in:
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<PropertyGroup Condition="'$(BUILD_DOTNET_TOOL)' == 'true'">
|
<PropertyGroup Condition="'$(BUILD_DOTNET_TOOL)' == 'true'">
|
||||||
<PackageId>Microsoft.SqlServer.KustoServiceLayer.Tool</PackageId>
|
<PackageId>Microsoft.SqlServer.KustoServiceLayer.Tool</PackageId>
|
||||||
<PackageVersion>1.0.0</PackageVersion>
|
<PackageVersion>1.1.0</PackageVersion>
|
||||||
<PackageDescription>.NET client Kusto Service application, usable as a dotnet tool. This package is intended to be used by internal applications only and should not be referenced directly.</PackageDescription>
|
<PackageDescription>.NET client Kusto Service application, usable as a dotnet tool. This package is intended to be used by internal applications only and should not be referenced directly.</PackageDescription>
|
||||||
<PackAsTool>true</PackAsTool>
|
<PackAsTool>true</PackAsTool>
|
||||||
<ToolCommandName>$(AssemblyName)</ToolCommandName>
|
<ToolCommandName>$(AssemblyName)</ToolCommandName>
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ namespace Microsoft.Kusto.ServiceLayer
|
|||||||
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
|
SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails);
|
||||||
ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext);
|
ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext);
|
||||||
|
|
||||||
|
// If this service was started by another process, then it should shutdown when that parent process does.
|
||||||
|
if (commandOptions.ParentProcessId != null)
|
||||||
|
{
|
||||||
|
ProcessExitTimer.Start(commandOptions.ParentProcessId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
serviceHost.WaitForExit();
|
serviceHost.WaitForExit();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|||||||
@@ -66,6 +66,13 @@ namespace Microsoft.SqlTools.Hosting.Utility
|
|||||||
case "-parallel-message-processing":
|
case "-parallel-message-processing":
|
||||||
ParallelMessageProcessing = true;
|
ParallelMessageProcessing = true;
|
||||||
break;
|
break;
|
||||||
|
case "-parent-pid":
|
||||||
|
string nextArg = args[++i];
|
||||||
|
if (Int32.TryParse(nextArg, out int parsedInt))
|
||||||
|
{
|
||||||
|
ParentProcessId = parsedInt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ErrorMessage += string.Format("Unknown argument \"{0}\"" + Environment.NewLine, argName);
|
ErrorMessage += string.Format("Unknown argument \"{0}\"" + Environment.NewLine, argName);
|
||||||
break;
|
break;
|
||||||
@@ -140,6 +147,12 @@ namespace Microsoft.SqlTools.Hosting.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ParallelMessageProcessing { get; private set; } = false;
|
public bool ParallelMessageProcessing { get; private set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the process that started this service. This is used to check when the parent
|
||||||
|
/// process exits so that the service process can exit at the same time.
|
||||||
|
/// </summary>
|
||||||
|
public int? ParentProcessId { get; private set; }
|
||||||
|
|
||||||
public virtual void SetLocale(string locale)
|
public virtual void SetLocale(string locale)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
44
src/Microsoft.SqlTools.Hosting/Utility/ProcessExitTimer.cs
Normal file
44
src/Microsoft.SqlTools.Hosting/Utility/ProcessExitTimer.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Microsoft.SqlTools.Utility
|
||||||
|
{
|
||||||
|
public static class ProcessExitTimer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a thread that checks if the provided parent process has exited each time the provided interval has elapsed.
|
||||||
|
/// Once the parent process has exited the process that started the timer also exits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parentProcessId">The ID of the parent process to monitor.</param>
|
||||||
|
/// <param name="intervalMs">The time interval in milliseconds for when to poll the parent process.</param>
|
||||||
|
/// <returns>The ID of the thread running the timer.</returns>
|
||||||
|
public static int Start(int parentProcessId, int intervalMs = 10000)
|
||||||
|
{
|
||||||
|
var statusThread = new Thread(() => CheckParentStatusLoop(parentProcessId, intervalMs));
|
||||||
|
statusThread.Start();
|
||||||
|
return statusThread.ManagedThreadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckParentStatusLoop(int parentProcessId, int intervalMs)
|
||||||
|
{
|
||||||
|
var parent = Process.GetProcessById(parentProcessId);
|
||||||
|
Logger.Write(TraceEventType.Information, $"Starting thread to check status of parent process. Parent PID: {parent.Id}");
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (parent.HasExited)
|
||||||
|
{
|
||||||
|
var processName = Process.GetCurrentProcess().ProcessName;
|
||||||
|
Logger.Write(TraceEventType.Information, $"Terminating {processName} process because parent process has exited. Parent PID: {parent.Id}");
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
Thread.Sleep(intervalMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<When Condition="'$(BUILD_DOTNET_TOOL)' == 'true'">
|
<When Condition="'$(BUILD_DOTNET_TOOL)' == 'true'">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>Microsoft.SqlServer.SqlToolsServiceLayer.Tool</PackageId>
|
<PackageId>Microsoft.SqlServer.SqlToolsServiceLayer.Tool</PackageId>
|
||||||
<PackageVersion>1.0.0</PackageVersion>
|
<PackageVersion>1.1.0</PackageVersion>
|
||||||
<PackageDescription>.NET client SQL Tools Service application, usable as a dotnet tool. This package is intended to be used by internal applications only and should not be referenced directly.</PackageDescription>
|
<PackageDescription>.NET client SQL Tools Service application, usable as a dotnet tool. This package is intended to be used by internal applications only and should not be referenced directly.</PackageDescription>
|
||||||
<PackAsTool>true</PackAsTool>
|
<PackAsTool>true</PackAsTool>
|
||||||
<ToolCommandName>$(AssemblyName)</ToolCommandName>
|
<ToolCommandName>$(AssemblyName)</ToolCommandName>
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using Microsoft.SqlTools.ServiceLayer.SqlContext;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
using Microsoft.SqlTools.Utility;
|
using Microsoft.SqlTools.Utility;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer
|
namespace Microsoft.SqlTools.ServiceLayer
|
||||||
{
|
{
|
||||||
@@ -57,9 +56,7 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
// If this service was started by another process, then it should shutdown when that parent process does.
|
// If this service was started by another process, then it should shutdown when that parent process does.
|
||||||
if (commandOptions.ParentProcessId != null)
|
if (commandOptions.ParentProcessId != null)
|
||||||
{
|
{
|
||||||
var parentProcess = Process.GetProcessById(commandOptions.ParentProcessId.Value);
|
ProcessExitTimer.Start(commandOptions.ParentProcessId.Value);
|
||||||
var statusThread = new Thread(() => CheckParentStatusLoop(parentProcess));
|
|
||||||
statusThread.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceHost.WaitForExit();
|
serviceHost.WaitForExit();
|
||||||
@@ -83,20 +80,5 @@ namespace Microsoft.SqlTools.ServiceLayer
|
|||||||
sqlClientListener?.Dispose();
|
sqlClientListener?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckParentStatusLoop(Process parent)
|
|
||||||
{
|
|
||||||
Logger.Write(TraceEventType.Information, $"Starting thread to check status of parent process. Parent PID: {parent.Id}");
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (parent.HasExited)
|
|
||||||
{
|
|
||||||
var processName = Process.GetCurrentProcess().ProcessName;
|
|
||||||
Logger.Write(TraceEventType.Information, $"Terminating {processName} process because parent process has exited. Parent PID: {parent.Id}");
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
Thread.Sleep(5000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
|||||||
{
|
{
|
||||||
internal const string ServiceLayerServiceName = "MicrosoftSqlToolsServiceLayer.exe";
|
internal const string ServiceLayerServiceName = "MicrosoftSqlToolsServiceLayer.exe";
|
||||||
|
|
||||||
private static readonly string[] serviceLayerCommandArgs = { "-d", "--developers", "--parent-pid" };
|
private static readonly string[] serviceLayerCommandArgs = { "-d", "--developers" };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of contributors to this project, used as part of the onboarding process.
|
* List of contributors to this project, used as part of the onboarding process.
|
||||||
@@ -24,8 +24,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
|||||||
"Charles-Gagnon"
|
"Charles-Gagnon"
|
||||||
};
|
};
|
||||||
|
|
||||||
public int? ParentProcessId { get; private set; }
|
|
||||||
|
|
||||||
public ServiceLayerCommandOptions(string[] args) : base(args.Where(arg => !serviceLayerCommandArgs.Contains(arg)).ToArray(), ServiceLayerServiceName)
|
public ServiceLayerCommandOptions(string[] args) : base(args.Where(arg => !serviceLayerCommandArgs.Contains(arg)).ToArray(), ServiceLayerServiceName)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < args.Length; ++i)
|
for (int i = 0; i < args.Length; ++i)
|
||||||
@@ -44,13 +42,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
|||||||
Console.WriteLine(string.Join(Environment.NewLine, contributors.Select(contributor => $"\t{contributor}")));
|
Console.WriteLine(string.Join(Environment.NewLine, contributors.Select(contributor => $"\t{contributor}")));
|
||||||
this.ShouldExit = true;
|
this.ShouldExit = true;
|
||||||
break;
|
break;
|
||||||
case "--parent-pid":
|
|
||||||
string nextArg = args[++i];
|
|
||||||
if (Int32.TryParse(nextArg, out int parsedInt))
|
|
||||||
{
|
|
||||||
ParentProcessId = parsedInt;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user