Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Ensure watched projects are not built in parallel to avoid file locking issues #895

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions src/Microsoft.Tye.Hosting/Model/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Microsoft.Tye.Hosting.Model
{
Expand All @@ -25,6 +27,9 @@ public Application(FileInfo source, Dictionary<string, Service> services)

public Dictionary<string, Service> Services { get; }

internal ConcurrentDictionary<string, TaskCompletionSource<ProcessResult>> OngoingBuildProjectProcesses { get; }
= new ConcurrentDictionary<string, TaskCompletionSource<ProcessResult>>();

public Dictionary<object, object> Items { get; } = new Dictionary<object, object>();

public string? Network { get; set; }
Expand Down
20 changes: 19 additions & 1 deletion src/Microsoft.Tye.Hosting/ProcessRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,9 +359,27 @@ async Task RunApplicationAsync(IEnumerable<(int ExternalPort, int Port, string?
},
Build = async () =>
{
if (service.Description.RunInfo is ProjectRunInfo)
if (service.Description.RunInfo is ProjectRunInfo projectRunInfo)
{
var projectFile = projectRunInfo.ProjectFile.FullName;
var newProcess = new TaskCompletionSource<ProcessResult>();
var ongoingProcess = application.OngoingBuildProjectProcesses.GetOrAdd(projectFile, newProcess);

if (ongoingProcess != newProcess)
{
return (await ongoingProcess.Task).ExitCode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a debug log here

}

_logger.LogDebug($"[{replica}] Building project {projectFile}:");
var buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{service.Status.ProjectFilePath}\" /nologo", throwOnError: false, workingDirectory: application.ContextDirectory);
_logger.LogDebug($"[{replica}] Finished Building project {projectFile}:");

ongoingProcess.SetResult(buildResult);

// Cannot remove a specific KVP until net5.0. Workaround is to cast to ICollection<KVP<>>
ICollection<KeyValuePair<string, TaskCompletionSource<ProcessResult>>> projectProcesses = application.OngoingBuildProjectProcesses;
projectProcesses.Remove(KeyValuePair.Create(projectFile, ongoingProcess));

if (buildResult.ExitCode != 0)
{
_logger.LogInformation("Building projects failed with exit code {ExitCode}: \r\n" + buildResult.StandardOutput, buildResult.ExitCode);
Expand Down
5 changes: 3 additions & 2 deletions src/Microsoft.Tye.Hosting/Watch/DotNetWatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public async Task WatchAsync(ProcessSpec processSpec, IFileSetFactory fileSetFac
if (finishedTask == processTask)
{
// Now wait for a file to change before restarting process
await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("Waiting for a file to change before restarting dotnet..."));
await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("watch: {Replica} Waiting for a file to change before restarting dotnet...", replica));
}

if (!string.IsNullOrEmpty(fileSetTask.Result))
Expand All @@ -112,7 +112,8 @@ public async Task WatchAsync(ProcessSpec processSpec, IFileSetFactory fileSetFac
// Build failed, keep retrying builds until successful build.
}

await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("Waiting for a file to change before restarting dotnet..."));
// Now wait for a file to change before restarting process
await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("watch: {Replica} Waiting for a file to change before restarting dotnet...", replica));
}
}
}
Expand Down