Skip to content

Commit

Permalink
improve exception handling when starting instances
Browse files Browse the repository at this point in the history
  • Loading branch information
BigBoot committed Dec 5, 2021
1 parent 5bef2bf commit f84a659
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 46 deletions.
44 changes: 30 additions & 14 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,33 @@ jobs:
- name: Setup msvc
uses: ilammy/msvc-dev-cmd@v1

- name: Build
run: pwsh dist.ps1

- uses: actions/upload-artifact@v2
with:
name: dist
path: dist

release:
runs-on: ubuntu-latest
needs: [build]
if: startsWith(github.ref, 'refs/tags/v')

steps:
- uses: actions/checkout@v2
- run: git fetch --prune --unshallow --tags

- uses: actions/download-artifact@v2
with:
name: dist
path: dist

- name: Install GitVersion
uses: gittools/actions/gitversion/[email protected]
with:
versionSpec: '5.x'

- name: Build
run: pwsh dist.ps1

- name: Set Version
id: version
uses: gittools/actions/gitversion/[email protected]
Expand Down Expand Up @@ -76,7 +95,6 @@ jobs:

- name: Create Release
uses: ncipollo/release-action@v1
if: ${{ steps.version.outputs.commitsSinceVersionSource == '0' }}
with:
allowUpdates: true
name: v${{ steps.version.outputs.informationalVersion }}
Expand All @@ -88,15 +106,13 @@ jobs:
prerelease: ${{ steps.version.outputs.preReleaseLabel != '' }}

- name: Create Discord release notification
uses: rjstone/[email protected]
if: ${{ steps.version.outputs.commitsSinceVersionSource == '0' }}
uses: tsickert/[email protected]
with:
webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
severity: info
username: GiganticEmu
color: "#1a7d93"
avatarUrl: https://cdn.jsdelivr.net/gh/BigBoot/GiganticEmu@master/GiganticEmu.Agent/icon.png
description: "[Release v${{ steps.version.outputs.informationalVersion }}](https://github.com/BigBoot/GiganticEmu/releases/tag/v${{ steps.version.outputs.informationalVersion }})"
details: ${{ steps.changelog.outputs.description }}
footer: Release Notification
webhook-url: ${{ secrets.DISCORD_WEBHOOK }}
username: GiganticEmu Release Notifications
avatar-url: https://cdn.jsdelivr.net/gh/BigBoot/GiganticEmu@master/GiganticEmu.Agent/icon.png
embed-title: "Version v${{ steps.version.outputs.informationalVersion }}"
embed-description: "**Changes:**\n${{ steps.changelog.outputs.description }}\n\n[Show more](https://github.com/BigBoot/GiganticEmu/releases/tag/v${{ steps.version.outputs.informationalVersion }})"
embed-color: 1736083
embed-thumbnail-url: https://cdn.jsdelivr.net/gh/BigBoot/GiganticEmu@master/GiganticEmu.Agent/icon.png

7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.0.5] - 2021-12-05
### Added
- Error page with Exception details to Gigantic.Agent

### Changed
- Made launching instances more resilient to errors


## [2.0.4] - 2021-12-04
### Fixed
Expand Down
28 changes: 16 additions & 12 deletions GiganticEmu.Agent/Pages/Error.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,24 @@
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
@if (!string.IsNullOrEmpty(Model.ErrorMessage))
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
<strong>Error Message:</strong> <code>@Model.ErrorMessage</code>
</p>
}

