Skip to content

add WithModule extension methods to IResourceBuilder<RedisResource>#18025

Open
aradalvand wants to merge 5 commits into
microsoft:mainfrom
aradalvand:main
Open

add WithModule extension methods to IResourceBuilder<RedisResource>#18025
aradalvand wants to merge 5 commits into
microsoft:mainfrom
aradalvand:main

Conversation

@aradalvand

@aradalvand aradalvand commented Jun 8, 2026

Copy link
Copy Markdown

Description

Adds WithModule extension methods to IResourceBuilder<RedisResource> so Redis containers can load Redis 8+ native modules or custom Redis module .so files.

Fixes #9768

The public C# API keeps strongly typed overloads, while polyglot app hosts get a single exported withModule method that accepts either a RedisNativeModule value or a custom module path.

var cache = builder.AddRedis("cache")
    .WithModule(RedisNativeModule.Json)
    .WithModule(RedisNativeModule.Search)
    .WithModule("/opt/redis/custom-module.so");
const cache = builder.addRedis("cache")
    .withModule(RedisNativeModule.Json)
    .withModule("/opt/redis/custom-module.so");

Custom module paths are validated as absolute container paths ending in .so.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Copilot AI review requested due to automatic review settings June 8, 2026 22:00
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18025

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18025"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds first-class support for loading Redis modules via resource annotations so Redis containers can be started with --loadmodule entries.

Changes:

  • Collect RedisModuleAnnotation annotations to append --loadmodule <path> arguments when starting Redis
  • Add WithModule(...) builder extensions for loading modules by preinstalled native module enum or explicit .so path
  • Introduce RedisNativeModule mapping to container module paths

Comment thread src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs Outdated
Comment thread src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs Outdated
Comment thread src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs Outdated
@aradalvand

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

1 similar comment
@aradalvand

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@davidfowl

davidfowl commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@aradalvand this doesn't build and there lots of AI comments on here.

I haven't spent time on adding unit tests yet because first I need to know whether the design is correct based on the maintainers' judgement.

Code samples help with this... I think we need to see this in action first to see if it works well locally and what happens when you attempt to deploy. Right now, it doesn't compile.

@sebastienros sebastienros self-assigned this Jun 9, 2026
Expose a single polyglot-only union overload for Redis WithModule, keep typed C# overloads public, and add test/polyglot coverage for the new API.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros

Copy link
Copy Markdown
Contributor

I submitted a bacth of fixes, including polyglot support

Reject custom Redis module paths unless they are absolute container paths ending in .so, and cover invalid values in unit tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros

sebastienros commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

PR Testing Report

PR Information

Verification Request

This verifies the concerns raised in #18025 (comment):

  • Confirm the PR now builds.
  • Show the new API in action locally.
  • Check publish/deployment output.

CLI / Package Source Used

The official dogfood installer was retried, but the selected PR workflow run still has no downloadable CLI artifacts:

no valid artifacts found to download
Failed to download artifact 'cli-native-archives-osx-arm64'

To complete the missing runtime validation, I built a local hive from the PR checkout at the tested commit and used that CLI/package layout for the AppHost SDK, Redis hosting package, DCP, dashboard, and local run.

Local hive CLI version:

13.5.0-local.20260609.t174428

Source Build and Unit Verification

Scenario 1: Redis hosting project build

Objective: Confirm the PR compiles after the review fixes.
Coverage Type: Build verification
Status: Passed

./restore.sh
dotnet build src/Aspire.Hosting.Redis/Aspire.Hosting.Redis.csproj --no-restore /p:SkipNativeBuild=true

Result:

Build succeeded.
0 Warning(s)
0 Error(s)

Scenario 2: Focused Redis WithModule tests

Objective: Verify native module args, custom module path args, multiple modules, and validation failures.
Coverage Type: Happy path and unhappy path
Status: Passed

dotnet test --project tests/Aspire.Hosting.Redis.Tests/Aspire.Hosting.Redis.Tests.csproj --no-launch-profile -- \
  --filter-method "*.WithModuleAddsCommandLineArgsForNativeModule" \
  --filter-method "*.WithModuleAddsCommandLineArgsForModulePath" \
  --filter-method "*.WithModuleAddsCommandLineArgsForMultipleModules" \
  --filter-method "*.WithModuleShouldThrowWhenPathIsNullOrEmpty" \
  --filter-method "*.WithModuleShouldThrowWhenPathIsNotAbsoluteSoPath" \
  --filter-method "*.WithModuleUnionShouldThrowWhenModuleIsNull" \
  --filter-method "*.WithModuleUnionShouldThrowWhenModuleTypeIsUnsupported" \
  --filter-not-trait "quarantined=true" \
  --filter-not-trait "outerloop=true"

Result:

Test run summary: Passed!
total: 10
failed: 0
succeeded: 10
skipped: 0

