From 6b31ddad73ddbc7f882ee305f27c271538134a1f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 14:23:23 +0200
Subject: [PATCH 1/7] add health checks

---
 .gitignore                                    |  1 +
 examples/ConductorSharp.ApiEnabled/Program.cs |  4 +
 .../Generated/Task.cs                         |  2 +-
 .../ConductorSharp.Engine.csproj              |  1 +
 src/ConductorSharp.Engine/ExecutionManager.cs |  9 +-
 .../Extensions/ConductorSharpBuilder.cs       |  3 +
 .../Extensions/WorkflowEngineBuilder.cs       |  3 +
 .../Health/ConductorSharpHealthService.cs     | 84 +++++++++++++++++++
 .../Health/DeploymentHealthCheck.cs           | 33 ++++++++
 .../Health/IConductorSharpHealthService.cs    | 12 +++
 .../Health/IConductorSharpHealthUpdater.cs    | 18 ++++
 .../Service/DeploymentService.cs              |  9 +-
 .../WorkflowEngineBackgroundService.cs        | 21 ++++-
 13 files changed, 191 insertions(+), 9 deletions(-)
 create mode 100644 src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
 create mode 100644 src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs
 create mode 100644 src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
 create mode 100644 src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs

diff --git a/.gitignore b/.gitignore
index b5457435..fd2d83a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ dist
 *.user
 .env
 *.xmldocs.xml
+**/CONDUCTORSHARP_HEALTH.json
\ No newline at end of file
diff --git a/examples/ConductorSharp.ApiEnabled/Program.cs b/examples/ConductorSharp.ApiEnabled/Program.cs
index dc2ddbe9..e8f1eb7b 100644
--- a/examples/ConductorSharp.ApiEnabled/Program.cs
+++ b/examples/ConductorSharp.ApiEnabled/Program.cs
@@ -1,5 +1,6 @@
 using Autofac.Extensions.DependencyInjection;
 using ConductorSharp.ApiEnabled.Extensions;
+using ConductorSharp.Engine.Health;
 using ConductorSharp.Engine.Util;
 using Serilog;
 
@@ -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<DeploymentHealthCheck>("deployment");
 
 //Autofac dependency injection
 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureApiEnabled(configuration);
@@ -26,5 +28,7 @@
 }
 
 app.UseAuthorization();
+
 app.MapControllers();
+app.MapHealthChecks("/health");
 app.Run();
diff --git a/examples/ConductorSharp.Definitions/Generated/Task.cs b/examples/ConductorSharp.Definitions/Generated/Task.cs
index d1afab87..68f05da4 100644
--- a/examples/ConductorSharp.Definitions/Generated/Task.cs
+++ b/examples/ConductorSharp.Definitions/Generated/Task.cs
@@ -28,7 +28,7 @@ public partial class EmailPrepareV1Output
     /// <originalName>
     /// EMAIL_prepare
     /// </originalName>
-    [OriginalName("EMAIL_prepare")]
+    [OriginalName("EMAILs_prepare")]
     public partial class EmailPrepareV1 : SimpleTaskModel<EmailPrepareV1Input, EmailPrepareV1Output> { }
 
     public partial class CustomerGetV1Input : IRequest<CustomerGetV1Output>
diff --git a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj
index bd020c6f..f3116732 100644
--- a/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj
+++ b/src/ConductorSharp.Engine/ConductorSharp.Engine.csproj
@@ -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" />
diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs
index 82fd77dc..67a203ae 100644
--- a/src/ConductorSharp.Engine/ExecutionManager.cs
+++ b/src/ConductorSharp.Engine/ExecutionManager.cs
@@ -12,10 +12,11 @@
 using System.Threading.Tasks;
 using Autofac;
 using ConductorSharp.Engine.Util;
