{"id":30268720,"url":"https://github.com/Arcenox-co/TickerQ","last_synced_at":"2025-08-16T01:05:01.322Z","repository":{"id":178140278,"uuid":"630568472","full_name":"Arcenox-co/TickerQ","owner":"Arcenox-co","description":"TickerQ is a fast, reflection-free background task scheduler for .NET — built with source generators, EF Core integration, cron + time-based execution, and a real-time dashboard.","archived":false,"fork":false,"pushed_at":"2025-08-07T19:06:02.000Z","size":432,"stargazers_count":2027,"open_issues_count":14,"forks_count":83,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-08-08T08:26:15.129Z","etag":null,"topics":["background-processing","dotnet","job-scheduler","open-source","real-time-dashboard"],"latest_commit_sha":null,"homepage":"https://tickerq.arcenox.com","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Arcenox-co.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}},"created_at":"2023-04-20T16:55:23.000Z","updated_at":"2025-08-08T07:31:05.000Z","dependencies_parsed_at":"2025-05-13T13:43:44.990Z","dependency_job_id":"532426a3-acac-4048-bd14-1ced19bd76ab","html_url":"https://github.com/Arcenox-co/TickerQ","commit_stats":null,"previous_names":["arcenox/tickerq","arcenox-co/tickerq"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Arcenox-co/TickerQ","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Arcenox-co%2FTickerQ","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Arcenox-co%2FTickerQ/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Arcenox-co%2FTickerQ/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Arcenox-co%2FTickerQ/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Arcenox-co","download_url":"https://codeload.github.com/Arcenox-co/TickerQ/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Arcenox-co%2FTickerQ/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270653571,"owners_count":24622789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"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-processing","dotnet","job-scheduler","open-source","real-time-dashboard"],"created_at":"2025-08-16T01:02:06.900Z","updated_at":"2025-08-16T01:05:01.313Z","avatar_url":"https://github.com/Arcenox-co.png","language":"C#","funding_links":["https://opencollective.com/tickerq","https://opencollective.com/tickerq/backer/0/website?requireActive=false"],"categories":["C# #","Background Job Processing \u0026 Scheduler","Scheduling","Identifiers"],"sub_categories":["GUI - other"],"readme":"# TickerQ\n\n\n[![Discord Community](https://img.shields.io/badge/Discord-TickerQ-5865F2?logo=discord\u0026logoColor=white\u0026style=for-the-badge)](https://discord.gg/ZJemWvp9MK)\n\n\n[![NuGet](https://img.shields.io/nuget/dt/tickerq.svg)](https://www.nuget.org/packages/tickerq) \n[![NuGet](https://img.shields.io/nuget/vpre/tickerq.svg)](https://www.nuget.org/packages/tickerq)\n[![Build NuGet Packages](https://github.com/Arcenox-co/TickerQ/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/Arcenox-co/TickerQ/actions/workflows/build.yml)\n[![Documentation](https://img.shields.io/badge/docs%20-official%20web-blue)](https://tickerq.arcenox.com)\n[![](https://opencollective.com/tickerq/tiers/badge.svg)](https://opencollective.com/tickerq)\n\n\n**Robust. Adaptive. Precise.**  \nTickerQ is a fast, reflection-free background task scheduler for .NET — built with source generators, EF Core integration, cron + time-based execution, and a real-time dashboard.\n\n### 📚 Full Docs: [https://tickerq.arcenox.com](https://tickerq.arcenox.com)\n\u003e **Note:**\nAs of v2.2.0, all TickerQ packages are versioned together — even if a package has no changes — to keep the ecosystem in sync. Always update all packages to the same version.\n\n---\n## ✨ Features\n\n- **Time and Cron Scheduling**\n- **Stateless Core** with source generator\n- **EF Core Persistence**\n- **Live Dashboard UI**\n- **Retry Policies \u0026 Throttling**\n- **Dependency Injection support**\n- **Multi-node distributed coordination**\n---\n\n## 📦 Installation\n\n### Core (required)\n```bash\ndotnet add package TickerQ\n```\n\n### Entity Framework Integration (optional)\n```bash\ndotnet add package TickerQ.EntityFrameworkCore\n```\n\n### Dashboard UI (optional)\n```bash\ndotnet add package TickerQ.Dashboard\n```\n\n---\n\n## ⚙️ Basic Setup\n\n### In `Program.cs` or `Startup.cs`\n\n```csharp\nbuilder.Services.AddTickerQ(options =\u003e\n{\n    options.SetMaxConcurrency(4); // Optional\n    options.SetExceptionHandler\u003cMyExceptionHandler\u003e(); // Optional\n    options.AddOperationalStore\u003cMyDbContext\u003e(efOpt =\u003e \n    {\n        efOpt.UseModelCustomizerForMigrations(); // Applies custom model customization only during EF Core migrations\n        efOpt.CancelMissedTickersOnApplicationRestart(); // Useful in distributed mode\n    }); // Enables EF-backed storage\n    options.AddDashboard(basePath: \"/tickerq-dashboard\"); // Dashboard path\n    options.AddDashboardBasicAuth(); // Enables simple auth\n});\n\napp.UseTickerQ(); // Activates job processor\n```\n\nTo control when the job processor starts use the TickerQStartMode overload\n\n```csharp\napp.UseTickerQ(TickerQStartMode.Manual);\n\nITickerHost tickerHost = app.Services.GetRequiredService\u003cITickerHost\u003e(); // Resolve the Singleton service ITickerHost from the IServiceProvider.\n\ntickerHost.Start(); // Invoke the start method to manually start TickerQ\n```\n---\n\n## ❗️If Not Using `UseModelCustomizerForMigrations()`\n\n### You must apply TickerQ configurations manually in your `DbContext`:\n\n```csharp\npublic class MyDbContext : DbContext\n{\n    public MyDbContext(DbContextOptions\u003cMyDbContext\u003e options)\n        : base(options) { }\n\n    protected override void OnModelCreating(ModelBuilder builder)\n    {\n        base.OnModelCreating(builder);\n\n        // Apply TickerQ entity configurations explicitly\n        builder.ApplyConfiguration(new TimeTickerConfigurations());\n        builder.ApplyConfiguration(new CronTickerConfigurations());\n        builder.ApplyConfiguration(new CronTickerOccurrenceConfigurations());\n\n        // Alternatively, apply all configurations from assembly:\n        // builder.ApplyConfigurationsFromAssembly(typeof(TimeTickerConfigurations).Assembly);\n    }\n}\n```\n\n\u003e 💡 **Recommendation:**  \nUse `UseModelCustomizerForMigrations()` to cleanly separate infrastructure concerns from your core domain model, especially during design-time operations like migrations.  \n**Note:** If you're using third-party libraries (e.g., OpenIddict) that also override `IModelCustomizer`, you must either merge customizations or fall back to manual configuration inside `OnModelCreating()` to avoid conflicts.\n\n##  Job Definition\n\n### 1. **Cron Job (Recurring)**\n\n```csharp\npublic class CleanupJobs\n{\n    [TickerFunction(functionName: \"CleanupLogs\", cronExpression: \"0 0 * * *\" )]\n    public void CleanupLogs()\n    {\n        // Runs every midnight\n    }\n}\n```\n\n\u003e This uses a cron expression to run daily at midnight.\n\n---\n\n### 2. **One-Time Job (TimeTicker)**\n\n```csharp\npublic class NotificationJobs\n{\n    [TickerFunction(functionName: \"SendWelcome\")]\n    public Task SendWelcome(TickerFunctionContext\u003cstring\u003e tickerContext ,CancellationToken ct)\n    {\n        Console.WriteLine(tickerContext.Request); // Output: User123\n        return Task.CompletedTask;\n    }\n}\n```\n\nThen schedule it:\n\n```csharp\nawait _timeTickerManager.AddAsync(new TimeTicker\n{\n    Function = \"SendWelcome\",\n    ExecutionTime = DateTime.UtcNow.AddMinutes(1),\n    Request = TickerHelper.CreateTickerRequest\u003cstring\u003e(\"User123\"),\n    Retries = 3,\n    RetryIntervals = new[] { 30, 60, 120 }, // Retry after 30s, 60s, then 2min\n\n    // Optional batching\n    BatchParent = Guid.Parse(\"....\"),\n    BatchRunCondition = BatchRunCondition.OnSuccess\n});\n```\n\n---\n\n### 3. **Injecting Services in Jobs (Fully DI Support)**\n\n```csharp\npublic class ReportJobs\n{\n    private readonly IReportService _reportService;\n\n    public ReportJobs(IReportService reportService)\n    {\n        _reportService = reportService;\n    }\n\n    [TickerFunction(functionName: \"GenerateDailyReport\", cronExpression: \"0 6 * * *\")]\n    public async Task GenerateDailyReport()\n    {\n        await _reportService.GenerateAsync();\n    }\n}\n```\n\n---\n\n## Dashboard UI\n\n### Check out Dashboard Overview:  [TickerQ-Dashboard-Examples](https://tickerq.arcenox.com/intro/dashboard-overview.html)\n\nEnabled by adding:\n\n```csharp\noptions.AddDashboard(basePath: \"/tickerq-dashboard\");\noptions.AddDashboardBasicAuth(); // Optional\n```\n\nAccessible at `/tickerq-dashboard`, it shows:\n\n- System status\n- Active tickers\n- Job queue state\n- Cron ticker stats\n- Execution history\n- Trigger/cancel/edit jobs live\n\nAuth config (optional):\n\n```json\n\"TickerQBasicAuth\": {\n  \"Username\": \"admin\",\n  \"Password\": \"admin\"\n}\n```\n\n## 🔐 Retry \u0026 Locking\n\nTickerQ supports:\n\n- Retries per job\n- Retry intervals (`RetryIntervals`)\n- Distributed locking (EF mode only)\n- Job ownership tracking across instances\n- Cooldown on job failure\n\n---\n\n## 🧪 Advanced: Manual CronTicker Scheduling\n\n```csharp\nawait _cronTickerManager.AddAsync(new CronTicker\n{\n    Function = \"CleanupLogs\",\n    Expression = \"0 */6 * * *\", // Every 6 hours\n    Retries = 2,\n    RetryIntervals = new[] { 60, 300 }\n});\n```\n\n---\n\n## 🛠️ Developer Tips\n\n- Use `[TickerFunction]` to register jobs\n- Use `FunctionName` consistently across schedule and handler\n- Use `CancellationToken` for graceful cancellation\n- Use `Request` to pass dynamic data to jobs\n- If you are building this project locally, you must replace the `$(PackageVersion)` with any version NuGet package version (ideally the latest).\n- If you are getting random 403 responses, make sure that you don't have any filter in some endpoint that might be triggering it, thus causing issues with TickerQ's dashboard. Check this [issue](https://github.com/Arcenox-co/TickerQ/issues/155#issuecomment-3175214745) for more details.\n---\n\n## 💖 Sponsors \u0026 Backers\n\nWe want to acknowledge the individuals and organizations who support the development of TickerQ through [OpenCollective](https://opencollective.com/tickerq). Your contributions help us maintain and grow this project. If you'd like to support, check out the tiers below and join the community!\n\n\n[Become a Sponsor or Backer on OpenCollective](https://opencollective.com/tickerq)\n\n---\n\n### 🏆 Gold Sponsors\n*Become a gold sponsor and get your logo here with a link to your site.*\n\n---\n\n### 🥈 Silver Sponsors\n*Become a silver sponsor and get your logo here with a link to your site.*\n\n---\n\n### 🥉 Bronze Sponsors\n*Become a bronze sponsor and get your logo here with a link to your site.*\n\n---\n\n### 🙌 Backers\n[Become a backer](https://opencollective.com/tickerq#backer) and get your image on our README on GitHub with a link to your site.\n\n\u003ca href=\"https://opencollective.com/tickerq/backer/0/website?requireActive=false\" target=\"_blank\"\u003e\u003cimg width=\"30\" src=\"https://opencollective.com/tickerq/backer/0/avatar.svg?requireActive=false\"\u003e\u003c/a\u003e\n---\n\n## 🤝 Contribution\n\nPRs, ideas, and issues are welcome!\n\n1. Fork \u0026 branch\n2. Code your change\n3. Submit a Pull Request\n\n---\n\n## 📄 License\n\n**MIT OR Apache 2.0** © [Arcenox](https://arcenox.com)  \nYou may choose either license to use this software.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArcenox-co%2FTickerQ","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FArcenox-co%2FTickerQ","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FArcenox-co%2FTickerQ/lists"}