Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v6.11.4: Various fixes in the static files component #1995

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/Version.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<!-- Integration tests will ensure they match across the board -->
<Import Project="WebpanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>6.11.3</TgsCoreVersion>
<TgsCoreVersion>6.11.4</TgsCoreVersion>
<TgsConfigVersion>5.3.0</TgsConfigVersion>
<TgsRestVersion>10.10.0</TgsRestVersion>
<TgsGraphQLVersion>0.2.0</TgsGraphQLVersion>
Expand Down
58 changes: 45 additions & 13 deletions src/Tgstation.Server.Host/Components/StaticFiles/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ sealed class Configuration : IConfiguration
readonly SemaphoreSlim semaphore;

/// <summary>
/// The <see cref="CancellationTokenSource"/> that is triggered when <see cref="IDisposable.Dispose"/> is called.
/// The <see cref="CancellationTokenSource"/> that is triggered when <see cref="StopAsync(CancellationToken)"/> is called.
/// </summary>
readonly CancellationTokenSource disposeCts;
readonly CancellationTokenSource stoppingCts;

/// <summary>
/// The culmination of all upload file transfer callbacks.
Expand Down Expand Up @@ -186,16 +186,15 @@ public Configuration(
this.sessionConfiguration = sessionConfiguration ?? throw new ArgumentNullException(nameof(sessionConfiguration));

semaphore = new SemaphoreSlim(1, 1);
disposeCts = new CancellationTokenSource();
stoppingCts = new CancellationTokenSource();
uploadTasks = Task.CompletedTask;
}

/// <inheritdoc />
public void Dispose()
{
semaphore.Dispose();
disposeCts.Cancel();
disposeCts.Dispose();
stoppingCts.Dispose();
}

/// <inheritdoc />
Expand Down Expand Up @@ -310,7 +309,7 @@ string GetFileSha()

var originalSha = GetFileSha();

var disposeToken = disposeCts.Token;
var disposeToken = stoppingCts.Token;
var fileTicket = fileTransferService.CreateDownload(
new FileDownloadProvider(
() =>
Expand Down Expand Up @@ -472,7 +471,7 @@ void WriteImpl()
try
{
var fileTicket = fileTransferService.CreateUpload(FileUploadStreamKind.ForSynchronousIO);
var uploadCancellationToken = disposeCts.Token;
var uploadCancellationToken = stoppingCts.Token;
async Task UploadHandler()
{
await using (fileTicket)
Expand All @@ -491,7 +490,7 @@ async Task UploadHandler()
void WriteCallback()
{
logger.LogTrace("Running synchronous write...");
success = synchronousIOManager.WriteFileChecked(path, uploadStream, ref fileHash, cancellationToken);
success = synchronousIOManager.WriteFileChecked(path, uploadStream, ref fileHash, uploadCancellationToken);
logger.LogTrace("Finished write {un}successfully!", success ? String.Empty : "un");
}

Expand All @@ -511,9 +510,9 @@ void WriteCallback()

logger.LogTrace("Kicking off write callback");
if (systemIdentity == null)
await Task.Factory.StartNew(WriteCallback, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
await Task.Factory.StartNew(WriteCallback, uploadCancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
else
await systemIdentity.RunImpersonated(WriteCallback, cancellationToken);
await systemIdentity.RunImpersonated(WriteCallback, uploadCancellationToken);
}

if (!success)
Expand All @@ -534,8 +533,24 @@ void WriteCallback()
Path = configurationRelativePath,
};

lock (disposeCts)
uploadTasks = Task.WhenAll(uploadTasks, UploadHandler());
lock (stoppingCts)
{
async Task ChainUploadTasks()
{
var oldUploadTask = uploadTasks;
var newUploadTask = UploadHandler();
try
{
await oldUploadTask;
}
finally
{
await newUploadTask;
}
}

uploadTasks = ChainUploadTasks();
}
}
catch (UnauthorizedAccessException)
{
Expand Down Expand Up @@ -609,7 +624,24 @@ void WriteCallback()
public Task StartAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);

/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
public async Task StopAsync(CancellationToken cancellationToken)
{
await EnsureDirectories(cancellationToken);

stoppingCts.Cancel();
try
{
await uploadTasks;
}
catch (OperationCanceledException ex)
{
logger.LogDebug(ex, "One or more uploads/downloads were aborted!");
}
catch (Exception ex)
{
logger.LogError(ex, "Error awaiting upload tasks!");
}
}

/// <inheritdoc />
public ValueTask HandleEvent(EventType eventType, IEnumerable<string?> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
Expand Down
Loading