<commit_before>﻿using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Tgstation.Server.Host.Components.Byond;

namespace Tgstation.Server.Host.Components.Watchdog
{
	/// <inheritdoc />
	sealed class Session : ISession
	{
		/// <inheritdoc />
		public int ProcessId => process.Id;

		/// <inheritdoc />
		public Task<LaunchResult> LaunchResult { get; }

		/// <inheritdoc />
		public Task<int> Lifetime => lifetimeTask.Task;

		/// <summary>
		/// The actual <see cref="Process"/>
		/// </summary>
		readonly Process process;
		/// <summary>
		/// The <see cref="IByondExecutableLock"/> for the <see cref="process"/>
		/// </summary>
		readonly IByondExecutableLock byondLock;

		/// <summary>
		/// The backing <see cref="TaskCompletionSource{TResult}"/> for <see cref="Lifetime"/>
		/// </summary>
		readonly TaskCompletionSource<int> lifetimeTask;

		/// <summary>
		/// Construct a <see cref="Session"/>
		/// </summary>
		/// <param name="process">The value of <see cref="process"/></param>
		/// <param name="byondLock">The value of <see cref="byondLock"/></param>
		public Session(Process process, IByondExecutableLock byondLock)
		{
			this.process = process ?? throw new ArgumentNullException(nameof(process));
			this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));

			LaunchResult = Task.Factory.StartNew(() =>
			{
				var startTime = DateTimeOffset.Now;
				try
				{
					process.WaitForInputIdle();
				}
				catch (InvalidOperationException) { }
				var result = new LaunchResult
				{
					ExitCode = process.HasExited ? (int?)process.ExitCode : null,
					StartupTime = DateTimeOffset.Now - startTime
				};
				return result;
			}, default, TaskCreationOptions.LongRunning, TaskScheduler.Current);
			lifetimeTask = new TaskCompletionSource<int>();
			process.EnableRaisingEvents = true;
			process.Exited += (a, b) => lifetimeTask.SetResult(process.ExitCode);
		}

		/// <inheritdoc />
		public void Dispose() => process.Dispose();

		/// <inheritdoc />
		public void Terminate()
		{
			try
			{
				process.Kill();
				process.WaitForExit();<commit_msg>Catch occasional InvalidOperationException in Session lifetimeTask<commit_after>﻿using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Tgstation.Server.Host.Components.Byond;

namespace Tgstation.Server.Host.Components.Watchdog
{
	/// <inheritdoc />
	sealed class Session : ISession
	{
		/// <inheritdoc />
		public int ProcessId => process.Id;

		/// <inheritdoc />
		public Task<LaunchResult> LaunchResult { get; }

		/// <inheritdoc />
		public Task<int> Lifetime => lifetimeTask.Task;

		/// <summary>
		/// The actual <see cref="Process"/>
		/// </summary>
		readonly Process process;
		/// <summary>
		/// The <see cref="IByondExecutableLock"/> for the <see cref="process"/>
		/// </summary>
		readonly IByondExecutableLock byondLock;

		/// <summary>
		/// The backing <see cref="TaskCompletionSource{TResult}"/> for <see cref="Lifetime"/>
		/// </summary>
		readonly TaskCompletionSource<int> lifetimeTask;

		/// <summary>
		/// Construct a <see cref="Session"/>
		/// </summary>
		/// <param name="process">The value of <see cref="process"/></param>
		/// <param name="byondLock">The value of <see cref="byondLock"/></param>
		public Session(Process process, IByondExecutableLock byondLock)
		{
			this.process = process ?? throw new ArgumentNullException(nameof(process));
			this.byondLock = byondLock ?? throw new ArgumentNullException(nameof(byondLock));

			LaunchResult = Task.Factory.StartNew(() =>
			{
				var startTime = DateTimeOffset.Now;
				try
				{
					process.WaitForInputIdle();
				}
				catch (InvalidOperationException) { }
				var result = new LaunchResult
				{
					ExitCode = process.HasExited ? (int?)process.ExitCode : null,
					StartupTime = DateTimeOffset.Now - startTime
				};
				return result;
			}, default, TaskCreationOptions.LongRunning, TaskScheduler.Current);
			lifetimeTask = new TaskCompletionSource<int>();
			try
			{
				process.EnableRaisingEvents = true;
				process.Exited += (a, b) => lifetimeTask.TrySetResult(process.ExitCode);
			}
			catch (InvalidOperationException)
			{
				//dead proccess
				lifetimeTask.TrySetResult(process.ExitCode);
			}
		}

		/// <inheritdoc />
		public void Dispose() => process.Dispose();

		/// <inheritdoc />
		public void Terminate()
		{
			try
			{
				process.Kill();
				process.WaitForExit();
{'fraction_non_alphanumeric': 0.1461382571492907, 'fraction_numerical': 0.0, 'mean_word_length': 3.415506958250497, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6076864', 'n_tokens_mistral': 1565, 'n_tokens_neox': 1320, 'n_words': 294}