+using ConductorSharp.Engine.Health;
 
 namespace ConductorSharp.Engine
 {
-    public class ExecutionManager
+    internal class ExecutionManager
     {
         private readonly SemaphoreSlim _semaphore;
         private readonly WorkerSetConfig _configuration;
@@ -23,6 +24,7 @@ public class ExecutionManager
         private readonly ITaskService _taskManager;
         private readonly IEnumerable<TaskToWorker> _registeredWorkers;
         private readonly ILifetimeScope _lifetimeScope;
+        private readonly IConductorSharpHealthUpdater _healthUpdater;
 
         // TODO: Implement polling strategy so that if there
         // are no requests incoming we poll less, and when queues are full
@@ -38,7 +40,8 @@ public ExecutionManager(
             ILogger<ExecutionManager> logger,
             ITaskService taskService,
             IEnumerable<TaskToWorker> workerMappings,
-            ILifetimeScope lifetimeScope
+            ILifetimeScope lifetimeScope,
+            IConductorSharpHealthUpdater healthUpdater
         )
         {
             _configuration = options;
@@ -47,10 +50,12 @@ ILifetimeScope lifetimeScope
             _taskManager = taskService;
             _registeredWorkers = workerMappings;
             _lifetimeScope = lifetimeScope;
+            _healthUpdater = healthUpdater;
         }
 
         public async Task StartAsync(CancellationToken cancellationToken)
         {
+            await _healthUpdater.SetExecutionManagerStarted();
             while (!cancellationToken.IsCancellationRequested)
             {
                 var scheduleQueue = await _taskManager.GetAllQueues();
diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
index 4d55e2b6..29331de7 100644
--- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
@@ -1,5 +1,6 @@
 ﻿using Autofac;
 using ConductorSharp.Engine.Behaviors;
+using ConductorSharp.Engine.Health;
 using ConductorSharp.Engine.Interface;
 using ConductorSharp.Engine.Service;
 using ConductorSharp.Engine.Util;
@@ -39,6 +40,8 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in
 
             _builder.RegisterType<ConductorSharpExecutionContext>().InstancePerLifetimeScope();
 
+            _builder.RegisterType<ConductorSharpHealthService>().AsImplementedInterfaces();
+
             return this;
         }
 
diff --git a/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs b/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
index 3ddcc654..31629bf0 100644
--- a/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
@@ -1,5 +1,6 @@
 ﻿using Autofac;
 using ConductorSharp.Engine.Behaviors;
+using ConductorSharp.Engine.Health;
 using ConductorSharp.Engine.Interface;
 using ConductorSharp.Engine.Service;
 using ConductorSharp.Engine.Util;
@@ -44,6 +45,8 @@ public IWorkflowEngineExecutionManager AddExecutionManager(
 
             _builder.RegisterGeneric(typeof(ValidationBehavior<,>)).As(typeof(IPipelineBehavior<,>));
 
+            _builder.RegisterType<ConductorSharpHealthService>().AsImplementedInterfaces();
+
             return this;
         }
     }
diff --git a/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
new file mode 100644
index 00000000..e84b3b5a
--- /dev/null
+++ b/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
@@ -0,0 +1,84 @@
+﻿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
+{
+    internal interface One { }
+
+    public interface Two { }
+
+    public class HealthData
+    {
+        public bool IsDeploymentStarted { get; set; }
+        public bool IsDeploymentCompleted { get; set; }
+        public bool IsExecutionManagerStarted { get; set; }
+    }
+
+    public class ConductorSharpHealthService : IConductorSharpHealthService, IConductorSharpHealthUpdater
+    {
+        private static readonly SemaphoreSlim _semaphore = new(1);
+
+        private const string HealthFileName = "CONDUCTORSHARP_HEALTH.json";
+
+        public async Task SetDeploymentCompleted() => await UpdateData(data => data.IsDeploymentCompleted = true);
+
+        public async Task SetDeploymentStarted() => await UpdateData(data => data.IsDeploymentStarted = true);
+
+        public async Task SetExecutionManagerStarted() => await UpdateData(data => data.IsExecutionManagerStarted = true);
+
+        private async Task UpdateData(Action<HealthData> updateHealthData)
+        {
+            await _semaphore.WaitAsync();
+
+            try
+            {
+                var data = await GetHealthData();
+                updateHealthData(data);
+                await WriteHealthData(data);
+            }
+            finally
+            {
+                _semaphore.Release();
+            }
+        }
+
+        public async Task<HealthData> GetHealthData()
+        {
+            await _semaphore.WaitAsync();
+
+            try
+            {
+                if (!File.Exists(HealthFileName))
+                {
+                    return new HealthData();
+                }
+                else
+                {
+                    return JsonConvert.DeserializeObject<HealthData>(await File.ReadAllTextAsync(HealthFileName)) ?? new HealthData();
+                }
+            }
+            finally
+            {
+                _semaphore.Release();
+            }
+        }
+
+        private async Task WriteHealthData(HealthData healthData) =>
+            await File.WriteAllTextAsync(HealthFileName, JsonConvert.SerializeObject(healthData));
+
+        public async Task ResetHealthData() => await WriteHealthData(new HealthData());
+
+        public Task RemoveHealthData()
+        {
+            if (File.Exists(HealthFileName))
+                File.Delete(HealthFileName);
+
+            return Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs b/src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs
new file mode 100644
index 00000000..ec550d70
--- /dev/null
+++ b/src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs
@@ -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 DeploymentHealthCheck : IHealthCheck
+    {
+        private readonly IConductorSharpHealthService _healthService;
+
+        public DeploymentHealthCheck(IConductorSharpHealthService healthService)
+        {
+            _healthService = healthService;
+        }
+
+        public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
+        {
+            var healthData = await _healthService.GetHealthData();
+
+            if (healthData.IsDeploymentCompleted)
+            {
+                return new HealthCheckResult(HealthStatus.Healthy, "Deployment completed");
+            }
+            else
+            {
+                return new HealthCheckResult(context.Registration.FailureStatus, "Deployment not completed");
+            }
+        }
+    }
+}
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
new file mode 100644
index 00000000..bd3e7533
--- /dev/null
+++ b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
@@ -0,0 +1,12 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConductorSharp.Engine.Health
+{
+    public interface IConductorSharpHealthService
+    {
+        Task<HealthData> GetHealthData();
+    }
+}
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
new file mode 100644
index 00000000..2de70ca5
--- /dev/null
+++ b/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
@@ -0,0 +1,18 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConductorSharp.Engine.Health
+{
+    internal interface IConductorSharpHealthUpdater
+    {
+        Task ResetHealthData();
+        Task RemoveHealthData();
+        Task SetDeploymentCompleted();
+
+        Task SetDeploymentStarted();
+
+        Task SetExecutionManagerStarted();
+    }
+}
diff --git a/src/ConductorSharp.Engine/Service/DeploymentService.cs b/src/ConductorSharp.Engine/Service/DeploymentService.cs
index 6825b37b..f1aa3352 100644
--- a/src/ConductorSharp.Engine/Service/DeploymentService.cs
+++ b/src/ConductorSharp.Engine/Service/DeploymentService.cs
@@ -1,4 +1,5 @@
 ﻿using ConductorSharp.Client.Service;
+using ConductorSharp.Engine.Health;
 using ConductorSharp.Engine.Interface;
 using ConductorSharp.Engine.Model;
 using Microsoft.Extensions.Logging;
@@ -6,20 +7,23 @@
 
 namespace ConductorSharp.Engine.Service
 {
-    public class DeploymentService : IDeploymentService
+    internal class DeploymentService : IDeploymentService
     {
         private readonly IMetadataService _metadataService;
 
         private readonly ILogger<DeploymentService> _logger;
+        private readonly IConductorSharpHealthUpdater _healthUpdater;
 
-        public DeploymentService(IMetadataService metadataService, ILogger<DeploymentService> logger)
+        public DeploymentService(IMetadataService metadataService, ILogger<DeploymentService> logger, IConductorSharpHealthUpdater healthUpdater)
         {
             _metadataService = metadataService;
             _logger = logger;
+            _healthUpdater = healthUpdater;
         }
 
         public async Task Deploy(Deployment deployment)
         {
+            await _healthUpdater.SetDeploymentStarted();
             _logger.LogInformation("Deploying conductor definitions");
 
             if (deployment.TaskDefinitions.Count > 0)
@@ -35,6 +39,7 @@ public async Task Deploy(Deployment deployment)
             // TODO: Add registration for event handlers
 
             _logger.LogInformation("Finished deploying conductor definitions");
+            await _healthUpdater.SetDeploymentCompleted();
         }
 
         public async Task Remove(Deployment deployment)
diff --git a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
index 89dee1dd..d0d3ce85 100644
--- a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
+++ b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
@@ -1,22 +1,30 @@
-﻿using ConductorSharp.Engine.Interface;
+﻿using ConductorSharp.Engine.Health;
+using ConductorSharp.Engine.Interface;
 using Microsoft.Extensions.Hosting;
 using System.Threading;
 using System.Threading.Tasks;
 
 namespace ConductorSharp.Engine.Service
 {
-    public class WorkflowEngineBackgroundService : IHostedService
+    internal class WorkflowEngineBackgroundService : IHostedService
     {
         private readonly IDeploymentService _deploymentService;
         private readonly ExecutionManager _executionManager;
         private readonly ModuleDeployment _deployment;
+        private readonly IConductorSharpHealthUpdater _healthUpdater;
         private Task _executingTask;
 
-        public WorkflowEngineBackgroundService(IDeploymentService deploymentService, ExecutionManager executionManager, ModuleDeployment deployment)
+        public WorkflowEngineBackgroundService(
+            IDeploymentService deploymentService,
+            ExecutionManager executionManager,
+            ModuleDeployment deployment,
+            IConductorSharpHealthUpdater healthUpdater
+        )
         {
             _deploymentService = deploymentService;
             _executionManager = executionManager;
             _deployment = deployment;
+            _healthUpdater = healthUpdater;
         }
 
         public Task StartAsync(CancellationToken cancellationToken)
@@ -27,10 +35,15 @@ public Task StartAsync(CancellationToken cancellationToken)
 
         private async Task RunAsync(CancellationToken cancellationToken)
         {
+            await _healthUpdater.ResetHealthData();
             await _deploymentService.Deploy(_deployment);
             await _executionManager.StartAsync(cancellationToken);
         }
 
-        public async Task StopAsync(CancellationToken cancellationToken) => await _executingTask;
+        public async Task StopAsync(CancellationToken cancellationToken)
+        {
+            _healthUpdater.RemoveHealthData().Wait();
+            await _executingTask;
+        }
     }
 }

From 019fd1277cafef76d9185878365cce87862bb287 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 14:28:13 +0200
Subject: [PATCH 2/7] add missing comma

---
 src/ConductorSharp.Engine/ExecutionManager.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs
index 40e5abe2..2b4d4c49 100644
--- a/src/ConductorSharp.Engine/ExecutionManager.cs
+++ b/src/ConductorSharp.Engine/ExecutionManager.cs
@@ -35,7 +35,7 @@ public ExecutionManager(
             ITaskService taskService,
             IEnumerable<TaskToWorker> workerMappings,
             ILifetimeScope lifetimeScope,
-            IConductorSharpHealthUpdater healthUpdater
+            IConductorSharpHealthUpdater healthUpdater,
             IPollTimingStrategy pollTimingStrategy,
             IPollOrderStrategy pollOrderStrategy
         )

From 9bd6450794400d35465552d24eebe4167d1bafbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 14:28:40 +0200
Subject: [PATCH 3/7] add missing comma

---
 .../Service/WorkflowEngineBackgroundService.cs                  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
index cd6a8f07..3c2d27f1 100644
--- a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
+++ b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
@@ -20,7 +20,7 @@ internal class WorkflowEngineBackgroundService : IHostedService, IDisposable
         private readonly CancellationTokenSource _stoppingCts = new();
 
         public WorkflowEngineBackgroundService(
-            IConductorSharpHealthUpdater healthUpdater
+            IConductorSharpHealthUpdater healthUpdater,
             ILogger<WorkflowEngineBackgroundService> logger,
             IHostApplicationLifetime hostApplicationLifetime,
             IDeploymentService deploymentService,

From bafdaeb330ae08d03b723454dd586cb55d786542 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 15:01:25 +0200
Subject: [PATCH 4/7] update services

---
 examples/ConductorSharp.ApiEnabled/Program.cs |  2 +-
 src/ConductorSharp.Engine/ExecutionManager.cs |  4 --
 ...hCheck.cs => ConductorSharpHealthCheck.cs} | 12 ++--
 .../Health/ConductorSharpHealthService.cs     | 62 +++++++++----------
 .../Health/IConductorSharpHealthService.cs    |  3 +-
 .../Health/IConductorSharpHealthUpdater.cs    | 12 ++--
 .../Service/DeploymentService.cs              |  6 +-
 .../WorkflowEngineBackgroundService.cs        |  6 +-
 8 files changed, 48 insertions(+), 59 deletions(-)
 rename src/ConductorSharp.Engine/Health/{DeploymentHealthCheck.cs => ConductorSharpHealthCheck.cs} (69%)

diff --git a/examples/ConductorSharp.ApiEnabled/Program.cs b/examples/ConductorSharp.ApiEnabled/Program.cs
index e8f1eb7b..a1ee324e 100644
--- a/examples/ConductorSharp.ApiEnabled/Program.cs
+++ b/examples/ConductorSharp.ApiEnabled/Program.cs
@@ -13,7 +13,7 @@
 // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
 builder.Services.AddEndpointsApiExplorer();
 builder.Services.AddSwaggerGen();
-builder.Services.AddHealthChecks().AddCheck<DeploymentHealthCheck>("deployment");
+builder.Services.AddHealthChecks().AddCheck<ConductorSharpHealthCheck>("running");
 
 //Autofac dependency injection
 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureApiEnabled(configuration);
diff --git a/src/ConductorSharp.Engine/ExecutionManager.cs b/src/ConductorSharp.Engine/ExecutionManager.cs
index 2b4d4c49..e8cefe68 100644
--- a/src/ConductorSharp.Engine/ExecutionManager.cs
+++ b/src/ConductorSharp.Engine/ExecutionManager.cs
@@ -25,7 +25,6 @@ internal class ExecutionManager
         private readonly ITaskService _taskManager;
         private readonly IEnumerable<TaskToWorker> _registeredWorkers;
         private readonly ILifetimeScope _lifetimeScope;
-        private readonly IConductorSharpHealthUpdater _healthUpdater;
         private readonly IPollTimingStrategy _pollTimingStrategy;
         private readonly IPollOrderStrategy _pollOrderStrategy;
 
@@ -35,7 +34,6 @@ public ExecutionManager(
             ITaskService taskService,
             IEnumerable<TaskToWorker> workerMappings,
             ILifetimeScope lifetimeScope,
-            IConductorSharpHealthUpdater healthUpdater,
             IPollTimingStrategy pollTimingStrategy,
             IPollOrderStrategy pollOrderStrategy
         )
@@ -46,14 +44,12 @@ IPollOrderStrategy pollOrderStrategy
             _taskManager = taskService;
             _registeredWorkers = workerMappings;
             _lifetimeScope = lifetimeScope;
-            _healthUpdater = healthUpdater;
             _pollTimingStrategy = pollTimingStrategy;
             _pollOrderStrategy = pollOrderStrategy;
         }
 
         public async Task StartAsync(CancellationToken cancellationToken)
         {
-            await _healthUpdater.SetExecutionManagerStarted();
             var currentSleepInterval = _configuration.SleepInterval;
 
             while (!cancellationToken.IsCancellationRequested)
diff --git a/src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs b/src/ConductorSharp.Engine/Health/ConductorSharpHealthCheck.cs
similarity index 69%
rename from src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs
rename to src/ConductorSharp.Engine/Health/ConductorSharpHealthCheck.cs
index ec550d70..462c0b3b 100644
--- a/src/ConductorSharp.Engine/Health/DeploymentHealthCheck.cs
+++ b/src/ConductorSharp.Engine/Health/ConductorSharpHealthCheck.cs
@@ -7,26 +7,26 @@
 
 namespace ConductorSharp.Engine.Health
 {
-    public class DeploymentHealthCheck : IHealthCheck
+    public class ConductorSharpHealthCheck : IHealthCheck
     {
         private readonly IConductorSharpHealthService _healthService;
 
-        public DeploymentHealthCheck(IConductorSharpHealthService healthService)
+        public ConductorSharpHealthCheck(IConductorSharpHealthService healthService)
         {
             _healthService = healthService;
         }
 
         public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
         {
-            var healthData = await _healthService.GetHealthData();
+            var healthData = await _healthService.GetHealthData(cancellationToken);
 
-            if (healthData.IsDeploymentCompleted)
+            if (healthData.IsExecutionManagerRunning)
             {
-                return new HealthCheckResult(HealthStatus.Healthy, "Deployment completed");
+                return new HealthCheckResult(HealthStatus.Healthy, "Deployment has been completed and Execution Manager is running");
             }
             else
             {
-                return new HealthCheckResult(context.Registration.FailureStatus, "Deployment not completed");
+                return new HealthCheckResult(context.Registration.FailureStatus, "Execution Manager is not running");
             }
         }
     }
diff --git a/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
index e84b3b5a..20a7fcd5 100644
--- a/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
+++ b/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
@@ -8,15 +8,9 @@
 
 namespace ConductorSharp.Engine.Health
 {
-    internal interface One { }
-
-    public interface Two { }
-
     public class HealthData
     {
-        public bool IsDeploymentStarted { get; set; }
-        public bool IsDeploymentCompleted { get; set; }
-        public bool IsExecutionManagerStarted { get; set; }
+        public bool IsExecutionManagerRunning { get; set; }
     }
 
     public class ConductorSharpHealthService : IConductorSharpHealthService, IConductorSharpHealthUpdater
@@ -25,41 +19,32 @@ public class ConductorSharpHealthService : IConductorSharpHealthService, IConduc
 
         private const string HealthFileName = "CONDUCTORSHARP_HEALTH.json";
 
-        public async Task SetDeploymentCompleted() => await UpdateData(data => data.IsDeploymentCompleted = true);
-
-        public async Task SetDeploymentStarted() => await UpdateData(data => data.IsDeploymentStarted = true);
+        public async Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default) =>
+            await UpdateData(data => data.IsExecutionManagerRunning = false, cancellationToken);
 
-        public async Task SetExecutionManagerStarted() => await UpdateData(data => data.IsExecutionManagerStarted = true);
+        public async Task SetExecutionManagerRunning(CancellationToken cancellationToken = default) =>
+            await UpdateData(data => data.IsExecutionManagerRunning = true, cancellationToken);
 
-        private async Task UpdateData(Action<HealthData> updateHealthData)
+        private async Task UpdateData(Action<HealthData> updateHealthData, CancellationToken cancellationToken = default)
         {
-            await _semaphore.WaitAsync();
-
-            try
-            {
-                var data = await GetHealthData();
-                updateHealthData(data);
-                await WriteHealthData(data);
-            }
-            finally
-            {
-                _semaphore.Release();
-            }
+            var data = await GetHealthData(cancellationToken);
+            updateHealthData(data);
+            await WriteHealthData(data, cancellationToken);
         }
 
-        public async Task<HealthData> GetHealthData()
+        public async Task<HealthData> GetHealthData(CancellationToken cancellationToken = default)
         {
-            await _semaphore.WaitAsync();
-
             try
             {
+                await _semaphore.WaitAsync(cancellationToken);
                 if (!File.Exists(HealthFileName))
                 {
                     return new HealthData();
                 }
                 else
                 {
-                    return JsonConvert.DeserializeObject<HealthData>(await File.ReadAllTextAsync(HealthFileName)) ?? new HealthData();
+                    return JsonConvert.DeserializeObject<HealthData>(await File.ReadAllTextAsync(HealthFileName, cancellationToken))
+                        ?? new HealthData();
                 }
             }
             finally
@@ -68,17 +53,28 @@ public async Task<HealthData> GetHealthData()
             }
         }
 
-        private async Task WriteHealthData(HealthData healthData) =>
-            await File.WriteAllTextAsync(HealthFileName, JsonConvert.SerializeObject(healthData));
+        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() => await WriteHealthData(new HealthData());
+        public async Task ResetHealthData(CancellationToken cancellationToken = default) =>
+            await WriteHealthData(new HealthData(), cancellationToken);
 
-        public Task RemoveHealthData()
+        public void RemoveHealthData()
         {
             if (File.Exists(HealthFileName))
                 File.Delete(HealthFileName);
 
-            return Task.CompletedTask;
+            return;
         }
     }
 }
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
index bd3e7533..6a4ec694 100644
--- a/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
+++ b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
@@ -1,12 +1,13 @@
 ﻿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();
+        Task<HealthData> GetHealthData(CancellationToken cancellationToken = default);
     }
 }
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
index 2de70ca5..ee1078ca 100644
--- a/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
+++ b/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
@@ -1,18 +1,16 @@
 ﻿using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
 
 namespace ConductorSharp.Engine.Health
 {
     internal interface IConductorSharpHealthUpdater
     {
-        Task ResetHealthData();
-        Task RemoveHealthData();
-        Task SetDeploymentCompleted();
-
-        Task SetDeploymentStarted();
-
-        Task SetExecutionManagerStarted();
+        Task ResetHealthData(CancellationToken cancellationToken = default);
+        void RemoveHealthData();
+        Task SetExecutionManagerRunning(CancellationToken cancellationToken = default);
+        Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default);
     }
 }
diff --git a/src/ConductorSharp.Engine/Service/DeploymentService.cs b/src/ConductorSharp.Engine/Service/DeploymentService.cs
index f1aa3352..59d4f814 100644
--- a/src/ConductorSharp.Engine/Service/DeploymentService.cs
+++ b/src/ConductorSharp.Engine/Service/DeploymentService.cs
@@ -12,18 +12,15 @@ internal class DeploymentService : IDeploymentService
         private readonly IMetadataService _metadataService;
 
         private readonly ILogger<DeploymentService> _logger;
-        private readonly IConductorSharpHealthUpdater _healthUpdater;
 
-        public DeploymentService(IMetadataService metadataService, ILogger<DeploymentService> logger, IConductorSharpHealthUpdater healthUpdater)
+        public DeploymentService(IMetadataService metadataService, ILogger<DeploymentService> logger)
         {
             _metadataService = metadataService;
             _logger = logger;
-            _healthUpdater = healthUpdater;
         }
 
         public async Task Deploy(Deployment deployment)
         {
-            await _healthUpdater.SetDeploymentStarted();
             _logger.LogInformation("Deploying conductor definitions");
 
             if (deployment.TaskDefinitions.Count > 0)
@@ -39,7 +36,6 @@ public async Task Deploy(Deployment deployment)
             // TODO: Add registration for event handlers
 
             _logger.LogInformation("Finished deploying conductor definitions");
-            await _healthUpdater.SetDeploymentCompleted();
         }
 
         public async Task Remove(Deployment deployment)
diff --git a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
index 3c2d27f1..a998f4f6 100644
--- a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
+++ b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
@@ -52,12 +52,14 @@ private async Task RunAsync(CancellationToken cancellationToken)
         {
             try
             {
-                await _healthUpdater.ResetHealthData();
+                await _healthUpdater.ResetHealthData(cancellationToken);
                 await _deploymentService.Deploy(_deployment);
+                await _healthUpdater.SetExecutionManagerRunning(cancellationToken);
                 await _executionManager.StartAsync(cancellationToken);
             }
             catch (Exception exception)
             {
+                await _healthUpdater.UnsetExecutionManagerRunning();
                 _logger.LogCritical(exception, "Workflow Engine Background Service encountered an error");
                 throw;
             }
@@ -69,7 +71,7 @@ private async Task RunAsync(CancellationToken cancellationToken)
 
         public async Task StopAsync(CancellationToken cancellationToken)
         {
-            _healthUpdater.RemoveHealthData().Wait();
+            _healthUpdater.RemoveHealthData();
             if (_executingTask == null)
             {
                 return;

From c913048eb52c485174eba6dade791a9abff996d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 15:06:08 +0200
Subject: [PATCH 5/7] update settings

---
 examples/ConductorSharp.Definitions/Generated/Task.cs | 2 +-
 examples/ConductorSharp.Definitions/appsettings.json  | 2 +-
 examples/ConductorSharp.NoApi/appsettings.json        | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/examples/ConductorSharp.Definitions/Generated/Task.cs b/examples/ConductorSharp.Definitions/Generated/Task.cs
index 68f05da4..d1afab87 100644
--- a/examples/ConductorSharp.Definitions/Generated/Task.cs
+++ b/examples/ConductorSharp.Definitions/Generated/Task.cs
@@ -28,7 +28,7 @@ public partial class EmailPrepareV1Output
     /// <originalName>
     /// EMAIL_prepare
     /// </originalName>
-    [OriginalName("EMAILs_prepare")]
+    [OriginalName("EMAIL_prepare")]
     public partial class EmailPrepareV1 : SimpleTaskModel<EmailPrepareV1Input, EmailPrepareV1Output> { }
 
     public partial class CustomerGetV1Input : IRequest<CustomerGetV1Output>
diff --git a/examples/ConductorSharp.Definitions/appsettings.json b/examples/ConductorSharp.Definitions/appsettings.json
index fa169067..c3c5ffd3 100644
--- a/examples/ConductorSharp.Definitions/appsettings.json
+++ b/examples/ConductorSharp.Definitions/appsettings.json
@@ -5,6 +5,6 @@
     "LongPollInterval": 100,
     "MaxConcurrentWorkers": 10,
     "SleepInterval": 500,
-    "PreventErrorOnBadRequest": false
+    "PreventErrorOnBadRequest": true
   }
 }
diff --git a/examples/ConductorSharp.NoApi/appsettings.json b/examples/ConductorSharp.NoApi/appsettings.json
index c3c5ffd3..fa169067 100644
--- a/examples/ConductorSharp.NoApi/appsettings.json
+++ b/examples/ConductorSharp.NoApi/appsettings.json
@@ -5,6 +5,6 @@
     "LongPollInterval": 100,
     "MaxConcurrentWorkers": 10,
     "SleepInterval": 500,
-    "PreventErrorOnBadRequest": true
+    "PreventErrorOnBadRequest": false
   }
 }

