Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
6c4812f
feat(api,ui): Add cursor-based pagination and workflow updates
bugrakosen May 20, 2026
9cde02d
feat(config): add support for configurable base path
bugrakosen May 20, 2026
fe774bd
refactor(dispatcher): decouple zombie cleanup logic
bugrakosen May 20, 2026
d454170
chore: Upgrade versions.
bugrakosen May 21, 2026
8a2164b
tests: test fix.
bugrakosen May 21, 2026
91f0d4b
feat: Add runtime base path config via /config.js endpoint
bugrakosen May 21, 2026
de110c5
fix: Change log level to information.
bugrakosen May 21, 2026
f548285
fix: Refactor config usage and log API base path at startup.
bugrakosen May 21, 2026
5314a5c
feat: Add RabbitMQ Management API support for queue monitoring
bugrakosen May 22, 2026
fe5b64c
fix: Update SDK package versions and refine sync logging
bugrakosen Jun 7, 2026
c212b80
feat: Block unnecessary user activity logs when workflow engine trigg…
bugrakosen Jun 16, 2026
a054d90
feat: Change main ui color.
bugrakosen Jul 9, 2026
1263a5b
feat: Add local job testing support and update dependencies
bugrakosen Jul 9, 2026
ae85b6c
fix: Update dependencies and test imports
bugrakosen Jul 9, 2026
6b9564d
feat: Refactor alert timeout handling and improve test reliability
bugrakosen Jul 10, 2026
8097d10
feat: Add infinite scroll to JobList card view
bugrakosen Jul 15, 2026
3ec6352
feat: Add API key management, MCP server, and UI integration
bugrakosen Jul 18, 2026
5e81213
docs: Update docs.
bugrakosen Jul 18, 2026
e7d7853
feat: Enforce MCP tool conventions, filtering, and prompts
bugrakosen Jul 18, 2026
7929570
feat: Expand MCP tools for Milvaion AI; update docs
bugrakosen Jul 18, 2026
982c0b3
feat: Add MediatR queries for MCP tool API analysis & reports
bugrakosen Jul 19, 2026
a58b859
feat: UI enhancements, add new mcp tools, impove workflow condition n…
bugrakosen Jul 19, 2026
90b9395
feat: UI enhancements.
bugrakosen Jul 20, 2026
d2c42ef
feat: UI/UX overhaul: dashboards, JSON, triggers, resource API
bugrakosen Jul 20, 2026
49e3a57
feat: Update job deletion logic to prevent removal if jobs are runnin…
bugrakosen Jul 20, 2026
23ff3aa
fix: Css fix.
bugrakosen Jul 22, 2026
329c190
feat: Improve mobile layouts and responsive UI handling
bugrakosen Jul 22, 2026
d7a654f
feat: Add integration tests for IRabbitMQPublisher routability
bugrakosen Jul 23, 2026
51b7d12
feat(settings): add runtime settings, alerting, and UI updates
bugrakosen Aug 2, 2026
bc85d21
chore(release): bump version to 1.2.3
bugrakosen Aug 2, 2026
97607ba
feat(scheduler): add running job reconciliation and test provider
bugrakosen Aug 2, 2026
73cf306
test: Stop the dispatcher tests racing their own startup
ebitrd Aug 3, 2026
a867832
fix: Bind log messages as values instead of templates
ebitrd Aug 3, 2026
2ede5e5
fix: Guard the log publisher against double disposal
ebitrd Aug 3, 2026
9b0ded9
fix: Stop logging a shutdown as a worker discovery failure
ebitrd Aug 3, 2026
e07648a
feat: Await broker acks on every publish
ebitrd Aug 3, 2026
e5eb053
docs: Document publisher confirms
ebitrd Aug 3, 2026
1e48db1
Merge branch 'feature/rabbitmq-publisher-confirms'
ebitrd Aug 3, 2026
1962da9
feat: Support quorum queues when declaring RabbitMQ topology
ebitrd Aug 3, 2026
976564b
docs: Document the RabbitMQ queue type setting
ebitrd Aug 3, 2026
f05f96b
docs: Document the queue type in the architecture guide
ebitrd Aug 3, 2026
6104e41
Merge branch 'feature/rabbitmq-quorum-queues'
ebitrd Aug 3, 2026
68338d1
feat: Namespace every Redis key with a configurable prefix
ebitrd Aug 4, 2026
fd1b746
docs: Document the worker Redis key prefix
ebitrd Aug 4, 2026
a2692ed
docs: Correct the Redis key structure
ebitrd Aug 4, 2026
793db7c
Merge branch 'feature/redis-key-prefix'
ebitrd Aug 4, 2026
240e93d
chore: Correct solution projects and drop the duplicate compose
ebitrd Aug 4, 2026
40fe222
feat: Add visual cron expression builder
ebitrd Aug 4, 2026
43ff033
Merge branch 'feature/cron-builder'
ebitrd Aug 4, 2026
a455acb
fix: Resolve head asset paths against the base path
ebitrd Aug 4, 2026
2413ecb
feat: Apply the SPA base path at runtime instead of build time
ebitrd Aug 4, 2026
b5d73ae
docs: Record that the runtime base path guide landed in the wrong commit
ebitrd Aug 4, 2026
1ca9866
Merge branch 'feature/runtime-base-path'
ebitrd Aug 4, 2026
3a8b7e9
Merge branch 'Milvasoft:master' into master
ebitrd Aug 4, 2026
d02f622
Merge remote-tracking branch 'origin/master'
ebitrd Aug 4, 2026
605d5f1
refactor(auth): Remove UserType concept from codebase
bugrakosen Aug 7, 2026
0b37b59
Merge branch 'Milvasoft:master' into master
ebitrd Aug 10, 2026
9495f8c
feat: Make RabbitMQ publisher confirms configurable
ebitrd Aug 10, 2026
6455c2d
chore: Regenerate the tracked XML documentation
ebitrd Aug 10, 2026
9647f83
Merge branch 'feature/configurable-publisher-confirms'
ebitrd Aug 10, 2026
04ce5d1
fix: Make existing installations usable again after the UserType removal
ebitrd Aug 10, 2026
39bbada
fix: Bring the new private members in line with the naming convention
ebitrd Aug 10, 2026
dc2f7ab
fix: Load the shared modal styles with the cron builder
ebitrd Aug 10, 2026
10a59dc
Merge pull request #5 from ebitrd/master
bugrakosen Aug 10, 2026
6096798
refactor(sdk): Bump package versions
bugrakosen Aug 10, 2026
64f47b7
refactor(redis): pascalcase keys, logging, migration tweaks
bugrakosen Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 12 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,15 @@
- Follow naming conventions

