Skip to content

Version-gate LMOVE for Redis 6.0.x compatibility (Azure Cache for Redis)#176

Merged
niemyjski merged 1 commit into
mainfrom
fix/174-lmove-version-gate
Jul 7, 2026
Merged

Version-gate LMOVE for Redis 6.0.x compatibility (Azure Cache for Redis)#176
niemyjski merged 1 commit into
mainfrom
fix/174-lmove-version-gate

Conversation

@niemyjski

Copy link
Copy Markdown
Member

Fixes #174

Root cause

Scripts/DequeueId.lua calls LMOVE, which requires Redis 6.2+. PR #164 replaced the deprecated RPOPLPUSH with LMOVE without a version gate. Azure Cache for Redis is pinned at 6.0.14, so every dequeue throws:

ERR Error running script (...): Unknown Redis command called from Lua script

Confirmed directly against a live Azure Cache for Redis instance (server reports v6.0.14).

Fix

  • Added RedisCapabilities.SupportsLMove (min version 6.2.0), mirroring the existing SupportsMsetex version-gate pattern.
  • RedisQueue.LoadScriptsAsync now selects the LMOVE script on 6.2+ servers and falls back to a restored RPOPLPUSH variant (DequeueId.Rpoplpush.lua) on older servers.
  • The capability cache is invalidated on reconnect (ConnectionMultiplexerOnConnectionRestored), same as SupportsMsetex.

Audit: fallback script correctness

DequeueId.Rpoplpush.lua was verified against the exact pre-#164 script (git show f77ee64^:src/Foundatio.Redis/Scripts/DequeueId.lua). The Lua logic is byte-for-byte identical; the only difference is a UTF-8 BOM and trailing newline in the old file, both of which are inconsequential (EmbeddedResourceLoader uses StreamReader, which strips a BOM by default, and other scripts in the repo already have mixed BOM/no-BOM and trailing-newline conventions).

LMOVE src dst RIGHT LEFT is functionally identical to RPOPLPUSH src dst, so behavior is unchanged regardless of which variant is selected.

Verification

  • Build: clean, 0 warnings / 0 errors.
  • Local Redis 6.0.20 (matches Azure's 6.0.14): full RedisQueueTests suite — 48 passed, 0 failed, 5 skipped, no LMOVE errors. Since 6.0 has no LMOVE, this confirms the RPOPLPUSH fallback is correctly selected and functioning.
  • Local Redis 7.4.9: dequeue tests pass, confirming the LMOVE path is still used (and preferred) on modern servers.

Scope

This PR only addresses the LMOVE incompatibility from #174. It does not touch the separately-reported cache expiration test flakiness (which is a test-latency issue against high-RTT connections, unrelated to Redis version support).

DequeueId.lua uses LMOVE (Redis 6.2+), which Azure Cache for Redis
(pinned at 6.0.14) does not support, causing 'Unknown Redis command
called from Lua script' errors on dequeue.

Add RedisCapabilities.SupportsLMove (min version 6.2.0) and have
RedisQueue select between the LMOVE script and a restored RPOPLPUSH
fallback script at load time, invalidating the cached capability on
reconnect.

The RPOPLPUSH fallback script (DequeueId.Rpoplpush.lua) is the exact
script used prior to #164 (verified via 'git show f77ee64^:...'); the
Lua logic is byte-for-byte identical aside from an inconsequential
UTF-8 BOM/trailing newline, which EmbeddedResourceLoader strips via
StreamReader's default BOM detection.

Verified locally:
- Redis 6.0.20: full RedisQueueTests suite - 48 passed, 0 failed, 5 skipped, no LMOVE errors (RPOPLPUSH fallback confirmed selected)
- Redis 7.4.9: dequeue passes, confirming LMOVE path still used on modern servers
@niemyjski niemyjski self-assigned this Jul 7, 2026
@niemyjski niemyjski merged commit 0546a35 into main Jul 7, 2026
3 checks passed
@niemyjski niemyjski deleted the fix/174-lmove-version-gate branch July 7, 2026 20:03
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.

Lua Issues with 13.0.2 + S.E.Redis 3.x + Azure Cache

1 participant