From 05b9dcac474e6712258d42ed4f3ff5c0a0521395 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 19:55:29 +0200
Subject: [PATCH 6/7] add services

---
 .../ConductorSharp.Definitions/Program.cs     |  2 +
 examples/ConductorSharp.NoApi/Program.cs      |  2 +
 .../Extensions/ConductorSharpBuilder.cs       |  9 ++++-
 .../Extensions/IExecutionManagerBuilder.cs    |  4 +-
 .../Extensions/WorkflowEngineBuilder.cs       |  1 -
 ....cs => ConductorSharpFileHealthService.cs} |  2 +-
 .../Health/IConductorSharpHealthService.cs    |  4 ++
 .../Health/IConductorSharpHealthUpdater.cs    | 16 --------
 .../Health/InMemoryHealthService.cs           | 38 +++++++++++++++++++
 .../WorkflowEngineBackgroundService.cs        | 14 +++----
 10 files changed, 65 insertions(+), 27 deletions(-)
 rename src/ConductorSharp.Engine/Health/{ConductorSharpHealthService.cs => ConductorSharpFileHealthService.cs} (96%)
 delete mode 100644 src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
 create mode 100644 src/ConductorSharp.Engine/Health/InMemoryHealthService.cs

diff --git a/examples/ConductorSharp.Definitions/Program.cs b/examples/ConductorSharp.Definitions/Program.cs
index 206b32bd..46959966 100644
--- a/examples/ConductorSharp.Definitions/Program.cs
+++ b/examples/ConductorSharp.Definitions/Program.cs
@@ -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;
@@ -39,6 +40,7 @@
                     longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
                     domain: configuration.GetValue<string>("Conductor:WorkerDomain")
                 )
