feat(inbound-api): InvalidateMethod seam purging handler + known-bad — consumer entry point for the script-artifact invalidation contract (plan 05)
Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -110,14 +110,26 @@ public class InboundScriptExecutor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a compiled script handler for a method name.
|
||||
/// Drops the compiled handler AND any known-bad record for the method. The
|
||||
/// consumption seam for the script-artifact invalidation contract (bundle import,
|
||||
/// out-of-band updates, failover activation). Safe to call for unknown names.
|
||||
/// The per-request revision check in ExecuteAsync remains the correctness
|
||||
/// fallback when an invalidation is missed.
|
||||
/// </summary>
|
||||
/// <param name="methodName">The method name to remove.</param>
|
||||
public void RemoveHandler(string methodName)
|
||||
/// <param name="methodName">The method name to invalidate.</param>
|
||||
public void InvalidateMethod(string methodName)
|
||||
{
|
||||
_scriptHandlers.TryRemove(methodName, out _);
|
||||
_knownBadMethods.TryRemove(methodName, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a compiled script handler for a method name. Delegates to
|
||||
/// <see cref="InvalidateMethod"/> (public API preserved).
|
||||
/// </summary>
|
||||
/// <param name="methodName">The method name to remove.</param>
|
||||
public void RemoveHandler(string methodName) => InvalidateMethod(methodName);
|
||||
|
||||
/// <summary>
|
||||
/// Compiles and registers a single API method script. Returns <c>false</c> if the
|
||||
/// script is empty, fails Roslyn compilation, or violates the script trust model.
|
||||
|
||||
@@ -2651,7 +2651,7 @@ public class ManagementActor : ReceiveActor
|
||||
await repo.DeleteApiMethodAsync(cmd.ApiMethodId);
|
||||
await repo.SaveChangesAsync();
|
||||
if (method != null)
|
||||
sp.GetService<InboundAPI.InboundScriptExecutor>()?.RemoveHandler(method.Name);
|
||||
sp.GetService<InboundAPI.InboundScriptExecutor>()?.InvalidateMethod(method.Name);
|
||||
await AuditAsync(sp, user, "Delete", "ApiMethod", cmd.ApiMethodId.ToString(), method?.Name ?? cmd.ApiMethodId.ToString(), null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,4 +86,21 @@ public class InboundScriptExecutorStalenessTests
|
||||
Assert.True(r.Success);
|
||||
Assert.Contains("99", r.ResultJson);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvalidateMethod_DropsHandlerAndKnownBadRecord()
|
||||
{
|
||||
var good = new ApiMethod("inv", "return 5;") { Id = 5, TimeoutSeconds = 10 };
|
||||
Assert.True(_executor.CompileAndRegister(good));
|
||||
var broken = new ApiMethod("invbad", "%%%") { Id = 6, TimeoutSeconds = 10 };
|
||||
Assert.False(_executor.CompileAndRegister(broken));
|
||||
|
||||
_executor.InvalidateMethod("inv");
|
||||
_executor.InvalidateMethod("invbad");
|
||||
|
||||
Assert.Equal(0, _executor.KnownBadMethodCount);
|
||||
// After invalidation the method lazily recompiles from the row — still serves.
|
||||
var r = await Run(good);
|
||||
Assert.True(r.Success);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user