## Testing Practices
- Integration tests should prefer obtaining services like IMilvaLogger directly from the ServiceProvider instead of using stubs or mocks.
- Integration tests should prefer obtaining services like IMilvaLogger directly from the ServiceProvider instead of using stubs or mocks.

## Commit Messages
Always generate commit messages that follow the [Conventional Commits](https://www.conventionalcommits.org/) specification.

- Format: `<type>(<scope>): <description>`, optionally followed by a blank line, body, and footer(s).
- Subject: imperative mood ("add", "fix", "remove"), lower-case, no trailing period, at most 72 characters.
- Types: `feat`, `fix`, `perf`, `refactor`, `docs`, `style`, `test`, `build`, `ci`, `chore`, `revert`.
- Scope (optional, lower-case) is the affected area, e.g. `api`, `ui`, `infrastructure`, `application`, `domain`, `sdk`, `mcp`, `settings`, `jobs`, `workflows`, `alerting`, `redis`, `auth`, `db`, `deps`. Omit it when a change spans many areas; never invent a scope not reflected by the changed files.
- Breaking changes: add `!` after the type/scope and a `BREAKING CHANGE:` footer.
- Describe intent (what/why), not a file list. Reference issues in the footer when relevant (`Closes #123`).
- Full rules and examples: [.github/git-commit-instructions.md](git-commit-instructions.md).
66 changes: 66 additions & 0 deletions .github/git-commit-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Commit message instructions (Conventional Commits)

Write every commit message following the [Conventional Commits](https://www.conventionalcommits.org/) specification.

## Format

```
<type>(<scope>): <description>

[optional body]

[optional footer(s)]
```

- The **subject** line is `<type>(<scope>): <description>`.
- Keep the subject in the **imperative mood** ("add", "fix", "remove" — not "added"/"fixes"), lower-case, no trailing period, and **<= 72 characters**.
- `scope` is optional but preferred; use lower-case.
- Leave a blank line before the body and before the footer.
- Wrap the body at ~100 characters. Explain **what** and **why**, not how.

## Allowed types

- `feat` — a new feature
- `fix` — a bug fix
- `perf` — a performance improvement
- `refactor` — a code change that neither fixes a bug nor adds a feature
- `docs` — documentation only
- `style` — formatting/whitespace, no code behaviour change
- `test` — adding or fixing tests
- `build` — build system, dependencies, packaging
- `ci` — CI/CD configuration and scripts
- `chore` — housekeeping that doesn't touch src or tests
- `revert` — reverts a previous commit

## Suggested scopes (this repo)

Pick the most specific scope that fits: `api`, `ui`, `infrastructure`, `application`, `domain`, `sdk`, `mcp`, `settings`, `jobs`, `workflows`, `occurrences`, `alerting`, `redis`, `auth`, `db`, `deps`, `ci`, `docs`. Omit the scope if a change spans many areas.

## Breaking changes

- Add a `!` after the type/scope **and** a `BREAKING CHANGE:` footer:

```
feat(api)!: change occurrence list response shape

BREAKING CHANGE: `totalCount` is now an estimate, not an exact count.
```

## Rules

- One logical change per commit; the subject should describe the whole change.
- Do not invent a scope that isn't reflected by the changed files.
- Do not include file lists in the message; summarise the intent.

## Examples

```
feat(settings): add runtime branding and notification config
fix(redis): estimate occurrence counts from planner stats to avoid full scans
perf(ui): format execution total with compact K/M notation
refactor(infrastructure): qualify SettingsProvider registration to avoid BCL type clash
docs(mcp): document settings tools
build(deps): bump Npgsql to 10.0.10
test(alerting): stub ISettingsProvider in AlertNotifier tests
chore(ci): silence MCP002 analyzer suggestion
```
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,7 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
/CoverageReport

# Local environment variables
.env
.env.local
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// GitHub Copilot generates commit messages using the Conventional Commits rules in
// .github/git-commit-instructions.md.
"github.copilot.chat.commitMessageGeneration.instructions": [
{ "file": ".github/git-commit-instructions.md" }
]
}
33 changes: 11 additions & 22 deletions Milvaion.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -85,29 +85,9 @@
<File Path="docs/portaldocs/20-workflows.md" />
<File Path="docs/portaldocs/21-reporter-worker.md" />
<File Path="docs/portaldocs/22-reports.md" />
<File Path="docs/portaldocs/23-local-job-testing.md" />
</Folder>
<Folder Name="/src/">
<Project Path="src/MilvaionUI/" Type="Website" DisplayName="MilvaionUI">
<BuildType Project="Debug" />
<Properties Name="WebsiteProperties">
<Property Name="Debug.AspNetCompiler.Debug" Value="&quot;True&quot;" />
<Property Name="Debug.AspNetCompiler.FixedNames" Value="&quot;false&quot;" />
<Property Name="Debug.AspNetCompiler.ForceOverwrite" Value="&quot;true&quot;" />
<Property Name="Debug.AspNetCompiler.PhysicalPath" Value="&quot;src\MilvaionUI\&quot;" />
<Property Name="Debug.AspNetCompiler.TargetPath" Value="&quot;PrecompiledWeb\localhost_49627\&quot;" />
<Property Name="Debug.AspNetCompiler.Updateable" Value="&quot;true&quot;" />
<Property Name="Debug.AspNetCompiler.VirtualPath" Value="&quot;/localhost_49627&quot;" />
<Property Name="Release.AspNetCompiler.Debug" Value="&quot;False&quot;" />
<Property Name="Release.AspNetCompiler.FixedNames" Value="&quot;false&quot;" />
<Property Name="Release.AspNetCompiler.ForceOverwrite" Value="&quot;true&quot;" />
<Property Name="Release.AspNetCompiler.PhysicalPath" Value="&quot;src\MilvaionUI\&quot;" />
<Property Name="Release.AspNetCompiler.TargetPath" Value="&quot;PrecompiledWeb\localhost_49627\&quot;" />
<Property Name="Release.AspNetCompiler.Updateable" Value="&quot;true&quot;" />
<Property Name="Release.AspNetCompiler.VirtualPath" Value="&quot;/localhost_49627&quot;" />
<Property Name="TargetFrameworkMoniker" Value="&quot;.NETFramework,Version%3Dv4.8&quot;" />
<Property Name="VWDPort" Value="&quot;49627&quot;" />
</Properties>
</Project>
</Folder>
<Folder Name="/src/Scheduler/" />
<Folder Name="/src/Scheduler/Core/">
Expand All @@ -130,6 +110,9 @@
<Project Path="src/Sdk/Milvasoft.Milvaion.Sdk.Worker/Milvasoft.Milvaion.Sdk.Worker.csproj">
<BuildType Solution="TemplateTest|*" Project="Debug" />
</Project>
<Project Path="src/Sdk/Milvasoft.Milvaion.Sdk.Worker.Testing/Milvasoft.Milvaion.Sdk.Worker.Testing.csproj">
<BuildType Solution="TemplateTest|*" Project="Debug" />
</Project>
<Project Path="src/Sdk/Milvasoft.Milvaion.Sdk/Milvasoft.Milvaion.Sdk.csproj" Id="848b918f-4553-4e07-8531-3c9423a9fa5e">
<BuildType Solution="TemplateTest|*" Project="Debug" />
</Project>
Expand Down Expand Up @@ -165,7 +148,13 @@
<BuildType Solution="TemplateTest|*" Project="Debug" />
</Project>
</Folder>
<Folder Name="/tests/" />
<Folder Name="/tests/">
<Project Path="tests/SampleWorker.Tests/SampleWorker.Tests.csproj">
<BuildType Solution="TemplateTest|*" Project="Debug" />
<Build Solution="Debug|*" Project="false" />
<Build Solution="TemplateTest|*" Project="false" />
</Project>
</Folder>
<Folder Name="/tests/IntegrationTests/">
<Project Path="tests/Milvaion.IntegrationTests/Milvaion.IntegrationTests.csproj">
<BuildType Solution="TemplateTest|*" Project="Release" />
Expand Down
90 changes: 72 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

<p align="center">
A distributed job scheduling system built on .NET 10
<br>
<sub>Already on <b>Hangfire</b> or <b>Quartz.NET</b>? Keep it — <a href="#already-running-hangfire-or-quartznet">add Milvaion monitoring in two lines</a>.</sub>
</p>

<div align="center">
Expand Down Expand Up @@ -60,12 +62,59 @@ Milvaion solves these problems by **completely separating scheduling from execut

---

## Already Running Hangfire or Quartz.NET?

**You don't have to migrate to adopt Milvaion.**

Milvaion plugs into the scheduler you already run. Your scheduler keeps owning triggers, storage and cron expressions. Your job code doesn't change. Milvaion adds one real-time dashboard across every service, plus persisted execution history, metrics and alerting.

```csharp
// Hangfire - your existing setup stays exactly as it is
builder.Services.AddMilvaionHangfireIntegration(builder.Configuration);
builder.Services.AddHangfire((sp, config) => config.UseMilvaion(sp));

// Quartz.NET - your existing setup stays exactly as it is
builder.Services.AddMilvaionQuartzIntegration(builder.Configuration);
builder.Services.AddQuartz(q => q.UseMilvaion(builder.Services));
```

That's the whole integration.

### The problem this solves

A typical .NET estate ends up with background jobs scattered across a dozen services — each with its own dashboard behind its own URL and its own auth. Nobody can answer *"which jobs failed last night?"* without opening every one of them, and history vanishes when the retention window rolls over.

| Before | After |
|--------|-------|
| One dashboard per service | One dashboard for the whole estate |
| History limited by Hangfire/Quartz retention | Full execution history in PostgreSQL |
| Logs only in each app's own sink | Real-time log streaming per execution |
| Failures noticed when someone complains | Multi-channel alerts on failure and timeout |
| No cross-service metrics | Success rate, duration and EPM per job |

### The adoption path

1. **Add monitoring** — two lines per application. No migration window, no change to job code.
2. **Get visibility** — every Hangfire and Quartz.NET job appears in the dashboard, flagged as external.
3. **Migrate selectively, or never** — when one job outgrows in-process execution, move just that job to a Milvaion worker. Everything else keeps running untouched.

Plenty of teams stop at step 2. That's a perfectly good outcome.

| Scheduler | Package | Status |
|-----------|---------|--------|
| **Hangfire** | `Milvasoft.Milvaion.Sdk.Worker.Hangfire` | ✅ Available |
| **Quartz.NET** | `Milvasoft.Milvaion.Sdk.Worker.Quartz` | ✅ Available |

📖 **[Full Integration Guide →](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/external-schedulers)**

---

## Features

![Milvaion Real Time](https://portal.milvasoft.com/assets/images/executions-4b5918b7fca1b603f54be133c7880397.gif)

### Reliability
- **At-least-once delivery** via RabbitMQ manual ACK
- **At-least-once delivery** via RabbitMQ publisher confirms and manual ACK
- **Automatic retries** with exponential backoff
- **Dead Letter Queue** for failed jobs after max retries
- **Zombie detection** recovers stuck jobs
Expand Down Expand Up @@ -105,26 +154,28 @@ Milvaion solves these problems by **completely separating scheduling from execut
- **Maintenance Worker** - Milvaion self data warehouse cleanup and archival

### External Scheduler Integration
Already using **Quartz.NET** or **Hangfire**? Keep your existing scheduler and gain Milvaion's monitoring capabilities:

| Scheduler | Package | Status |
|-----------|---------|--------|
| **Quartz.NET** | `Milvasoft.Milvaion.Sdk.Worker.Quartz` | ✅ Available |
| **Hangfire** | `Milvasoft.Milvaion.Sdk.Worker.Hangfire` | ✅ Available |
Milvaion also monitors jobs running in **Quartz.NET** and **Hangfire** without replacing them — see [Already Running Hangfire or Quartz.NET?](#already-running-hangfire-or-quartznet) above.

```csharp
// Quartz.NET Integration
builder.Services.AddMilvaionQuartzIntegration(builder.Configuration);
builder.Services.AddQuartz(q => q.UseMilvaion(builder.Services));
### MCP Server
Point Claude Code, Cursor or GitHub Copilot at Milvaion and ask about your jobs in plain language:

// Hangfire Integration
builder.Services.AddMilvaionHangfireIntegration(builder.Configuration);
builder.Services.AddHangfire((sp, config) => config.UseMilvaion(sp));
```json
{
"mcpServers": {
"milvaion": {
"type": "http",
"url": "https://milvaion.yourcompany.com/mcp",
"headers": { "X-ApiKey": "your-api-key" }
}
}
}
```

External jobs appear in Milvaion dashboard with full monitoring, metrics, and execution history - without changing your existing scheduler setup.
> *"Which jobs failed last night and why?"*

More than forty tools — reading, triggering, pausing, editing and deleting — each gated by the same permissions used everywhere else. A read-only api key gives an assistant full visibility and no ability to change anything. Milvaion is the data source here; it never calls a language model and stores no model provider keys.

[For more information...](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/external-schedulers)
📖 **[MCP Server Guide →](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/mcp-server)**

---

Expand Down Expand Up @@ -378,6 +429,9 @@ Each workflow can also configure **Max Step Retries** and a **Timeout** (auto-ca
| Document | Description |
|----------|-------------|
| [Introduction](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/introduction) | What is Milvaion, when to use it |
| [Hangfire & Quartz.NET Integration](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/external-schedulers) | Keep your existing scheduler, add Milvaion monitoring |
| [Api Keys](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/api-keys) | Credentials for CI pipelines, scripts and MCP clients |
| [MCP Server](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/mcp-server) | Connect Claude Code, Cursor or Copilot to Milvaion |
| [Quick Start](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/quick-start) | Get running in under 10 minutes |
| [Core Concepts](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/core-concepts) | Architecture and key terms |
| [Your First Worker](https://portal.milvasoft.com/docs/1.0.1/open-source-libs/milvaion/your-first-worker) | Create a custom worker |
Expand All @@ -397,6 +451,7 @@ Each workflow can also configure **Max Step Retries** and a **Timeout** (auto-ca
| [Architecture](./docs/githubdocs/ARCHITECTURE.md) | Technical architecture deep-dive |
| [Development](./docs/githubdocs/DEVELOPMENT.md) | Development environment setup |
| [Worker SDK](./docs/githubdocs/WORKER-SDK.md) | Worker SDK reference |
| [MCP Server](./docs/githubdocs/MCP-SERVER.md) | MCP server and api key auth internals |
| [Security](./SECURITY.md) | Security policies |

---
Expand Down Expand Up @@ -493,8 +548,7 @@ dotnet new install Milvasoft.Templates.Milvaion
# Pull the latest image
docker pull milvasoft/milvaion-api:latest

# Run with Docker Compose
cd build
# Run with Docker Compose, from the repository root
docker compose up -d
```

Expand Down
Loading