+                .SetHealthCheckService<ConductorSharpFileHealthService>()
                 .AddPipelines(pipelines =>
                 {
                     pipelines.AddRequestResponseLogging();
diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs
index 1f712530..3072a646 100644
--- a/examples/ConductorSharp.NoApi/Program.cs
+++ b/examples/ConductorSharp.NoApi/Program.cs
@@ -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;
@@ -39,6 +40,7 @@
                     longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
                     domain: configuration.GetValue<string>("Conductor:WorkerDomain")
                 )
+                .SetHealthCheckService<ConductorSharpFileHealthService>()
                 .AddPipelines(pipelines =>
                 {
                     pipelines.AddContextLogging();
diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
index b6e3a19e..6fec8141 100644
--- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
@@ -41,7 +41,8 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in
 
             _builder.RegisterType<ConductorSharpExecutionContext>().InstancePerLifetimeScope();
 
-            _builder.RegisterType<ConductorSharpHealthService>().AsImplementedInterfaces();
+            _builder.RegisterType<InMemoryHealthService>().As<IConductorSharpHealthService>();
+
             _builder.RegisterType<InverseExponentialBackoff>().As<IPollTimingStrategy>();
 
             _builder.RegisterType<RandomOrdering>().As<IPollOrderStrategy>();
@@ -61,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>();
+            return this;
+        }
     }
 }
diff --git a/src/ConductorSharp.Engine/Extensions/IExecutionManagerBuilder.cs b/src/ConductorSharp.Engine/Extensions/IExecutionManagerBuilder.cs
index 0ce51831..f758aff4 100644
--- a/src/ConductorSharp.Engine/Extensions/IExecutionManagerBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/IExecutionManagerBuilder.cs
@@ -1,4 +1,5 @@
-﻿using System;
+﻿using ConductorSharp.Engine.Health;
+using System;
 using System.Collections.Generic;
 using System.Text;
 
@@ -7,5 +8,6 @@ namespace ConductorSharp.Engine.Extensions
     public interface IExecutionManagerBuilder
     {
         IExecutionManagerBuilder AddPipelines(Action<IPipelineBuilder> pipelines);
+        IExecutionManagerBuilder SetHealthCheckService<T>() where T : IConductorSharpHealthService;
     }
 }
diff --git a/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs b/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
index 739ac486..82b6dd16 100644
--- a/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/WorkflowEngineBuilder.cs
@@ -46,7 +46,6 @@ public IWorkflowEngineExecutionManager AddExecutionManager(
 
             _builder.RegisterGeneric(typeof(ValidationBehavior<,>)).As(typeof(IPipelineBehavior<,>));
 
-            _builder.RegisterType<ConductorSharpHealthService>().AsImplementedInterfaces();
             _builder.RegisterType<InverseExponentialBackoff>().As<IPollTimingStrategy>();
 
             _builder.RegisterType<RandomOrdering>().As<IPollOrderStrategy>();
diff --git a/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs
similarity index 96%
rename from src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
rename to src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs
index 20a7fcd5..eb4195e4 100644
--- a/src/ConductorSharp.Engine/Health/ConductorSharpHealthService.cs
+++ b/src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs
@@ -13,7 +13,7 @@ public class HealthData
         public bool IsExecutionManagerRunning { get; set; }
     }
 
-    public class ConductorSharpHealthService : IConductorSharpHealthService, IConductorSharpHealthUpdater
+    public class ConductorSharpFileHealthService : IConductorSharpHealthService
     {
         private static readonly SemaphoreSlim _semaphore = new(1);
 
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
index 6a4ec694..bfe22d5e 100644
--- a/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
+++ b/src/ConductorSharp.Engine/Health/IConductorSharpHealthService.cs
@@ -9,5 +9,9 @@ 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);
     }
 }
diff --git a/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs b/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
deleted file mode 100644
index ee1078ca..00000000
--- a/src/ConductorSharp.Engine/Health/IConductorSharpHealthUpdater.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace ConductorSharp.Engine.Health
-{
-    internal interface IConductorSharpHealthUpdater
-    {
-        Task ResetHealthData(CancellationToken cancellationToken = default);
-        void RemoveHealthData();
-        Task SetExecutionManagerRunning(CancellationToken cancellationToken = default);
-        Task UnsetExecutionManagerRunning(CancellationToken cancellationToken = default);
-    }
-}
diff --git a/src/ConductorSharp.Engine/Health/InMemoryHealthService.cs b/src/ConductorSharp.Engine/Health/InMemoryHealthService.cs
new file mode 100644
index 00000000..fd485d36
--- /dev/null
+++ b/src/ConductorSharp.Engine/Health/InMemoryHealthService.cs
@@ -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;
+        }
+    }
+}
diff --git a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
index a998f4f6..a5d2c30b 100644
--- a/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
+++ b/src/ConductorSharp.Engine/Service/WorkflowEngineBackgroundService.cs
@@ -15,12 +15,12 @@ internal class WorkflowEngineBackgroundService : IHostedService, IDisposable
         private readonly IDeploymentService _deploymentService;
         private readonly ExecutionManager _executionManager;
         private readonly ModuleDeployment _deployment;
