diff --git a/README.md b/README.md index 9a9a7ce..8761501 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# Task Control Tower +# Task Turnstile A thread-safe named task lifecycle manager for .NET. Prevents duplicate background job execution across threads and — optionally — across multiple application instances via a distributed backing store. -> **Think of it like an air traffic control tower.** Every job that wants to run must request clearance first. The tower knows exactly what's in the air — only one flight can hold a given slot at a time, others are told to wait or come back later. When a flight lands, the slot is released and the next one can take off. +> **Think of it like a turnstile.** Every job that wants to run must push through first. Only one can hold the bar at a time — others wait their turn or are sent away. When the job is done, the bar rotates and the next one can step through. ## Why? -Scheduled jobs (Coravel, Hangfire, Quartz) fire on a timer. If the previous run hasn't finished, you don't want a second one to start. `TaskControlTower` gives you a named gate: +Scheduled jobs (Coravel, Hangfire, Quartz) fire on a timer. If the previous run hasn't finished, you don't want a second one to start. `TaskTurnstile` gives you a named gate: ```csharp if (!await _concurrencyManager.CanStartAsync("import-job")) @@ -22,7 +22,7 @@ Unlike a simple lock, the state can survive app restarts (via Redis or SQL Serve ### In-memory (single instance, no persistence) ```csharp -builder.Services.AddTaskControlTower(); +builder.Services.AddTaskTurnstile(); ``` The default store is a private in-memory cache — isolated from your app's own `IMemoryCache` and requiring zero configuration. @@ -30,18 +30,18 @@ The default store is a private in-memory cache — isolated from your app's own ### Redis ```csharp -builder.Services.AddTaskControlTower() +builder.Services.AddTaskTurnstile() .AddRedisStore(o => o.Configuration = "localhost:6379"); ``` -This creates a **dedicated** Redis connection for `TaskControlTower`, independent of any other Redis cache your app may be using. Configure it with any connection string — it can point at the same Redis instance as your app or a completely separate one. +This creates a **dedicated** Redis connection for `TaskTurnstile`, independent of any other Redis cache your app may be using. Configure it with any connection string — it can point at the same Redis instance as your app or a completely separate one. -If you'd prefer `TaskControlTower` to share your app's **existing** `IDistributedCache` instead, use `AddDistributedStore()` (see below). +If you'd prefer `TaskTurnstile` to share your app's **existing** `IDistributedCache` instead, use `AddDistributedStore()` (see below). ### SQL Server ```csharp -builder.Services.AddTaskControlTower() +builder.Services.AddTaskTurnstile() .AddSqlServerStore(o => { o.ConnectionString = "Server=.;Database=MyApp;..."; @@ -57,10 +57,10 @@ builder.Services.AddTaskControlTower() ### Use the app's existing `IDistributedCache` -If you've already registered a distributed cache (e.g. `AddStackExchangeRedisCache`) and want `TaskControlTower` to share it: +If you've already registered a distributed cache (e.g. `AddStackExchangeRedisCache`) and want `TaskTurnstile` to share it: ```csharp -builder.Services.AddTaskControlTower() +builder.Services.AddTaskTurnstile() .AddDistributedStore(); ``` @@ -71,7 +71,7 @@ Task keys are prefixed with `KeyPrefix` (default `"cm:"`) to avoid collisions wi ## Options ```csharp -builder.Services.AddTaskControlTower(o => +builder.Services.AddTaskTurnstile(o => { // Maximum time a task can run before it's considered stale. // Prevents tasks from being stuck forever if TryStopAsync is never called (e.g. app crash). @@ -217,11 +217,11 @@ Register it: ```csharp // Let DI create it: -builder.Services.AddTaskControlTower() +builder.Services.AddTaskTurnstile() .UseTaskStateStore(); // Or use a factory: -builder.Services.AddTaskControlTower() +builder.Services.AddTaskTurnstile() .UseTaskStateStore(sp => new MyCustomStore("/var/run/locks")); ``` diff --git a/TaskControlTower.slnx b/TaskControlTower.slnx deleted file mode 100644 index c9d22cd..0000000 --- a/TaskControlTower.slnx +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/TaskControlTower.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs b/TaskTurnstile.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs similarity index 66% rename from TaskControlTower.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs rename to TaskTurnstile.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs index 4535e99..9911706 100644 --- a/TaskControlTower.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs +++ b/TaskTurnstile.Redis/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs @@ -1,20 +1,20 @@ -using TaskControlTower.DependencyInjection; +using TaskTurnstile.DependencyInjection; using Microsoft.Extensions.Caching.StackExchangeRedis; -namespace TaskControlTower.Redis.DependencyInjection; +namespace TaskTurnstile.Redis.DependencyInjection; -public static class TaskControlTowerBuilderExtensions +public static class TaskTurnstileBuilderExtensions { /// /// Uses a dedicated Redis cache as the backing store, isolated from any other Redis cache /// the app may have registered. /// /// - /// services.AddTaskControlTower() + /// services.AddTaskTurnstile() /// .AddRedisStore(o => o.Configuration = "localhost:6379"); /// - public static TaskControlTowerBuilder AddRedisStore( - this TaskControlTowerBuilder builder, + public static TaskTurnstileBuilder AddRedisStore( + this TaskTurnstileBuilder builder, Action configure) { return builder.AddDistributedStore(_ => diff --git a/TaskControlTower.Redis/TaskControlTower.Redis.csproj b/TaskTurnstile.Redis/TaskTurnstile.Redis.csproj similarity index 78% rename from TaskControlTower.Redis/TaskControlTower.Redis.csproj rename to TaskTurnstile.Redis/TaskTurnstile.Redis.csproj index 1dae971..1b5d966 100644 --- a/TaskControlTower.Redis/TaskControlTower.Redis.csproj +++ b/TaskTurnstile.Redis/TaskTurnstile.Redis.csproj @@ -4,11 +4,11 @@ net10.0 enable enable - TaskControlTower.Redis + TaskTurnstile.Redis Chris Hunt TappetyClick - Redis backing store for TaskControlTower via StackExchange.Redis and IDistributedCache. + Redis backing store for TaskTurnstile via StackExchange.Redis and IDistributedCache. Supports dedicated Redis instances independent of the app's own cache. Concurrency, Background Tasks, Named Lock, Redis, Distributed Cache @@ -20,7 +20,7 @@ - + diff --git a/TaskControlTower.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs b/TaskTurnstile.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs similarity index 69% rename from TaskControlTower.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs rename to TaskTurnstile.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs index a20779a..e4b2b97 100644 --- a/TaskControlTower.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs +++ b/TaskTurnstile.SqlServer/DependencyInjection/ConcurrencyManagerBuilderExtensions.cs @@ -1,9 +1,9 @@ -using TaskControlTower.DependencyInjection; +using TaskTurnstile.DependencyInjection; using Microsoft.Extensions.Caching.SqlServer; -namespace TaskControlTower.SqlServer.DependencyInjection; +namespace TaskTurnstile.SqlServer.DependencyInjection; -public static class TaskControlTowerBuilderExtensions +public static class TaskTurnstileBuilderExtensions { /// /// Uses a dedicated SQL Server distributed cache as the backing store, isolated from any @@ -11,16 +11,16 @@ public static class TaskControlTowerBuilderExtensions /// The cache table must exist — create it with: dotnet sql-cache create "connection" schema table /// /// - /// services.AddTaskControlTower() + /// services.AddTaskTurnstile() /// .AddSqlServerStore(o => /// { /// o.ConnectionString = "Server=..."; /// o.SchemaName = "dbo"; - /// o.TableName = "TaskControlTowerCache"; + /// o.TableName = "TaskTurnstileCache"; /// }); /// - public static TaskControlTowerBuilder AddSqlServerStore( - this TaskControlTowerBuilder builder, + public static TaskTurnstileBuilder AddSqlServerStore( + this TaskTurnstileBuilder builder, Action configure) { return builder.AddDistributedStore(_ => diff --git a/TaskControlTower.SqlServer/TaskControlTower.SqlServer.csproj b/TaskTurnstile.SqlServer/TaskTurnstile.SqlServer.csproj similarity index 81% rename from TaskControlTower.SqlServer/TaskControlTower.SqlServer.csproj rename to TaskTurnstile.SqlServer/TaskTurnstile.SqlServer.csproj index 8f3541c..5f4335d 100644 --- a/TaskControlTower.SqlServer/TaskControlTower.SqlServer.csproj +++ b/TaskTurnstile.SqlServer/TaskTurnstile.SqlServer.csproj @@ -4,11 +4,11 @@ net10.0 enable enable - TaskControlTower.SqlServer + TaskTurnstile.SqlServer Chris Hunt TappetyClick - SQL Server backing store for TaskControlTower via IDistributedCache. + SQL Server backing store for TaskTurnstile via IDistributedCache. Supports dedicated SQL Server instances independent of the app's own cache. Requires the cache table to be pre-created with the dotnet sql-cache CLI tool. @@ -21,7 +21,7 @@ - + diff --git a/TaskControlTower.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs b/TaskTurnstile.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs similarity index 78% rename from TaskControlTower.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs rename to TaskTurnstile.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs index 6613c0b..295855b 100644 --- a/TaskControlTower.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs +++ b/TaskTurnstile.Tests/DependencyInjection/ServiceCollectionExtensionsTests.cs @@ -1,46 +1,46 @@ -using TaskControlTower.DependencyInjection; +using TaskTurnstile.DependencyInjection; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NSubstitute; -namespace TaskControlTower.Tests.DependencyInjection; +namespace TaskTurnstile.Tests.DependencyInjection; public class ServiceCollectionExtensionsTests { // ── Registration ────────────────────────────────────────────────────────── [Fact] - public void AddTaskControlTower_RegistersITaskStateManager() + public void AddTaskTurnstile_RegistersITaskStateManager() { - var sp = new ServiceCollection().AddTaskControlTower().Services.BuildServiceProvider(); + var sp = new ServiceCollection().AddTaskTurnstile().Services.BuildServiceProvider(); Assert.NotNull(sp.GetService()); } [Fact] - public void AddTaskControlTower_RegistersITaskStateStore() + public void AddTaskTurnstile_RegistersITaskStateStore() { - var sp = new ServiceCollection().AddTaskControlTower().Services.BuildServiceProvider(); + var sp = new ServiceCollection().AddTaskTurnstile().Services.BuildServiceProvider(); Assert.NotNull(sp.GetService()); } // ── CleanupOnStartup ────────────────────────────────────────────────────── [Fact] - public void AddTaskControlTower_CleanupOnStartup_True_RegistersHostedService() + public void AddTaskTurnstile_CleanupOnStartup_True_RegistersHostedService() { var sp = new ServiceCollection() - .AddTaskControlTower(o => o.CleanupOnStartup = true) + .AddTaskTurnstile(o => o.CleanupOnStartup = true) .Services.BuildServiceProvider(); Assert.Contains(sp.GetServices(), s => s is CleanupOnStartupHostedService); } [Fact] - public void AddTaskControlTower_CleanupOnStartup_False_DoesNotRegisterHostedService() + public void AddTaskTurnstile_CleanupOnStartup_False_DoesNotRegisterHostedService() { var sp = new ServiceCollection() - .AddTaskControlTower(o => o.CleanupOnStartup = false) + .AddTaskTurnstile(o => o.CleanupOnStartup = false) .Services.BuildServiceProvider(); Assert.DoesNotContain(sp.GetServices(), s => s is CleanupOnStartupHostedService); @@ -68,7 +68,7 @@ public async Task AddDistributedStore_UsesRegisteredDistributedCache() var sp = new ServiceCollection() .AddSingleton(appCache) - .AddTaskControlTower().AddDistributedStore() + .AddTaskTurnstile().AddDistributedStore() .Services.BuildServiceProvider(); var store = sp.GetRequiredService(); @@ -85,7 +85,7 @@ public void UseTaskStateStore_ReplacesDefaultStore() var customStore = Substitute.For(); var sp = new ServiceCollection() - .AddTaskControlTower().UseTaskStateStore(_ => customStore) + .AddTaskTurnstile().UseTaskStateStore(_ => customStore) .Services.BuildServiceProvider(); Assert.Same(customStore, sp.GetRequiredService()); @@ -98,7 +98,7 @@ public void UseTaskStateStore_CalledTwice_LastRegistrationWins() var second = Substitute.For(); var sp = new ServiceCollection() - .AddTaskControlTower() + .AddTaskTurnstile() .UseTaskStateStore(_ => first) .UseTaskStateStore(_ => second) .Services.BuildServiceProvider(); diff --git a/TaskControlTower.Tests/Manager/TaskStateManagerTests.cs b/TaskTurnstile.Tests/Manager/TaskStateManagerTests.cs similarity index 96% rename from TaskControlTower.Tests/Manager/TaskStateManagerTests.cs rename to TaskTurnstile.Tests/Manager/TaskStateManagerTests.cs index 60cda56..0caafd9 100644 --- a/TaskControlTower.Tests/Manager/TaskStateManagerTests.cs +++ b/TaskTurnstile.Tests/Manager/TaskStateManagerTests.cs @@ -1,5 +1,5 @@ -using TaskControlTower.DependencyInjection; -using TaskControlTower.Stores; +using TaskTurnstile.DependencyInjection; +using TaskTurnstile.Stores; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -7,16 +7,16 @@ using NSubstitute; using NSubstitute.ExceptionExtensions; -namespace TaskControlTower.Tests.Manager; +namespace TaskTurnstile.Tests.Manager; /// Unit tests for TaskStateManager using a mock ITaskStateStore. public class TaskStateManagerTests { private static (TaskStateManager manager, ITaskStateStore store) BuildWithMockStore( - TaskControlTowerOptions? options = null) + TaskTurnstileOptions? options = null) { var store = Substitute.For(); - var manager = new TaskStateManager(store, options ?? new TaskControlTowerOptions()); + var manager = new TaskStateManager(store, options ?? new TaskTurnstileOptions()); return (manager, store); } @@ -24,7 +24,7 @@ private static TaskStateManager BuildWithRealStore() { var cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions())); var store = new DistributedCacheTaskStateStore(cache); - return new TaskStateManager(store, new TaskControlTowerOptions()); + return new TaskStateManager(store, new TaskTurnstileOptions()); } // ── CanStartAsync ───────────────────────────────────────────────────────── @@ -101,7 +101,7 @@ public async Task StartAsync_UsesDefaultMaxRuntime_WhenNotProvided() var cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions())); var manager = new TaskStateManager( new DistributedCacheTaskStateStore(cache), - new TaskControlTowerOptions { DefaultMaxRuntime = TimeSpan.FromMilliseconds(50) }); + new TaskTurnstileOptions { DefaultMaxRuntime = TimeSpan.FromMilliseconds(50) }); await manager.StartAsync("job"); Assert.True(await manager.IsRunningAsync("job")); @@ -400,8 +400,8 @@ private static (TaskStateManager managerA, TaskStateManager managerB) BuildTwoMa var cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions())); var store = new DistributedCacheTaskStateStore(cache); return ( - new TaskStateManager(store, new TaskControlTowerOptions()), - new TaskStateManager(store, new TaskControlTowerOptions()) + new TaskStateManager(store, new TaskTurnstileOptions()), + new TaskStateManager(store, new TaskTurnstileOptions()) ); } diff --git a/TaskControlTower.Tests/Stores/DistributedCacheTaskStateStoreTests.cs b/TaskTurnstile.Tests/Stores/DistributedCacheTaskStateStoreTests.cs similarity index 98% rename from TaskControlTower.Tests/Stores/DistributedCacheTaskStateStoreTests.cs rename to TaskTurnstile.Tests/Stores/DistributedCacheTaskStateStoreTests.cs index ba59d6b..a60eb94 100644 --- a/TaskControlTower.Tests/Stores/DistributedCacheTaskStateStoreTests.cs +++ b/TaskTurnstile.Tests/Stores/DistributedCacheTaskStateStoreTests.cs @@ -1,9 +1,9 @@ -using TaskControlTower.Stores; +using TaskTurnstile.Stores; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; -namespace TaskControlTower.Tests.Stores; +namespace TaskTurnstile.Tests.Stores; public class DistributedCacheTaskStateStoreTests { diff --git a/TaskControlTower.Tests/TaskControlTower.Tests.csproj b/TaskTurnstile.Tests/TaskTurnstile.Tests.csproj similarity index 92% rename from TaskControlTower.Tests/TaskControlTower.Tests.csproj rename to TaskTurnstile.Tests/TaskTurnstile.Tests.csproj index 13e405d..c820fde 100644 --- a/TaskControlTower.Tests/TaskControlTower.Tests.csproj +++ b/TaskTurnstile.Tests/TaskTurnstile.Tests.csproj @@ -23,7 +23,7 @@ - + \ No newline at end of file diff --git a/TaskTurnstile.slnx b/TaskTurnstile.slnx new file mode 100644 index 0000000..edb5f82 --- /dev/null +++ b/TaskTurnstile.slnx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TaskControlTower/DependencyInjection/CleanupOnStartupHostedService.cs b/TaskTurnstile/DependencyInjection/CleanupOnStartupHostedService.cs similarity index 87% rename from TaskControlTower/DependencyInjection/CleanupOnStartupHostedService.cs rename to TaskTurnstile/DependencyInjection/CleanupOnStartupHostedService.cs index af145e0..82cff84 100644 --- a/TaskControlTower/DependencyInjection/CleanupOnStartupHostedService.cs +++ b/TaskTurnstile/DependencyInjection/CleanupOnStartupHostedService.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Hosting; -namespace TaskControlTower.DependencyInjection; +namespace TaskTurnstile.DependencyInjection; internal sealed class CleanupOnStartupHostedService(ITaskStateStore store) : IHostedService { diff --git a/TaskControlTower/DependencyInjection/ServiceCollectionExtensions.cs b/TaskTurnstile/DependencyInjection/ServiceCollectionExtensions.cs similarity index 78% rename from TaskControlTower/DependencyInjection/ServiceCollectionExtensions.cs rename to TaskTurnstile/DependencyInjection/ServiceCollectionExtensions.cs index c11d5a0..58d9b0b 100644 --- a/TaskControlTower/DependencyInjection/ServiceCollectionExtensions.cs +++ b/TaskTurnstile/DependencyInjection/ServiceCollectionExtensions.cs @@ -1,4 +1,4 @@ -using TaskControlTower.Stores; +using TaskTurnstile.Stores; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -6,15 +6,15 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; -namespace TaskControlTower.DependencyInjection; +namespace TaskTurnstile.DependencyInjection; public static class ServiceCollectionExtensions { - public static TaskControlTowerBuilder AddTaskControlTower( + public static TaskTurnstileBuilder AddTaskTurnstile( this IServiceCollection services, - Action? configure = null) + Action? configure = null) { - var options = new TaskControlTowerOptions(); + var options = new TaskTurnstileOptions(); configure?.Invoke(options); services.AddSingleton(options); @@ -31,6 +31,6 @@ public static TaskControlTowerBuilder AddTaskControlTower( if (options.CleanupOnStartup) services.AddSingleton(); - return new TaskControlTowerBuilder(services); + return new TaskTurnstileBuilder(services); } } diff --git a/TaskControlTower/DependencyInjection/TaskControlTowerBuilder.cs b/TaskTurnstile/DependencyInjection/TaskControlTowerBuilder.cs similarity index 68% rename from TaskControlTower/DependencyInjection/TaskControlTowerBuilder.cs rename to TaskTurnstile/DependencyInjection/TaskControlTowerBuilder.cs index a958021..7b21c90 100644 --- a/TaskControlTower/DependencyInjection/TaskControlTowerBuilder.cs +++ b/TaskTurnstile/DependencyInjection/TaskControlTowerBuilder.cs @@ -1,24 +1,24 @@ -using TaskControlTower.Stores; +using TaskTurnstile.Stores; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -namespace TaskControlTower.DependencyInjection; +namespace TaskTurnstile.DependencyInjection; -public sealed class TaskControlTowerBuilder(IServiceCollection services) +public sealed class TaskTurnstileBuilder(IServiceCollection services) { public IServiceCollection Services { get; } = services; /// /// Uses the app's registered as the backing store. /// The app must register a distributed cache (e.g. AddStackExchangeRedisCache) before building the container. - /// Task keys are prefixed with (default "cm:") to avoid collisions. + /// Task keys are prefixed with (default "cm:") to avoid collisions. /// - public TaskControlTowerBuilder AddDistributedStore() + public TaskTurnstileBuilder AddDistributedStore() { ReplaceStore(services => services.AddSingleton(sp => { - var opts = sp.GetRequiredService(); + var opts = sp.GetRequiredService(); return new DistributedCacheTaskStateStore( sp.GetRequiredService(), opts.KeyPrefix); @@ -29,27 +29,27 @@ public TaskControlTowerBuilder AddDistributedStore() /// /// Uses a dedicated instance created by the provided factory, /// completely isolated from the app's own cache. - /// Task keys are prefixed with (default "cm:"). + /// Task keys are prefixed with (default "cm:"). /// - public TaskControlTowerBuilder AddDistributedStore(Func cacheFactory) + public TaskTurnstileBuilder AddDistributedStore(Func cacheFactory) { ReplaceStore(services => services.AddSingleton(sp => { - var opts = sp.GetRequiredService(); + var opts = sp.GetRequiredService(); return new DistributedCacheTaskStateStore(cacheFactory(sp), opts.KeyPrefix); })); return this; } /// Replaces the backing store with a custom implementation. - public TaskControlTowerBuilder UseTaskStateStore() where T : class, ITaskStateStore + public TaskTurnstileBuilder UseTaskStateStore() where T : class, ITaskStateStore { ReplaceStore(services => services.AddSingleton()); return this; } /// Replaces the backing store with a custom instance created by the provided factory. - public TaskControlTowerBuilder UseTaskStateStore(Func factory) + public TaskTurnstileBuilder UseTaskStateStore(Func factory) { ReplaceStore(services => services.AddSingleton(factory)); return this; diff --git a/TaskControlTower/ITaskStateManager.cs b/TaskTurnstile/ITaskStateManager.cs similarity index 98% rename from TaskControlTower/ITaskStateManager.cs rename to TaskTurnstile/ITaskStateManager.cs index ef87d66..48019cf 100644 --- a/TaskControlTower/ITaskStateManager.cs +++ b/TaskTurnstile/ITaskStateManager.cs @@ -1,4 +1,4 @@ -namespace TaskControlTower; +namespace TaskTurnstile; public interface ITaskStateManager { diff --git a/TaskControlTower/ITaskStateStore.cs b/TaskTurnstile/ITaskStateStore.cs similarity index 94% rename from TaskControlTower/ITaskStateStore.cs rename to TaskTurnstile/ITaskStateStore.cs index 578df3f..238b379 100644 --- a/TaskControlTower/ITaskStateStore.cs +++ b/TaskTurnstile/ITaskStateStore.cs @@ -1,4 +1,4 @@ -namespace TaskControlTower; +namespace TaskTurnstile; public interface ITaskStateStore { diff --git a/TaskControlTower/Stores/DistributedCacheTaskStateStore.cs b/TaskTurnstile/Stores/DistributedCacheTaskStateStore.cs similarity index 97% rename from TaskControlTower/Stores/DistributedCacheTaskStateStore.cs rename to TaskTurnstile/Stores/DistributedCacheTaskStateStore.cs index b6e74c8..aa78f6d 100644 --- a/TaskControlTower/Stores/DistributedCacheTaskStateStore.cs +++ b/TaskTurnstile/Stores/DistributedCacheTaskStateStore.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Caching.Distributed; -namespace TaskControlTower.Stores; +namespace TaskTurnstile.Stores; internal sealed class DistributedCacheTaskStateStore(IDistributedCache cache, string keyPrefix = "cm:") : ITaskStateStore { diff --git a/TaskControlTower/TaskControlTowerOptions.cs b/TaskTurnstile/TaskControlTowerOptions.cs similarity index 90% rename from TaskControlTower/TaskControlTowerOptions.cs rename to TaskTurnstile/TaskControlTowerOptions.cs index a1b95d1..93998bd 100644 --- a/TaskControlTower/TaskControlTowerOptions.cs +++ b/TaskTurnstile/TaskControlTowerOptions.cs @@ -1,6 +1,6 @@ -namespace TaskControlTower; +namespace TaskTurnstile; -public sealed class TaskControlTowerOptions +public sealed class TaskTurnstileOptions { /// Default MaxRuntime applied when StartAsync is called without an explicit maxRuntime. Null means no expiry. public TimeSpan? DefaultMaxRuntime { get; set; } diff --git a/TaskControlTower/TaskStateManager.cs b/TaskTurnstile/TaskStateManager.cs similarity index 98% rename from TaskControlTower/TaskStateManager.cs rename to TaskTurnstile/TaskStateManager.cs index d8c3ec5..ba119fe 100644 --- a/TaskControlTower/TaskStateManager.cs +++ b/TaskTurnstile/TaskStateManager.cs @@ -3,9 +3,9 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; -namespace TaskControlTower; +namespace TaskTurnstile; -internal sealed class TaskStateManager(ITaskStateStore store, TaskControlTowerOptions options) : ITaskStateManager +internal sealed class TaskStateManager(ITaskStateStore store, TaskTurnstileOptions options) : ITaskStateManager { private readonly AsyncKeyedLocker _locker = new(); private readonly IMemoryCache _localCache = new MemoryCache(Options.Create(new MemoryCacheOptions())); diff --git a/TaskControlTower/TaskControlTower.csproj b/TaskTurnstile/TaskTurnstile.csproj similarity index 92% rename from TaskControlTower/TaskControlTower.csproj rename to TaskTurnstile/TaskTurnstile.csproj index 1ccef04..b3fbea6 100644 --- a/TaskControlTower/TaskControlTower.csproj +++ b/TaskTurnstile/TaskTurnstile.csproj @@ -4,7 +4,7 @@ net10.0 enable enable - TaskControlTower + TaskTurnstile Chris Hunt TappetyClick @@ -25,7 +25,7 @@ - + diff --git a/TaskControlTower/TryRunResult.cs b/TaskTurnstile/TryRunResult.cs similarity index 87% rename from TaskControlTower/TryRunResult.cs rename to TaskTurnstile/TryRunResult.cs index cb2a55e..c3acacf 100644 --- a/TaskControlTower/TryRunResult.cs +++ b/TaskTurnstile/TryRunResult.cs @@ -1,4 +1,4 @@ -namespace TaskControlTower; +namespace TaskTurnstile; public record TryRunResult(bool Started, T? Value) { diff --git a/TaskControlTower/obj/ConcurrencyManager.csproj.nuget.g.props b/TaskTurnstile/obj/ConcurrencyManager.csproj.nuget.g.props similarity index 100% rename from TaskControlTower/obj/ConcurrencyManager.csproj.nuget.g.props rename to TaskTurnstile/obj/ConcurrencyManager.csproj.nuget.g.props diff --git a/samples/FileStore/FileStore.csproj b/samples/FileStore/FileStore.csproj index 738e569..d88f411 100644 --- a/samples/FileStore/FileStore.csproj +++ b/samples/FileStore/FileStore.csproj @@ -10,7 +10,7 @@ - + diff --git a/samples/FileStore/FileTaskStateStore.cs b/samples/FileStore/FileTaskStateStore.cs index b858ea7..4160c2c 100644 --- a/samples/FileStore/FileTaskStateStore.cs +++ b/samples/FileStore/FileTaskStateStore.cs @@ -1,4 +1,4 @@ -using TaskControlTower; +using TaskTurnstile; using Microsoft.Extensions.DependencyInjection; // ────────────────────────────────────────────────────────────────────────────── @@ -18,7 +18,7 @@ public sealed class FileTaskStateStore(string directory) : ITaskStateStore { - public FileTaskStateStore() : this(Path.Combine(Path.GetTempPath(), "task-control-tower")) { } + public FileTaskStateStore() : this(Path.Combine(Path.GetTempPath(), "task-turnstile")) { } private string LockFile(string taskName) => Path.Combine(directory, $"{taskName}.lock"); @@ -86,10 +86,10 @@ public Task CleanupAsync(CancellationToken cancellationToken = default) // Registration — wire it up via UseTaskStateStore() // ────────────────────────────────────────────────────────────────────────────── -// services.AddTaskControlTower(o => o.CleanupOnStartup = true) +// services.AddTaskTurnstile(o => o.CleanupOnStartup = true) // .UseTaskStateStore(); // // Or with a factory if you need to pass the directory: // -// services.AddTaskControlTower(o => o.CleanupOnStartup = true) +// services.AddTaskTurnstile(o => o.CleanupOnStartup = true) // .UseTaskStateStore(sp => new FileTaskStateStore("/var/run/my-app/locks")); diff --git a/samples/FileStore/Program.cs b/samples/FileStore/Program.cs index 7bc254a..c746d07 100644 --- a/samples/FileStore/Program.cs +++ b/samples/FileStore/Program.cs @@ -1,16 +1,16 @@ using Microsoft.Extensions.DependencyInjection; -using TaskControlTower; -using TaskControlTower.DependencyInjection; +using TaskTurnstile; +using TaskTurnstile.DependencyInjection; Console.OutputEncoding = System.Text.Encoding.UTF8; -var lockDir = Path.Combine(Path.GetTempPath(), "task-control-tower-demo"); +var lockDir = Path.Combine(Path.GetTempPath(), "task-turnstile-demo"); const string TaskName = "nightly-report"; // ── Build the service provider ──────────────────────────────────────────────── var sp = new ServiceCollection() - .AddTaskControlTower() + .AddTaskTurnstile() .UseTaskStateStore(_ => new FileTaskStateStore(lockDir)) .Services .BuildServiceProvider(); @@ -20,7 +20,7 @@ // ── Header ──────────────────────────────────────────────────────────────────── -Section("TaskControlTower — Persistence Demo"); +Section("TaskTurnstile — Persistence Demo"); Info($"Lock directory : {lockDir}"); Info($"Task name : {TaskName}"); Console.WriteLine();