Skip to content

Commit

Permalink
Address misleading documentation
Browse files Browse the repository at this point in the history
Add remarks for the evaluation methods of the 'LoadedLuaScript' abstraction which explicitly state that if a SHA-1 hash, of a previously loaded Lua script, was not found in the server cache - it will be reloaded with 'SCRIPT LOAD'. The first evaluation of the reloaded script will be carried out by the 'EVAL' command, but any subsequent evaluations will use 'EVALSHA'.
  • Loading branch information
SonnyRR committed May 3, 2023
1 parent 571d832 commit 08d7db4
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 11 deletions.
4 changes: 2 additions & 2 deletions docs/Scripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ Any object that exposes field or property members with the same name as @-prefix
- RedisKey
- RedisValue

StackExchange.Redis handles Lua script caching internally. It automatically transmits the Lua script to redis on the first call to 'ScriptEvaluate'. For further calls of the same script only the hash with [`EVALSHA`](https://redis.io/commands/evalsha) is used.
StackExchange.Redis handles Lua script caching internally. It automatically transmits the Lua script to redis on the first call to 'ScriptEvaluate'. For further calls of the same script [`EVAL`](https://redis.io/commands/eval) is used instead of [`EVALSHA`](https://redis.io/commands/evalsha), due to resiliency concerns.

For more control of the Lua script transmission to redis, `LuaScript` objects can be converted into `LoadedLuaScript`s via `LuaScript.Load(IServer)`.
`LoadedLuaScripts` are evaluated with the [`EVALSHA`](https://redis.io/commands/evalsha), and referred to by hash.
`LoadedLuaScripts` are evaluated with the [`EVAL`](https://redis.io/commands/eval) command instead of [`EVALSHA`](https://redis.io/commands/evalsha), due to resiliency concerns.

An example use of `LoadedLuaScript`:

Expand Down
30 changes: 21 additions & 9 deletions src/StackExchange.Redis/LuaScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,16 @@ public Task<RedisResult> EvaluateAsync(IDatabaseAsync db, object? ps = null, Red

/// <summary>
/// <para>
/// Loads this LuaScript into the given IServer so it can be run with it's SHA1 hash, instead of
/// using the implicit SHA1 hash that's calculated after the script is sent to the server for the first time.
/// Loads this LuaScript into the given IServer. Due to resiliency concerns, the LoadedLuaScript
/// does not evaluate the script by it's SHA-1 hash anymore.
/// </para>
/// <para>Note: the FireAndForget command flag cannot be set.</para>
/// </summary>
/// <param name="server">The server to load the script on.</param>
/// <param name="flags">The command flags to use.</param>
/// <remarks>
/// Previously, this method was intended provide scripts, that can be evaluated by their SHA-1 hashes.
/// </remarks>
public LoadedLuaScript Load(IServer server, CommandFlags flags = CommandFlags.None)
{
if ((flags & CommandFlags.FireAndForget) != 0)
Expand All @@ -186,13 +189,16 @@ public LoadedLuaScript Load(IServer server, CommandFlags flags = CommandFlags.No

/// <summary>
/// <para>
/// Loads this LuaScript into the given IServer so it can be run with it's SHA1 hash, instead of
/// using the implicit SHA1 hash that's calculated after the script is sent to the server for the first time.
/// Loads this LuaScript into the given IServer. Due to resiliency concerns, the LoadedLuaScript
/// does not evaluate the script by it's SHA-1 hash anymore.
/// </para>
/// <para>Note: the FireAndForget command flag cannot be set</para>
/// </summary>
/// <param name="server">The server to load the script on.</param>
/// <param name="flags">The command flags to use.</param>
/// <remarks>
/// Previously, this method was intended provide scripts, that can be evaluated by their SHA-1 hashes.
/// </remarks>
public async Task<LoadedLuaScript> LoadAsync(IServer server, CommandFlags flags = CommandFlags.None)
{
if ((flags & CommandFlags.FireAndForget) != 0)
Expand Down Expand Up @@ -239,7 +245,7 @@ public sealed class LoadedLuaScript

/// <summary>
/// <para>The SHA1 hash of ExecutableScript.</para>
/// <para>This is sent to Redis instead of ExecutableScript during Evaluate and EvaluateAsync calls.</para>
/// <para>This is not sent to Redis, instead ExecutableScript is used during Evaluate and EvaluateAsync calls.</para>
/// </summary>
/// <remarks>Be aware that using hash directly is not resilient to Redis server restarts.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
Expand All @@ -257,14 +263,17 @@ internal LoadedLuaScript(LuaScript original, byte[] hash)
/// <summary>
/// <para>Evaluates this LoadedLuaScript against the given database, extracting parameters for the passed in object if any.</para>
/// <para>
/// This method sends the SHA1 hash of the ExecutableScript instead of the script itself.
/// If the script has not been loaded into the passed Redis instance, it will fail.
/// This method evaluates the script itself and does not send the SHA-1 hash, generated by the server when loaded initially, in order to execute it.
/// If the script has not been loaded into the passed Redis instance, it will not fail.
/// </para>
/// </summary>
/// <param name="db">The redis database to evaluate against.</param>
/// <param name="ps">The parameter object to use.</param>
/// <param name="withKeyPrefix">The key prefix to use, if any.</param>
/// <param name="flags">The command flags to use.</param>
/// <remarks>
/// Previously, this method evaluated the script by it's SHA-1 hash.
/// </remarks>
public RedisResult Evaluate(IDatabase db, object? ps = null, RedisKey? withKeyPrefix = null, CommandFlags flags = CommandFlags.None)
{
Original.ExtractParameters(ps, withKeyPrefix, out RedisKey[]? keys, out RedisValue[]? args);
Expand All @@ -275,14 +284,17 @@ public RedisResult Evaluate(IDatabase db, object? ps = null, RedisKey? withKeyPr
/// <summary>
/// <para>Evaluates this LoadedLuaScript against the given database, extracting parameters for the passed in object if any.</para>
/// <para>
/// This method sends the SHA1 hash of the ExecutableScript instead of the script itself.
/// If the script has not been loaded into the passed Redis instance, it will fail.
/// This method evaluates the script itself and does not send the SHA-1 hash, generated by the server when loaded initially, in order to execute it.
/// If the script has not been loaded into the passed Redis instance, it will not fail.
/// </para>
/// </summary>
/// <param name="db">The redis database to evaluate against.</param>
/// <param name="ps">The parameter object to use.</param>
/// <param name="withKeyPrefix">The key prefix to use, if any.</param>
/// <param name="flags">The command flags to use.</param>
/// <remarks>
/// Previously, this method evaluated the script by it's SHA-1 hash.
/// </remarks>
public Task<RedisResult> EvaluateAsync(IDatabaseAsync db, object? ps = null, RedisKey? withKeyPrefix = null, CommandFlags flags = CommandFlags.None)
{
Original.ExtractParameters(ps, withKeyPrefix, out RedisKey[]? keys, out RedisValue[]? args);
Expand Down

0 comments on commit 08d7db4

Please sign in to comment.