Skip to content

feat(aspire): Garnet-as-executable shared cache/queue for Docker-less bare metal (generator + self-provision) #372

Description

@rickylabs

Child of #327 (enterprise deployment framework — explicitly bare-metal + Aspire). Sibling of #371 (shared Deno KV Connect). Together these are the two arms of an environment-aware shared-cache provisioner. Validated live in eis-chat (rickylabs/eis-chat#133).

Problem

The Aspire generator provisions a shared cache only as a Docker container — Redis/Garnet via addContainer (ghcr.io/microsoft/garnet), and the historical Deno KV Connect path was also a container (ghcr.io/denoland/denokv). On a Docker-less host (e.g. Windows bare metal — a first-class target per #327/#364) there is no way to stand up a shared cache/queue: DenoKv no-ops (file-backed, per-process), and Redis/Garnet require Docker. Result in multi-process mode: workers-api (enqueue) and the workers processor (listen) each open their own per-process Deno KV, so jobs are never delivered (split-brain queue).

Confirmed: git log --all -S "GarnetServer" / -S "Microsoft.Garnet" in netscript-start = 0 commits. Neither netscript-start nor the SDK has ever run Garnet as an executable — only the container integration + an External (BYO-URL) mode. So there is no Docker-less managed shared cache today.

Proposal — Garnet as an Aspire EXECUTABLE, self-provisioned

Garnet is .NET-native and runs on Windows bare metal without Docker. Since the Aspire AppHost is itself .NET-hosted (the SDK is guaranteed present), the generator can self-provision it:

  • Ship a local tool manifest (.config/dotnet-tools.json) pinning garnet-server (the Microsoft-published, verified NuGet tool — dotnet tool search garnetgarnet-server), and dotnet tool restore at AppHost startup; then register addExecutable('garnet', 'garnet-server', ['--port','6379','--bind','127.0.0.1', ...]) with a tcp endpoint on 6379. (Or probe + dotnet tool install on first run.)
  • Inject the connection env into every RequiresKv consumer: GARNET_URI (or services__garnet__tcp__0 / ConnectionStrings__garnet). The SDK already reads these.
  • The generator's shared-cache selection should be environment-aware: Docker present → Redis/Garnet/denokv container (existing); Docker-less bare metal → Garnet (or Redis) executable via the managed dotnet tool.

No @netscript/kv or @netscript/queue change needed: @netscript/kv/redis RedisKvAdapter + @netscript/queue RedisAdapter (native LPUSH/BRPOPLPUSH, cross-process) already consume GARNET_URI. One requirement to document: each Deno entrypoint that calls getKv() must import '@netscript/kv/redis' (self-registers the adapter) — otherwise getKv() throws "Redis adapter is not registered" once a Garnet URL is present. (The plugin-workers/services entrypoint already does this; a bare background-runtime entrypoint like workers/runtime.ts does not — the generator/docs should surface this.)

Live proof (eis-chat, Docker-less Windows bare metal, .NET 10, @netscript/* alpha.19)

Hand-edited the generated apphost helpers to stand Garnet up as an executable + inject GARNET_URI/REDIS_URI/CACHE_PROVIDER=garnet into workers-api + the workers processor, and added import 'jsr:@netscript/kv@0.0.1-alpha.19/redis' to workers/runtime.ts. Then, via the Aspire CLI/MCP (aspire start, list_resources, execute_resource_command, list_console_logs):

  • garnet resource: Running / Healthy, garnet-server --port 6379 --bind 127.0.0.1 --memory 1g --index 64m.
  • workers-api + workers: both Running/Healthy, both WaitFor(garnet), both carry GARNET_URI.
  • Triggered a job on workers-api (POST /api/v1/workers/jobs/<id>/trigger, the enqueue side) → the separate workers processor logged Processing job … (trigger: api)Executing job … via WorkerPool. Cross-process delivery over the shared Garnet queue works — the exact hop the split-brain Deno KV was dropping.

(The health-check job then failed with Module not found …/plugins/workers/jobs/health-check.ts — an unrelated thin-plugin-surface gap where the plugin's own job entrypoint isn't vendored; the queue delivered the message correctly. Filed/flagged separately.)

Asks

  1. Generator (packages/cli/.../generate-register-infrastructure.ts): add a Garnet-executable branch (new cache Mode, e.g. Executable/BareMetal) emitting addExecutable('garnet','garnet-server', ...) + tcp endpoint + GARNET_URI/services__garnet__tcp__0 injection into RequiresKv consumers.
  2. Self-provision the tool (.config/dotnet-tools.json + dotnet tool restore, or install-on-first-run) so git clone && aspire start needs no manual dotnet tool install.
  3. Environment-aware selection (Docker vs bare metal) shared with feat(aspire): restore shared Deno KV Connect cache/queue resource in the generator (multi-process backend) #371, and doc the import '@netscript/kv/redis' requirement for background-runtime entrypoints.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:deployDeployment: CLI/Aspire deploy, targets, bare-metalepic:deploymentEnterprise deployment framework epic

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions