[Aspire.Hosting.Docker] UpdateConfig.MaxFailureRatio serializes as a quoted string and produces invalid Compose YAML
- Dominant language
- C#
- Stars
- 6.3k
- Forks
- 991
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 196
Description
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Describe the bug
`Aspire.Hosting.Docker.Resources.ServiceNodes.Swarm.UpdateConfig.MaxFailureRatio` is typed as `string?`.
When assigned a valid Docker Swarm failure ratio such as `"0"`, Aspire publishes it as a quoted YAML string:
```yaml
deploy:
update_config:
max_failure_ratio: "0"
```
Docker Compose requires `max_failure_ratio` to be a numeric value. As a result, the generated deployment artifact fails validation:
```text
services.web.deploy.update_config.max_failure_ratio must be a number
```
This appears related to #15566, which corrected the types of `Parallelism` and `FailureAction`, but did not change `MaxFailureRatio`.
### Expected Behavior
`MaxFailureRatio` should use a numeric CLR type, likely `double?`, and serialize as a YAML number:
```yaml
deploy:
update_config:
max_failure_ratio: 0
```
A Compose file generated by Aspire should pass `docker compose config` and `docker stack config` validation without requiring manual edits.
### Steps To Reproduce
Create an Aspire AppHost with the Docker hosting integration and configure a Docker Compose service with `MaxFailureRatio`:
```csharp
using Aspire.Hosting.Docker.Resources.ServiceNodes.Swarm;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("web", "nginx")
.PublishAsDockerComposeService((_, service) =>
{
service.Deploy ??= new();
service.Deploy.UpdateConfig = new UpdateConfig
{
Parallelism = 1,
FailureAction = "rollback",
MaxFailureRatio = "0",
Order = "start-first"
};
});
builder.AddDockerComposeEnvironment("compose");
builder.Build().Run();
```
Publish the application:
```shell
aspire publish --environment Production --non-interactive
```
The generated Compose YAML contains:
```yaml
update_config:
parallelism: 1
failure_action: "rollback"
max_failure_ratio: "0"
order: "start-first"
```
Validate it:
```shell
docker stack config -c docker-compose.yaml
```
The command fails with:
```text
services.web.deploy.update_config.max_failure_ratio must be a number
```
Removing `MaxFailureRatio` allows the generated Compose file to validate because Docker's default value is numeric zero.
### Exceptions (if any)
No .NET exception is thrown during publishing. The invalid type is detected by Docker when validating the generated Compose file:
```text
services.web.deploy.update_config.max_failure_ratio must be a number
```
### Aspire doctor output
```text
Aspire Environment Check
========================
Aspire
✅ Aspire CLI version 13.4.6 (channel: stable)
AppHost
✅ AppHost version 13.4.6
.NET SDK
✅ .NET 10.0.400-preview.0.26322.102 installed (x64)
Container Runtime
✅ Docker v29.6.2: running (auto-detected (default))
Environment
✅ HTTPS development certificate is trusted
Summary: 5 passed, 0 warnings, 0 failed
Aspire CLI version:
13.4.6+87fe259e4fc244c599019a7b1304c85a1488f248
```
### Anything else?
- Operating system: Windows
- Aspire CLI: 13.4.6
- Aspire AppHost SDK: 13.4.6
- .NET SDK: 10.0.400-preview.0.26322.102
- Docker Engine: 29.6.2
- Deployment target: Docker Compose used with Docker Swarm
- Workaround: omit `MaxFailureRatio`, allowing Docker's default value of `0` to apply
- Related change: https://github.com/microsoft/aspire/pull/15566
Contributor guide
Research direction
Inspect Aspire.Hosting.Docker.Resources.ServiceNodes.Swarm.UpdateConfig, focusing on the MaxFailureRatio declaration and the existing Docker Compose serialization path. Reproduce the issue with the configuration shown, then verify that the generated max_failure_ratio is numeric and that the resulting file passes docker stack config or docker compose config validation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, docker, docker-compose
- Domain
- devops
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- Half a day
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100