{"id":50748316,"url":"https://github.com/chunty/taskturnstile","last_synced_at":"2026-06-10T23:01:29.255Z","repository":{"id":355013221,"uuid":"1226069123","full_name":"chunty/TaskTurnstile","owner":"chunty","description":" A thread-safe named task lifecycle manager for .NET. Prevents duplicate background job execution across threads and  across multiple app instances via Redis or SQL Server.","archived":false,"fork":false,"pushed_at":"2026-05-14T10:51:38.000Z","size":79,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-14T12:38:57.157Z","etag":null,"topics":["background-jobs","background-tasks","concurrency","csharp","dotnet","nuget","task-locking","task-manager"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chunty.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T00:10:28.000Z","updated_at":"2026-05-14T10:51:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/chunty/TaskTurnstile","commit_stats":null,"previous_names":["chunty/taskcontroltower","chunty/taskturnstile"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/chunty/TaskTurnstile","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chunty%2FTaskTurnstile","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chunty%2FTaskTurnstile/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chunty%2FTaskTurnstile/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chunty%2FTaskTurnstile/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chunty","download_url":"https://codeload.github.com/chunty/TaskTurnstile/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chunty%2FTaskTurnstile/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34174148,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["background-jobs","background-tasks","concurrency","csharp","dotnet","nuget","task-locking","task-manager"],"created_at":"2026-06-10T23:01:24.091Z","updated_at":"2026-06-10T23:01:29.238Z","avatar_url":"https://github.com/chunty.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Task Turnstile\n[![NuGet](https://img.shields.io/nuget/v/TaskTurnstile.svg)](https://www.nuget.org/packages/TaskTurnstile)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/TaskTurnstile.svg)](https://www.nuget.org/packages/TaskTurnstile)\n[![CI](https://github.com/chunty/TaskTurnstile/actions/workflows/ci.yml/badge.svg)](https://github.com/chunty/TaskTurnstile/actions/workflows/ci.yml)\n[![Publish Wiki](https://github.com/chunty/TaskTurnstile/actions/workflows/publish-wiki.yml/badge.svg)](https://github.com/chunty/TaskTurnstile/actions/workflows/publish-wiki.yml)\n\nPrevents duplicate background job execution in .NET — within a single instance **and across multiple instances** via a distributed backing store. Perfect for scheduled jobs running on multiple pods, servers, or worker processes where only one should run at a time.\n\n\u003e **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.\n\n## Why?\n\nScheduled 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:\n\n```csharp\nif (!await manager.CanStartAsync(\"import-job\"))\n    return; // already running, skip this tick\n```\n\nUnlike a simple lock, the state can survive app restarts (via Redis or SQL Server) and be shared across multiple instances of your app.\n\n## Install\n\n```\ndotnet add package TaskTurnstile\n```\n\n## Quick start\n\n```csharp\nbuilder.Services.AddTaskTurnstile();\n```\n\n```csharp\nbool ran = await manager.TryRunAsync(\"import-job\", async ct =\u003e\n{\n    await DoImportAsync(ct);\n});\n```\n\nReturns `true` after the work completes, or `false` immediately if the task is already running.\n\n## Scale out across instances\n\nThe default store is in-memory — great for a single instance. Add a backing store to prevent duplicate runs across **multiple pods, servers, or worker processes**:\n\n**Redis**\n```csharp\nbuilder.Services.AddTaskTurnstile()\n                .AddRedisStore(o =\u003e o.Configuration = \"localhost:6379\");\n```\n\n**SQL Server**\n```csharp\nbuilder.Services.AddTaskTurnstile()\n                .AddSqlServerStore(o =\u003e o.ConnectionString = \"Server=.;Database=MyApp;...\");\n```\n\n**Shared `IDistributedCache`** (use your app's existing distributed cache)\n```csharp\nbuilder.Services.AddTaskTurnstile()\n                .AddDistributedStore();\n```\n\n\u003e All three options use an in-process memory short-circuit — the backing store is only hit when a task isn't already known to be running locally, keeping overhead minimal. See [Setup](https://github.com/chunty/TaskTurnstile/wiki/Setup) for full options.\n\n## Documentation\n\n| | |\n|---|---|\n| [Setup](https://github.com/chunty/TaskTurnstile/wiki/Setup) | In-memory, Redis, SQL Server, shared `IDistributedCache`, and all options |\n| [API Reference](https://github.com/chunty/TaskTurnstile/wiki/API-Reference) | Full `ITaskStateManager` method reference |\n| [Patterns](https://github.com/chunty/TaskTurnstile/wiki/Patterns) | Coravel, BackgroundService, manual start/stop, returning values |\n| [Testing](https://github.com/chunty/TaskTurnstile/wiki/Testing) | `FakeTaskStateManager` and manual Moq / NSubstitute setup |\n| [Custom Store](https://github.com/chunty/TaskTurnstile/wiki/Custom-Store) | Implement `ITaskStateStore` to use any backing store |\n\n## Packages\n\n| Package | NuGet | Purpose |\n|---|---|---|\n| `TaskTurnstile` | [![NuGet](https://img.shields.io/nuget/v/TaskTurnstile.svg)](https://www.nuget.org/packages/TaskTurnstile) | Core package |\n| `TaskTurnstile.Redis` | [![NuGet](https://img.shields.io/nuget/v/TaskTurnstile.Redis.svg)](https://www.nuget.org/packages/TaskTurnstile.Redis) | Dedicated Redis backing store |\n| `TaskTurnstile.SqlServer` | [![NuGet](https://img.shields.io/nuget/v/TaskTurnstile.SqlServer.svg)](https://www.nuget.org/packages/TaskTurnstile.SqlServer) | SQL Server backing store |\n| `TaskTurnstile.Testing` | [![NuGet](https://img.shields.io/nuget/v/TaskTurnstile.Testing.svg)](https://www.nuget.org/packages/TaskTurnstile.Testing) | `FakeTaskStateManager` test double |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchunty%2Ftaskturnstile","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchunty%2Ftaskturnstile","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchunty%2Ftaskturnstile/lists"}