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

Fix to allow parallel deployments across apps #216

Open
wants to merge 6 commits into
base: feature/k8se
Choose a base branch
from
Open
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
20 changes: 19 additions & 1 deletion Kudu.Core/Deployment/DeploymentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -439,19 +439,32 @@ internal IEnumerable<DeployResult> PurgeDeployments(IEnumerable<DeployResult> re
if (results.Any())
{
var toDelete = new List<DeployResult>();
toDelete.AddRange(GetPurgeTemporaryDeployments(results));
//toDelete.AddRange(GetPurgeTemporaryDeployments(results));
toDelete.AddRange(GetPurgeFailedDeployments(results));
toDelete.AddRange(GetPurgeObsoleteDeployments(results));

if (toDelete.Any())
{
var purgeTempDeployments = GetPurgeTemporaryDeployments(results);
foreach (DeployResult temp in purgeTempDeployments)
{
Console.WriteLine("We used to Remove {0}, {1}, received at {2}, but not doing now",
temp.Id.Substring(0, Math.Min(temp.Id.Length, 9)),
temp.Status,
temp.ReceivedTime);
}

var tracer = _traceFactory.GetTracer();
using (tracer.Step("Purge deployment items"))
{
foreach (DeployResult delete in toDelete)
{
_status.Delete(delete.Id, _environment);

Console.WriteLine("Remove {0}, {1}, received at {2}",
delete.Id.Substring(0, Math.Min(delete.Id.Length, 9)),
delete.Status,
delete.ReceivedTime);
tracer.Trace("Remove {0}, {1}, received at {2}",
delete.Id.Substring(0, Math.Min(delete.Id.Length, 9)),
delete.Status,
Expand Down Expand Up @@ -559,7 +572,12 @@ IDeploymentStatusFile GetOrCreateStatusFile(ChangeSet changeSet, ITracer tracer,
{
// Create the status file and store information about the commit
statusFile = _status.Create(id, _environment);
Console.WriteLine("id=" + id + ": In GetOrCreateStatusFile. statusFile was NULL. So, created it.");
}else
{
Console.WriteLine("id=" + id + ": In GetOrCreateStatusFile. statusFile already exists");
}

statusFile.Message = changeSet.Message;
statusFile.Author = changeSet.AuthorName;
statusFile.Deployer = deployer;
Expand Down
17 changes: 16 additions & 1 deletion Kudu.Core/Deployment/DeploymentStatusFile.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Linq;
using Kudu.Contracts.Infrastructure;
using Kudu.Core.Infrastructure;
Expand Down Expand Up @@ -32,12 +33,23 @@ private DeploymentStatusFile(string id, IEnvironment environment, IOperationLock
{
Initialize(document);
}

// Ensure that the status file is created before we enter this code block
Task ensureLogFileExists = Task.Run(() =>
OperationManager.Attempt(() =>
{
if (!FileSystemHelpers.FileExists(_statusFile))
{
throw new FileNotFoundException("Status file doesn't exist. Will wait for 1 second and retry");
}
}, 5, 250));
}

public static DeploymentStatusFile Create(string id, IEnvironment environment, IOperationLock statusLock)
{
string path = Path.Combine(environment.DeploymentsPath, id);

Console.WriteLine("id=" +id + ": Creating statusFile at " + path);
FileSystemHelpers.EnsureDirectory(path);

DateTime utcNow = DateTime.UtcNow;
Expand All @@ -53,11 +65,14 @@ public static DeploymentStatusFile Open(string id, IEnvironment environment, IAn
return statusLock.LockOperation(() =>
{
string path = Path.Combine(environment.DeploymentsPath, id, StatusFile);
if (!FileSystemHelpers.FileExists(path))

if(!FileSystemHelpers.FileExists(path))
{
Console.WriteLine("id=" +id + ": DeploymentStatusFile.open. path=" + path +". FileNotFound");
return null;
}

Console.WriteLine("id=" + id + ": DeploymentStatusFile.open. path=" + path + ". FileExists");
try
{
XDocument document = null;
Expand Down
3 changes: 3 additions & 0 deletions Kudu.Core/Deployment/FetchDeploymentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ public static async Task<bool> PerformBackgroundDeployment(
var hooksLock = new LockFile(hooksLockPath, traceFactory);
var deploymentLock = DeploymentLockFile.GetInstance(deploymentLockPath, traceFactory);

Console.WriteLine("deploymentLockPath=" + deploymentLockPath);
Console.WriteLine((deploymentLock == null) ? "deploymentLock is null" : "deploymentLock is not null");

var analytics = new Analytics(settings, new ServerConfiguration(), traceFactory);
var deploymentStatusManager = new DeploymentStatusManager(environment, analytics, statusLock);
var siteBuilderFactory = new SiteBuilderFactory(new BuildPropertyProvider(), environment, _httpContextAccessor);
Expand Down
11 changes: 10 additions & 1 deletion Kudu.Core/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,17 @@ public Environment(
RootPath = rootPath;

SiteRootPath = Path.Combine(rootPath, Constants.SiteFolder);
if(k8seAppName == null)
{
_tempPath = Path.GetTempPath();
Console.WriteLine("k8seAppName is null. tempPath=" + _tempPath);
}
else
{
_tempPath = Path.Combine(Path.GetTempPath(), k8seAppName);
Console.WriteLine("k8seAppName is " + k8seAppName +". tempPath=" + _tempPath);
}

_tempPath = Path.GetTempPath();
_repositoryPath = repositoryPath;
_zipTempPath = Path.Combine(_tempPath, Constants.ZipTempPath);
_webRootPath = Path.Combine(SiteRootPath, Constants.WebRoot);
Expand Down
36 changes: 5 additions & 31 deletions Kudu.Core/Infrastructure/DeploymentLockFile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.Threading;
using Kudu.Contracts.Infrastructure;
using Kudu.Contracts.SourceControl;
using Kudu.Core.Helpers;
using Kudu.Core.SourceControl;
Expand All @@ -11,49 +12,22 @@ namespace Kudu.Core.Infrastructure
/// <summary>
/// Specific to deployment lock.
/// </summary>
public class DeploymentLockFile : AllSafeLinuxLock
public class DeploymentLockFile
{
private static readonly ReaderWriterLockSlim rwl = new ReaderWriterLockSlim();
private readonly string _path;
private static DeploymentLockFile _deploymentLockFile;
private static IOperationLock _deploymentLockFile;
//private static AllSafeLinuxLock _linuxLock;

public static DeploymentLockFile GetInstance(string path, ITraceFactory traceFactory)
public static IOperationLock GetInstance(string path, ITraceFactory traceFactory)
{
if (_deploymentLockFile == null)
{
_deploymentLockFile = new DeploymentLockFile(path,traceFactory);
_deploymentLockFile = new NoOpLock();
}

return _deploymentLockFile;
}

private DeploymentLockFile(string path, ITraceFactory traceFactory) : base(path,traceFactory)
{
_path = path;
/*
if (!OSDetector.IsOnWindows())
{
_linuxLock = new LinuxLockFile(path+"_2",traceFactory);
_isLinux = true;
}
*/
}


public void OnLockAcquired()
{
IRepositoryFactory repositoryFactory = RepositoryFactory;
if (repositoryFactory != null)
{
IRepository repository = repositoryFactory.GetRepository();
if (repository != null)
{
// Clear any left over repository-related lock since we have the actual lock
repository.ClearLock();
}
}
}

}
}
4 changes: 2 additions & 2 deletions Kudu.Core/Infrastructure/LockFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ public virtual bool IsHeld

public LockFile(string path)
{
_lock = new WindowsLockFile(path);
_lock = new NoOpLock();

}

public LockFile(string path, ITraceFactory traceFactory, bool ensureLock = false)
{
_lock = new WindowsLockFile(path,traceFactory,ensureLock);
_lock = new NoOpLock();

}

Expand Down
35 changes: 35 additions & 0 deletions Kudu.Core/Infrastructure/NoOpLock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Kudu.Contracts.Infrastructure;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace Kudu.Core.Infrastructure
{
public class NoOpLock : IOperationLock
{
public bool IsHeld => false;

public OperationLockInfo LockInfo => new OperationLockInfo();

public void InitializeAsyncLocks()
{
//
}

public bool Lock(string operationName)
{
return true;
}

public Task LockAsync(string operationName)
{
return Task.Run(() => true);
}

public void Release()
{
//
}
}
}
11 changes: 9 additions & 2 deletions Kudu.Services.Web/KubeMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,17 @@ public async Task Invoke(HttpContext context, IEnvironment environment, IServerC
}

// Cache the App Environment for this request
context.Items.TryAdd("environment", GetEnvironment(homeDir, appName, null, null, appNamenamespace, appType));
if (!context.Items.ContainsKey("environment"))
{
Console.WriteLine("KubeMiddlware: adding environment. appName=" + appName + ",appType=" + appType);
context.Items.TryAdd("environment", GetEnvironment(homeDir, appName, null, null, appNamenamespace, appType));
}

// Cache the appName for this request
context.Items.TryAdd("appName", appName);
if (!context.Items.ContainsKey("appName")) {
Console.WriteLine("KubeMiddlware: appName=" + appName);
context.Items.TryAdd("appName", appName);
}

// Add All AppSettings to the context.
K8SEDeploymentHelper.UpdateContextWithAppSettings(context);
Expand Down
8 changes: 3 additions & 5 deletions Kudu.Services.Web/KuduWebUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ internal static class KuduWebUtil

private static Dictionary<string, IOperationLock> _namedLocks;

private static DeploymentLockFile _deploymentLock;
private static IOperationLock _deploymentLock;

// <summary>
// This method initializes status,ssh,hooks & deployment locks used by Kudu to ensure
Expand Down Expand Up @@ -81,9 +81,7 @@ private static void SetupLocks(ITraceFactory traceFactory, IEnvironment environm
var statusLockPath = Path.Combine(lockPath, Constants.StatusLockFile);
var sshKeyLockPath = Path.Combine(lockPath, Constants.SSHKeyLockFile);
var hooksLockPath = Path.Combine(lockPath, Constants.HooksLockFile);
_deploymentLock = DeploymentLockFile.GetInstance(deploymentLockPath, traceFactory);
_deploymentLock.InitializeAsyncLocks();

_deploymentLock = new NoOpLock();
var statusLock = new LockFile(statusLockPath, traceFactory);
statusLock.InitializeAsyncLocks();
var sshKeyLock = new LockFile(sshKeyLockPath, traceFactory);
Expand Down Expand Up @@ -470,7 +468,7 @@ internal static void EnsureDotNetCoreEnvironmentVariable(IEnvironment environmen
/// <param name="traceFactory"></param>
/// <param name="environment"></param>
/// <returns></returns>
internal static DeploymentLockFile GetDeploymentLock(ITraceFactory traceFactory, IEnvironment environment)
internal static IOperationLock GetDeploymentLock(ITraceFactory traceFactory, IEnvironment environment)
{
if (_namedLocks == null || _deploymentLock == null)
{
Expand Down
6 changes: 0 additions & 6 deletions Kudu.Services.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,6 @@ public void ConfigureServices(IServiceCollection services)

services.AddScoped<ISSHKeyManager, SSHKeyManager>();

services.AddScoped<IRepositoryFactory>(
sp => KuduWebUtil.GetDeploymentLock(traceFactory, environment).RepositoryFactory =
new RepositoryFactory(
sp.GetRequiredService<IEnvironment>(), sp.GetRequiredService<IDeploymentSettingsManager>(),
sp.GetRequiredService<ITraceFactory>()));

services.AddScoped<IApplicationLogsReader, ApplicationLogsReader>();

// Git server
Expand Down