HostLoom.Valkey
0.8.0
See the version list below for details.
dotnet add package HostLoom.Valkey --version 0.8.0
NuGet\Install-Package HostLoom.Valkey -Version 0.8.0
<PackageReference Include="HostLoom.Valkey" Version="0.8.0" />
<PackageVersion Include="HostLoom.Valkey" Version="0.8.0" />
<PackageReference Include="HostLoom.Valkey" />
paket add HostLoom.Valkey --version 0.8.0
#r "nuget: HostLoom.Valkey, 0.8.0"
#:package HostLoom.Valkey@0.8.0
#addin nuget:?package=HostLoom.Valkey&version=0.8.0
#tool nuget:?package=HostLoom.Valkey&version=0.8.0
HostLoom.Valkey
Standalone Valkey caching and coordination locks over ValkeyDotNet 1.1.0.
Targets .NET 10. Applications continue to consume ICache and IDistributedLock from the
backend-neutral kernels. The Redis adapter remains separately available.
using System.Text.Json;
using HostLoom.Caching.DependencyInjection;
using HostLoom.Locking.DependencyInjection;
using HostLoom.Valkey;
using ValkeyDotNet;
builder.Services.AddHostLoomCaching(options => options.Namespace = "catalog-worker")
.UseValkey(options =>
{
options.Connection = new ValkeyClientOptions
{
Host = "localhost",
Port = 6379,
// Configure UseTls and ACL credentials for your deployment.
};
})
.UseSystemTextJson(new JsonSerializerOptions
{
TypeInfoResolver = CatalogJsonContext.Default,
})
.AddHealthChecks();
builder.Services.AddHostLoomLocking(options => options.Namespace = "catalog-worker")
.UseValkey()
.AddHealthChecks();
CatalogJsonContext is an application-owned source-generated JsonSerializerContext containing
its cached types. A runnable example is in examples/HostLoom.Examples.ValkeyAot in the repository.
Both registrations share one lazily connected ValkeyConnection, owned by the container.
Configuration callbacks run in registration order; configure the endpoint once. Public constructors
also work without a container: create ValkeyConnection, then ValkeyCacheStore,
ValkeyLockProvider, and optionally ValkeyCacheInvalidationChannel. Stores and providers borrow
the connection; dispose channels before disposing the connection. Connection settings are
snapshotted at construction. Command recovery reuses the configured TLS, ACL and database settings.
A standalone ServiceCollection needs a DI container implementation to call BuildServiceProvider.
Cache behavior
- Binary payloads and fully prefixed keys pass through unchanged. The kernel owns serialization, key domains, L1, single-flight, failure metrics and fail-open behavior.
- Lua reads the value and remaining TTL together. Bulk reads pipeline these scripts in one call.
- Untagged writes use
SET PX; conditional writes useSET NX PX. Tagged writes atomically add memberships and extend tag expiry only when the value is written. Lua runtime errors do not roll back partial writes; reserved key domains must contain the expected value/index types. - Tag memberships are monotonic: rewriting under other tags can leave earlier memberships. Tag removal is best-effort across concurrent writers, as in the Redis adapter.
- Pipeline server errors are checked individually and surfaced as
CacheStoreException.
Invalidation
Auto uses explicit Pub/Sub only. Tracking and Broadcast are rejected, since server-assisted
tracking and keyspace notification handling are not implemented. Changes made outside HostLoom
are observed through expiry. The probe describes this explicit-channel fallback.
The dedicated subscriber starts on the first subscription. StartAsync(token) can be used to wait
for its first server acknowledgement before beginning work. The channel is
{namespace}:cache:invalidate:db:{database} because Valkey Pub/Sub ignores logical database
selection. Messages use a bounded versioned JSON format, separate from the Redis adapter's wire
format; mixed Redis/Valkey adapters do not share invalidation messages.
Recovery uses exponential backoff from 100 ms to 30 seconds. Pub/Sub cannot replay messages lost
during a disconnection, so a re-established subscription hands CacheInvalidation.Flush to its
subscribers when Caching:Invalidation:FlushLocalOnReconnect is set (the default) and the cache
clears its in-process tier. Queue overflow drops incoming messages, and with the flush disabled a
disconnection loses them too; in either case L1 expiry bounds staleness; choose a suitable
CacheEntryOptions.LocalExpiration. No stronger consistency is promised. A published flush is a
fourth array element on the wire; an instance on an earlier package version counts it as
malformed. Handler exceptions do not stop other handlers. Handlers must not block.
The HostLoom.Valkey meter records invalidation failures, queue drops, malformed messages, and
handler failures; recovery also records the kernel's resubscription counter. Warnings are limited
to one per channel per 30 seconds. ValkeyDotNet connection-owner telemetry is opt-in through
EnableTelemetry. Neither adapter warnings nor probe text include credentials or payloads.
Lock behavior
Acquisition is SET key owner NX PX lease. Lua release and extension compare the owner before
DEL or PEXPIRE. Positive durations round up to milliseconds. Contention and owner mismatch
return false; backend failures become LockProviderException; caller cancellation propagates.
Command, pipeline, and script transport failures are never automatically replayed. A lost reply
may mean the operation executed; an unconfirmed acquisition is reported as failure and its lease
expires. The next independent operation can reconnect. Script-cache recovery retries only a
received NOSCRIPT response.
These are coordination leases on one primary, without fencing or consensus guarantees. A primary failover can lose a lease. Database constraints, transactions, or idempotency own persisted-state correctness. Cluster routing, Sentinel, replica reads, tracking and sharded invalidation are outside this adapter's current scope.
Options and verification
| Option | Default |
|---|---|
Connection |
ValkeyDotNet standalone settings, localhost:6379, RESP3 |
CommandTimeout |
5 seconds per command, script, or pipeline including connection acquisition |
HealthTimeout |
2 seconds per PING |
FailFast |
true; startup PING failure prevents host startup |
InvalidationQueueCapacity |
1,000 messages |
EnableTelemetry |
false |
FailFast=false permits startup while unavailable; later independent operations reconnect and
readiness reports backend health. It does not turn lock failures into successful acquisition.
docker compose up -d --wait valkey
HOSTLOOM_REQUIRE_VALKEY=1 dotnet test --project tests/HostLoom.IntegrationTests/HostLoom.IntegrationTests.csproj -c Release -- --filter-class '*Valkey*'
dotnet publish examples/HostLoom.Examples.ValkeyAot -c Release -r linux-x64 -o artifacts/valkey-aot
artifacts/valkey-aot/HostLoom.Examples.ValkeyAot
Tests and the sample default to localhost:16379; override HOSTLOOM_VALKEY_PORT for another local
port. Use your platform's RID for Native AOT (for example osx-arm64). The sample verifies a
source-generated serialized L2 round trip, leases and explicit invalidation against a real server.
HOSTLOOM_REQUIRE_VALKEY=1 or HOSTLOOM_REQUIRE_BROKERS=1 makes an absent listener fail tests.
Validation on 2026-09-06: 44 shared conformance cases and eight adapter cases passed on Valkey 9.1.2; the eight adapter cases also passed on 8.1.10 and 7.2.14. Binary cache and lease cases cover RESP2 and RESP3; shared conformance and invalidation use RESP3. Twelve deterministic adapter tests cover configuration, DI, error mapping, invalidation encoding, lifecycle, startup policy and non-replay after ambiguous lock writes. Source and package-only Native AOT consumers passed on macOS arm64. Those initial live runs used disposable Linux arm64 containers without TLS or persistence. TLS/ACL and restart coverage is provided separately below.
TLS/ACL and restart checks
just test-valkey-deployment builds Release and runs seven opt-in deployment cases against its own
TLS-only container. Docker and OpenSSL are required on Linux or macOS; first cache the image with
docker pull valkey/valkey:9.1. Use uv run --locked python scripts/test-valkey-deployment.py --no-build --image valkey/valkey:8.1 to test another cached image (7.2 is also accepted).
The temporary certificate authority is trusted only by the test clients. Certificate name and chain validation remain enabled. A restricted ACL user exercises cache and lease scripts, expiry, bulk reads and Pub/Sub; invalid trust, hostnames, credentials, keys, commands and channels are rejected. Restart cases reuse the same connection and subscriber, verify TLS/ACL/database settings on recovery, reload scripts, observe L1 expiry and lost leases, and preserve a replacement owner's lock. The runner removes only its owned container and temporary credentials/certificates.
The normal suite skips these cases without a fixture. The release workflow runs them separately as a required step. This covers server-authenticated TLS with ACL passwords and stop/start of one nonpersistent primary; mutual TLS, replica failover and cluster semantics remain unverified.
Deployment validation on 2026-09-06 passed all seven cases on each of valkey/valkey:9.1,
valkey/valkey:8.1, and valkey/valkey:7.2 (21 executions, no failures or skips), using .NET 10
on macOS arm64 and Linux arm64 server containers. The complete solution gate passed 890 cases;
the seven opt-in deployment cases were skipped there and verified by the separate runner above.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- HostLoom.Caching.DependencyInjection (>= 0.8.0)
- HostLoom.Locking.DependencyInjection (>= 0.8.0)
- ValkeyDotNet (>= 1.1.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.17.0 | 0 | 10/25/2026 |
| 0.16.1 | 47 | 10/22/2026 |
| 0.16.0 | 85 | 10/14/2026 |
| 0.15.1 | 90 | 10/12/2026 |
| 0.15.0 | 93 | 10/4/2026 |
| 0.14.0 | 93 | 10/4/2026 |
| 0.13.0 | 95 | 9/28/2026 |
| 0.12.0 | 96 | 9/27/2026 |
| 0.11.0 | 93 | 9/25/2026 |
| 0.10.0 | 95 | 9/22/2026 |
| 0.9.0 | 100 | 9/22/2026 |
| 0.8.0 | 102 | 9/19/2026 |
| 0.7.0 | 113 | 9/17/2026 |
| 0.6.0 | 117 | 9/6/2026 |