Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ dist
*.user
.env
*.xmldocs.xml
**/CONDUCTORSHARP_HEALTH.json
23 changes: 23 additions & 0 deletions docker-compose.override.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
version: '3.4'

services:

conductorsharp.noapi:
healthcheck:
test: bash -c "[ -f /app/CONDUCTORSHARP_HEALTH.json ]"
interval: 60s
retries: 5
start_period: 20s
timeout: 10s

conductorsharp.definitions:
healthcheck:
test: bash -c "[ -f /app/CONDUCTORSHARP_HEALTH.json ]"
interval: 60s
retries: 5
start_period: 20s
timeout: 10s

conductorsharp.apienabled:
healthcheck:
test: bash -c "[ -f /app/CONDUCTORSHARP_HEALTH.json ]"
interval: 60s
retries: 5
start_period: 20s
timeout: 10s
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Autofac;
using ConductorSharp.Engine.Extensions;
using ConductorSharp.Engine.Health;
using MediatR.Extensions.Autofac.DependencyInjection;

namespace ConductorSharp.ApiEnabled.Extensions;
Expand All @@ -22,6 +23,7 @@ public static IHostBuilder ConfigureApiEnabled(this IHostBuilder hostBuilder, Co
longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
domain: configuration.GetValue<string>("Conductor:WorkerDomain")
)
.SetHealthCheckService<FileHealthService>()
.AddPipelines(pipelines =>
{
pipelines.AddContextLogging();
Expand Down
4 changes: 4 additions & 0 deletions examples/ConductorSharp.ApiEnabled/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Autofac.Extensions.DependencyInjection;
using ConductorSharp.ApiEnabled.Extensions;
using ConductorSharp.Engine.Health;
using ConductorSharp.Engine.Util;
using Serilog;

Expand All @@ -12,6 +13,7 @@
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddHealthChecks().AddCheck<ConductorSharpHealthCheck>("running");

//Autofac dependency injection
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureApiEnabled(configuration);
Expand All @@ -26,5 +28,7 @@
}

app.UseAuthorization();

app.MapControllers();
app.MapHealthChecks("/health");
app.Run();
2 changes: 2 additions & 0 deletions examples/ConductorSharp.Definitions/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Autofac.Extensions.DependencyInjection;
using ConductorSharp.Definitions;
using ConductorSharp.Engine.Extensions;
using ConductorSharp.Engine.Health;
using MediatR.Extensions.Autofac.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -39,6 +40,7 @@
longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
domain: configuration.GetValue<string>("Conductor:WorkerDomain")
)
.SetHealthCheckService<FileHealthService>()
.AddPipelines(pipelines =>
{
pipelines.AddRequestResponseLogging();
Expand Down
2 changes: 1 addition & 1 deletion examples/ConductorSharp.Definitions/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"LongPollInterval": 100,
"MaxConcurrentWorkers": 10,
"SleepInterval": 500,
"PreventErrorOnBadRequest": false
"PreventErrorOnBadRequest": true
}
}
2 changes: 2 additions & 0 deletions examples/ConductorSharp.NoApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using ConductorSharp.Engine.Extensions;
using ConductorSharp.Engine.Health;
using ConductorSharp.NoApi;
using MediatR.Extensions.Autofac.DependencyInjection;
using Microsoft.Extensions.Configuration;
Expand Down Expand Up @@ -39,6 +40,7 @@
longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
domain: configuration.GetValue<string>("Conductor:WorkerDomain")
)
.SetHealthCheckService<FileHealthService>()
.AddPipelines(pipelines =>
{
pipelines.AddContextLogging();
Expand Down
2 changes: 1 addition & 1 deletion examples/ConductorSharp.NoApi/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"LongPollInterval": 100,
"MaxConcurrentWorkers": 10,
"SleepInterval": 500,
"PreventErrorOnBadRequest": true
"PreventErrorOnBadRequest": false
}
}
1 change: 1 addition & 0 deletions src/ConductorSharp.Engine/ConductorSharp.Engine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ItemGroup>
<PackageReference Include="Autofac" Version="6.3.0" />
<PackageReference Include="MediatR" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="6.0.9" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
<PackageReference Include="Serilog" Version="2.12.0" />
Expand Down
3 changes: 2 additions & 1 deletion src/ConductorSharp.Engine/ExecutionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
using System.Threading.Tasks;
using Autofac;
using ConductorSharp.Engine.Util;
using ConductorSharp.Engine.Health;
using ConductorSharp.Engine.Polling;

namespace ConductorSharp.Engine
{
public class ExecutionManager
internal class ExecutionManager
{
private readonly SemaphoreSlim _semaphore;
private readonly WorkerSetConfig _configuration;
Expand Down
9 changes: 9 additions & 0 deletions src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Autofac;
using ConductorSharp.Engine.Behaviors;
using ConductorSharp.Engine.Health;
using ConductorSharp.Engine.Interface;
using ConductorSharp.Engine.Polling;
using ConductorSharp.Engine.Service;
Expand Down Expand Up @@ -40,6 +41,8 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in

_builder.RegisterType<ConductorSharpExecutionContext>().InstancePerLifetimeScope();

_builder.RegisterType<InMemoryHealthService>().As<IConductorSharpHealthService>().SingleInstance();

_builder.RegisterType<InverseExponentialBackoff>().As<IPollTimingStrategy>();

_builder.RegisterType<RandomOrdering>().As<IPollOrderStrategy>();
Expand All @@ -59,5 +62,11 @@ public void AddRequestResponseLogging() =>
public void AddValidation() => _builder.RegisterGeneric(typeof(ValidationBehavior<,>)).As(typeof(IPipelineBehavior<,>));

public void AddContextLogging() => _builder.RegisterGeneric(typeof(ContextLoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));

public IExecutionManagerBuilder SetHealthCheckService<T>() where T : IConductorSharpHealthService
{
_builder.RegisterType<T>().As<IConductorSharpHealthService>().SingleInstance();
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using ConductorSharp.Engine.Health;
using System;
using System.Collections.Generic;
using System.Text;

Expand All @@ -7,5 +8,6 @@ namespace ConductorSharp.Engine.Extensions
public interface IExecutionManagerBuilder
{
IExecutionManagerBuilder AddPipelines(Action<IPipelineBuilder> pipelines);
IExecutionManagerBuilder SetHealthCheckService<T>() where T : IConductorSharpHealthService;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Autofac;
using ConductorSharp.Engine.Behaviors;
using ConductorSharp.Engine.Health;
using ConductorSharp.Engine.Interface;
using ConductorSharp.Engine.Polling;
using ConductorSharp.Engine.Service;
Expand Down
33 changes: 33 additions & 0 deletions src/ConductorSharp.Engine/Health/ConductorSharpHealthCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConductorSharp.Engine.Health
{
public class ConductorSharpHealthCheck : IHealthCheck
{
private readonly IConductorSharpHealthService _healthService;

public ConductorSharpHealthCheck(IConductorSharpHealthService healthService)
{
_healthService = healthService;
}

public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
var healthData = await _healthService.GetHealthData(cancellationToken);

if (healthData.IsExecutionManagerRunning)
{
return new HealthCheckResult(HealthStatus.Healthy, "Deployment has been completed and Execution Manager is running");
}
else
{
return new HealthCheckResult(context.Registration.FailureStatus, "Execution Manager is not running");
}
}
}
}
80 changes: 80 additions & 0 deletions src/ConductorSharp.Engine/Health/FileHealthService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConductorSharp.Engine.Health
{
public class HealthData
{
public bool IsExecutionManagerRunning { get; set; }
}

public class FileHealthService : IConductorSharpHealthService
{
private readonly SemaphoreSlim _semaphore = new(1);

private const string HealthFileName = "CONDUCTORSHARP_HEALTH.json";

public async Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default) =>
await UpdateData(data => data.IsExecutionManagerRunning = false, cancellationToken);

public async Task SetExecutionManagerRunning(CancellationToken cancellationToken = default) =>
await UpdateData(data => data.IsExecutionManagerRunning = true, cancellationToken);

private async Task UpdateData(Action<HealthData> updateHealthData, CancellationToken cancellationToken = default)
{
var data = await GetHealthData(cancellationToken);
updateHealthData(data);
await WriteHealthData(data, cancellationToken);
}

public async Task<HealthData> GetHealthData(CancellationToken cancellationToken = default)
{
try
{
await _semaphore.WaitAsync(cancellationToken);
if (!File.Exists(HealthFileName))
{
return new HealthData();
}
else
{
return JsonConvert.DeserializeObject<HealthData>(await File.ReadAllTextAsync(HealthFileName, cancellationToken))
?? new HealthData();
}
}
finally
{
_semaphore.Release();
}
}

private async Task WriteHealthData(HealthData healthData, CancellationToken cancellationToken = default)
{
try
{
await _semaphore.WaitAsync(cancellationToken);
await File.WriteAllTextAsync(HealthFileName, JsonConvert.SerializeObject(healthData), cancellationToken);
}
finally
{
_semaphore.Release();
}
}

public async Task ResetHealthData(CancellationToken cancellationToken = default) =>
await WriteHealthData(new HealthData(), cancellationToken);

public void RemoveHealthData()
{
if (File.Exists(HealthFileName))
File.Delete(HealthFileName);

return;
}
}
}
17 changes: 17 additions & 0 deletions src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConductorSharp.Engine.Health
{
public interface IConductorSharpHealthService
{
Task<HealthData> GetHealthData(CancellationToken cancellationToken = default);
Task ResetHealthData(CancellationToken cancellationToken = default);
void RemoveHealthData();
Task SetExecutionManagerRunning(CancellationToken cancellationToken = default);
Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default);
}
}
38 changes: 38 additions & 0 deletions src/ConductorSharp.Engine/Health/InMemoryHealthService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConductorSharp.Engine.Health
{
public class InMemoryHealthService : IConductorSharpHealthService
{
private static bool _isExecutionManagerRunning;

public Task<HealthData> GetHealthData(CancellationToken cancellationToken = default)
{
return Task.FromResult(new HealthData { IsExecutionManagerRunning = _isExecutionManagerRunning });
}

public void RemoveHealthData() { }

public Task ResetHealthData(CancellationToken cancellationToken = default)
{
_isExecutionManagerRunning = false;
return Task.CompletedTask;
}

public Task SetExecutionManagerRunning(CancellationToken cancellationToken = default)
{
_isExecutionManagerRunning = true;
return Task.CompletedTask;
}

public Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default)
{
_isExecutionManagerRunning = false;
return Task.CompletedTask;
}
}
}
3 changes: 2 additions & 1 deletion src/ConductorSharp.Engine/Service/DeploymentService.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using ConductorSharp.Client.Service;
using ConductorSharp.Engine.Health;
using ConductorSharp.Engine.Interface;
using ConductorSharp.Engine.Model;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace ConductorSharp.Engine.Service
{
public class DeploymentService : IDeploymentService
internal class DeploymentService : IDeploymentService
{
private readonly IMetadataService _metadataService;

Expand Down
Loading