Local API Usage Verification

Scenario 3: Generated C# file-based AppHost uses Redis modules

Objective: Exercise the new API in a generated AppHost using the PR-built local hive.
Coverage Type: Happy path API usage
Status: Passed

Generated AppHost sample:

#:sdk Aspire.AppHost.Sdk@13.5.0-local.20260609.t174428
#:package Aspire.Hosting.Redis@13.5.0-local.20260609.t174428

var builder = DistributedApplication.CreateBuilder(args);

builder.AddRedis("cache")
    .WithModule(RedisNativeModule.Json)
    .WithModule("/opt/redis/custom-module.so");

builder.Build().Run();

Result: the generated AppHost builds and the API is usable from C# with both overloads:

  • WithModule(RedisNativeModule.Json)
  • WithModule("/opt/redis/custom-module.so")

Publish / Deployment Artifact Verification

Scenario 4: Manifest publish includes Redis module arguments

Objective: Verify deployment/publish output represents Redis module loading correctly.
Coverage Type: Publish artifact verification
Status: Passed

Manifest generation:

dotnet run apphost.cs -- --publisher manifest --output-path <manifest>

Relevant manifest output:

{
  "resources": {
    "cache": {
      "type": "container.v0",
      "image": "docker.io/library/redis:8.6",
      "entrypoint": "/bin/sh",
      "args": [
        "-c",
        "redis-server --requirepass $REDIS_PASSWORD --loadmodule /usr/local/lib/redis/modules/rejson.so --loadmodule /opt/redis/custom-module.so"
      ]
    }
  }
}

Result: manifest generation succeeded and includes both module load arguments:

  • Native module: --loadmodule /usr/local/lib/redis/modules/rejson.so
  • Custom module path: --loadmodule /opt/redis/custom-module.so

I also ran aspire publish --output-path <output> --non-interactive against the generated AppHost. The pipeline completed successfully:

✅ Pipeline succeeded
4/4 steps succeeded

Local Runtime Verification

Scenario 5: Start Redis locally with a native Redis module

Objective: Verify Redis starts locally with the native module path generated by WithModule(RedisNativeModule.Json).
Coverage Type: Runtime/local behavior
Status: Passed

Generated runtime AppHost:

#:sdk Aspire.AppHost.Sdk@13.5.0-local.20260609.t174428
#:package Aspire.Hosting.Redis@13.5.0-local.20260609.t174428

var builder = DistributedApplication.CreateBuilder(args);

builder.AddRedis("cache")
    .WithModule(RedisNativeModule.Json);

builder.Build().Run();

Start command:

aspire start --apphost . --isolated --non-interactive --format Json

aspire ps showed the AppHost running:

[
  {
    "status": "running",
    "sdkVersion": "13.5.0-local.20260609.t174428"
  }
]

Docker showed the Redis container running with the expected native module argument:

image=docker.io/library/redis:8.6
entrypoint=["/bin/sh"]
cmd=["-c","redis-server --requirepass $REDIS_PASSWORD --loadmodule /usr/local/lib/redis/modules/rejson.so ..."]
state=running

Redis logs confirmed the module loaded and the server accepted connections:

Module 'ReJSON' loaded from /usr/local/lib/redis/modules/rejson.so
Ready to accept connections tcp
Ready to accept connections tls

The AppHost was stopped successfully after inspection.

Unhappy-Path Verification

Scenario 6: Invalid custom module paths fail fast

Objective: Verify invalid custom module paths do not defer failure to Redis/container startup.
Coverage Type: Unhappy path / validation
Status: Passed

Invalid values covered by unit tests:

  • null
  • empty string
  • relative path: custom-module.so
  • absolute path without .so: /opt/redis/custom-module
  • absolute path with wrong extension: /opt/redis/custom-module.txt

Expected outcome: ArgumentNullException or ArgumentException with path as the parameter name.

Result: all invalid-path cases fail fast.

Summary

Scenario Status Notes
Redis hosting project build Passed 0 warnings, 0 errors
Focused WithModule tests Passed 10 tests passed
Generated AppHost API usage Passed Native and custom module calls compile
Manifest publish output Passed Includes both --loadmodule args
aspire publish pipeline Passed 4/4 steps succeeded
Local Redis runtime startup Passed Redis 8.6 started with ReJSON loaded
Invalid path validation Passed Invalid paths fail fast
Official dogfood artifact install Blocked externally PR workflow currently has no CLI artifacts

Overall Result

Verified with local PR-built hive. The PR now builds, the new API works in generated AppHost code, invalid input fails fast, publish/manifest output carries the Redis module arguments correctly, and Redis starts locally with the native JSON module loaded.

Ensure enums referenced only through AspireUnion alternatives are included in the scanned enum type set so polyglot SDK generation can emit them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienros sebastienros self-requested a review as a code owner June 9, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redis v8's default modules aren't loaded

4 participants