@if (!string.IsNullOrEmpty(Model.ErrorMessage))
{
<p>
<strong>Stacktrace:</strong>
<textarea class="form-control" rows="20" readonly>@Model.StackTrace</textarea>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@if (!string.IsNullOrEmpty(Model.RequestId))
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
15 changes: 14 additions & 1 deletion GiganticEmu.Agent/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
Expand All @@ -11,7 +12,9 @@ public class ErrorModel : PageModel
{
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public string? ErrorMessage { get; set; }

public string? StackTrace { get; set; }

private readonly ILogger<ErrorModel> _logger;

Expand All @@ -23,6 +26,16 @@ public ErrorModel(ILogger<ErrorModel> logger)
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;

var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

ErrorMessage = exceptionHandlerPathFeature?.Error?.Message;
StackTrace = exceptionHandlerPathFeature?.Error?.StackTrace;
}

public void OnPost()
{
OnGet();
}
}
}
11 changes: 9 additions & 2 deletions GiganticEmu.Agent/Pages/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,21 @@
<nav class="float-left">
<ul>
<li>
<a href="#">Gigantic Control Panel @ViewData["AppVersion"]</a>
<a href="https://github.com/BigBoot/GiganticEmu">GiganticEmu.Agent
@GitVersionInformation.InformationalVersion @if
(GitVersionInformation.CommitsSinceVersionSource != "0" ||
GitVersionInformation.UncommittedChanges != "0")
{
<text>(unofficial)</text>
}
</a>
</li>
</ul>
</nav>
<div class="float-right">
<ul>
<li>
<a href="#">&copy;
<a href="https://github.com/BigBoot">&copy;
<script> document.write(new Date().getFullYear())</script> BigBoot
</a>
</li>
Expand Down
65 changes: 48 additions & 17 deletions GiganticEmu.Agent/ServerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace GiganticEmu.Agent;

public class ServerManager
{
private record Instance(Process Process, string AdminPassword);
private record Instance(Process Process, string AdminPassword, string DefaultGameIniPath, int Port);

private static Regex RE_CREATURE = new Regex(@"DefaultMinionLoadout\[(\d+)]=""\w*""", RegexOptions.Compiled | RegexOptions.Multiline);
private static Regex RE_MAX_PLAYERS = new Regex(@"MaxPlayers=\d*", RegexOptions.Compiled | RegexOptions.Multiline);
Expand All @@ -30,7 +30,7 @@ private record Instance(Process Process, string AdminPassword);
private readonly string _binaryPath;
private readonly string _configPath;

public int RunningInstances { get => _instances.Count; }
public int RunningInstances { get => _configuration.MaxInstances - _freePorts.Count; }

public ServerManager(ILogger<ServerManager> logger, IOptions<AgentConfiguration> configuration)
{
Expand All @@ -51,8 +51,33 @@ public async Task<int> StartInstance(string map, int? maxPlayers = null, (string
throw new NoInstanceAvailableException();
}

var process = new Process();

Instance instance;
try
{
instance = await StartInstance(port, map, maxPlayers, creatures, useLobby);
}
catch (Exception)
{
_instances.Remove(port);
_freePorts.Enqueue(port, port);

throw;
}

if (instance != null)
{
_ = Task
.Run(async () => RunInstance(instance))
.LogExceptions(_logger);
}

return port;
}

private async Task<Instance> StartInstance(int port, string map, int? maxPlayers, (string, string, string)? creatures, bool useLobby)
{
var process = new Process();

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Expand Down Expand Up @@ -143,24 +168,30 @@ public async Task<int> StartInstance(string map, int? maxPlayers = null, (string
}

process.Start();
_instances.Add(port, new Instance(process, adminPassword));
ChildProcessTracker.AddProcess(process);

_ = Task.Run(async () =>
{
await process.WaitForExitAsync();
_instances.Remove(port);
_freePorts.Enqueue(port, port);
File.Delete(defGameIniPath);
}).LogExceptions(_logger);
var instance = new Instance(process, adminPassword, defGameIniPath, port);
_instances.Add(port, instance);
return instance;
}

_ = Task.Run(async () =>
private async Task RunInstance(Instance instance)
{
try
{
await Task.Delay(TimeSpan.FromHours(1));
process.Kill();
}).LogExceptions(_logger);

return port;
var timeout = Task.Delay(TimeSpan.FromHours(1));
if (await Task.WhenAny(instance.Process.WaitForExitAsync(), timeout) == timeout)
{
instance.Process.Kill();
await instance.Process.WaitForExitAsync();
}
}
finally
{
_instances.Remove(instance.Port);
_freePorts.Enqueue(instance.Port, instance.Port);
File.Delete(instance.DefaultGameIniPath);
}
}

public async Task KillInstance(int port)
Expand Down

0 comments on commit f84a659

Please sign in to comment.