-        private readonly IConductorSharpHealthUpdater _healthUpdater;
+        private readonly IConductorSharpHealthService _healthService;
         private Task _executingTask;
         private readonly CancellationTokenSource _stoppingCts = new();
 
         public WorkflowEngineBackgroundService(
-            IConductorSharpHealthUpdater healthUpdater,
+            IConductorSharpHealthService healthService,
             ILogger<WorkflowEngineBackgroundService> logger,
             IHostApplicationLifetime hostApplicationLifetime,
             IDeploymentService deploymentService,
@@ -33,7 +33,7 @@ ModuleDeployment deployment
             _deploymentService = deploymentService;
             _executionManager = executionManager;
             _deployment = deployment;
-            _healthUpdater = healthUpdater;
+            _healthService = healthService;
         }
 
         public Task StartAsync(CancellationToken cancellationToken)
@@ -52,14 +52,14 @@ private async Task RunAsync(CancellationToken cancellationToken)
         {
             try
             {
-                await _healthUpdater.ResetHealthData(cancellationToken);
+                _healthService.RemoveHealthData();
                 await _deploymentService.Deploy(_deployment);
-                await _healthUpdater.SetExecutionManagerRunning(cancellationToken);
+                await _healthService.SetExecutionManagerRunning(cancellationToken);
                 await _executionManager.StartAsync(cancellationToken);
             }
             catch (Exception exception)
             {
-                await _healthUpdater.UnsetExecutionManagerRunning();
+                await _healthService.UnsetExecutionManagerRunning();
                 _logger.LogCritical(exception, "Workflow Engine Background Service encountered an error");
                 throw;
             }
@@ -71,7 +71,7 @@ private async Task RunAsync(CancellationToken cancellationToken)
 
         public async Task StopAsync(CancellationToken cancellationToken)
         {
-            _healthUpdater.RemoveHealthData();
+            _healthService.RemoveHealthData();
             if (_executingTask == null)
             {
                 return;

From 46e17ef2cafa1b7cf90e19b821fba564d6db803e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ognjen=20Kati=C4=87?=
 <44910579+ognjenkatic@users.noreply.github.com>
Date: Fri, 7 Oct 2022 21:19:27 +0200
Subject: [PATCH 7/7] make healthcheck services singleton

---
 docker-compose.override.yml                   | 23 +++++++++++++++++++
 .../Extensions/HostConfiguration.cs           |  2 ++
 .../ConductorSharp.Definitions/Program.cs     |  2 +-
 examples/ConductorSharp.NoApi/Program.cs      |  2 +-
 .../Extensions/ConductorSharpBuilder.cs       |  4 ++--
 ...eHealthService.cs => FileHealthService.cs} |  4 ++--
 6 files changed, 31 insertions(+), 6 deletions(-)
 rename src/ConductorSharp.Engine/Health/{ConductorSharpFileHealthService.cs => FileHealthService.cs} (94%)

diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index 17cc4b44..f505adaa 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -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:
diff --git a/examples/ConductorSharp.ApiEnabled/Extensions/HostConfiguration.cs b/examples/ConductorSharp.ApiEnabled/Extensions/HostConfiguration.cs
index 5ea3188d..d31a44bf 100644
--- a/examples/ConductorSharp.ApiEnabled/Extensions/HostConfiguration.cs
+++ b/examples/ConductorSharp.ApiEnabled/Extensions/HostConfiguration.cs
@@ -1,5 +1,6 @@
 ﻿using Autofac;
 using ConductorSharp.Engine.Extensions;
+using ConductorSharp.Engine.Health;
 using MediatR.Extensions.Autofac.DependencyInjection;
 
 namespace ConductorSharp.ApiEnabled.Extensions;
@@ -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();
diff --git a/examples/ConductorSharp.Definitions/Program.cs b/examples/ConductorSharp.Definitions/Program.cs
index 46959966..02c88e92 100644
--- a/examples/ConductorSharp.Definitions/Program.cs
+++ b/examples/ConductorSharp.Definitions/Program.cs
@@ -40,7 +40,7 @@
                     longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
                     domain: configuration.GetValue<string>("Conductor:WorkerDomain")
                 )
-                .SetHealthCheckService<ConductorSharpFileHealthService>()
+                .SetHealthCheckService<FileHealthService>()
                 .AddPipelines(pipelines =>
                 {
                     pipelines.AddRequestResponseLogging();
diff --git a/examples/ConductorSharp.NoApi/Program.cs b/examples/ConductorSharp.NoApi/Program.cs
index 3072a646..07209c68 100644
--- a/examples/ConductorSharp.NoApi/Program.cs
+++ b/examples/ConductorSharp.NoApi/Program.cs
@@ -40,7 +40,7 @@
                     longPollInterval: configuration.GetValue<int>("Conductor:LongPollInterval"),
                     domain: configuration.GetValue<string>("Conductor:WorkerDomain")
                 )
-                .SetHealthCheckService<ConductorSharpFileHealthService>()
+                .SetHealthCheckService<FileHealthService>()
                 .AddPipelines(pipelines =>
                 {
                     pipelines.AddContextLogging();
diff --git a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
index 6fec8141..2bca4b78 100644
--- a/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
+++ b/src/ConductorSharp.Engine/Extensions/ConductorSharpBuilder.cs
@@ -41,7 +41,7 @@ public IExecutionManagerBuilder AddExecutionManager(int maxConcurrentWorkers, in
 
             _builder.RegisterType<ConductorSharpExecutionContext>().InstancePerLifetimeScope();
 
-            _builder.RegisterType<InMemoryHealthService>().As<IConductorSharpHealthService>();
+            _builder.RegisterType<InMemoryHealthService>().As<IConductorSharpHealthService>().SingleInstance();
 
             _builder.RegisterType<InverseExponentialBackoff>().As<IPollTimingStrategy>();
 
@@ -65,7 +65,7 @@ public void AddRequestResponseLogging() =>
 
         public IExecutionManagerBuilder SetHealthCheckService<T>() where T : IConductorSharpHealthService
         {
-            _builder.RegisterType<T>().As<IConductorSharpHealthService>();
+            _builder.RegisterType<T>().As<IConductorSharpHealthService>().SingleInstance();
             return this;
         }
     }
diff --git a/src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs b/src/ConductorSharp.Engine/Health/FileHealthService.cs
similarity index 94%
rename from src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs
rename to src/ConductorSharp.Engine/Health/FileHealthService.cs
index eb4195e4..02e6962c 100644
--- a/src/ConductorSharp.Engine/Health/ConductorSharpFileHealthService.cs
+++ b/src/ConductorSharp.Engine/Health/FileHealthService.cs
@@ -13,9 +13,9 @@ public class HealthData
         public bool IsExecutionManagerRunning { get; set; }
     }
 
-    public class ConductorSharpFileHealthService : IConductorSharpHealthService
+    public class FileHealthService : IConductorSharpHealthService
     {
-        private static readonly SemaphoreSlim _semaphore = new(1);
+        private readonly SemaphoreSlim _semaphore = new(1);
 
         private const string HealthFileName = "CONDUCTORSHARP_HEALTH.json";
 
