feat(inbound-api): machine-readable error codes per spec (incl. SITE_UNREACHABLE) + 415 for non-JSON bodies
Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -384,7 +384,7 @@ public class InboundScriptExecutor
|
||||
// Fast-fail only when the CURRENT script text is the one already known bad.
|
||||
if (_knownBadMethods.TryGetValue(method.Name, out var badScript)
|
||||
&& string.Equals(badScript, method.Script, StringComparison.Ordinal))
|
||||
return new InboundScriptResult(false, null, "Script compilation failed for this method");
|
||||
return new InboundScriptResult(false, null, "Script compilation failed for this method", "SCRIPT_COMPILE_FAILED");
|
||||
|
||||
// Lazy compile (handles methods created after startup, and stale/known-bad
|
||||
// recompiles). Compile outside the cache so a failed compile is not stored,
|
||||
@@ -396,7 +396,7 @@ public class InboundScriptExecutor
|
||||
// Routed through TryRecordBadMethod so the
|
||||
// cache is bounded under a flood of unique method names.
|
||||
TryRecordBadMethod(method.Name, method.Script ?? string.Empty);
|
||||
return new InboundScriptResult(false, null, "Script compilation failed for this method");
|
||||
return new InboundScriptResult(false, null, "Script compilation failed for this method", "SCRIPT_COMPILE_FAILED");
|
||||
}
|
||||
|
||||
_knownBadMethods.TryRemove(method.Name, out _);
|
||||
@@ -448,17 +448,25 @@ public class InboundScriptExecutor
|
||||
if (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogWarning("Script execution timed out for method {Method}", method.Name);
|
||||
return new InboundScriptResult(false, null, "Script execution timed out");
|
||||
return new InboundScriptResult(false, null, "Script execution timed out", "TIMEOUT");
|
||||
}
|
||||
|
||||
_logger.LogDebug("Inbound API request for method {Method} cancelled by client", method.Name);
|
||||
return new InboundScriptResult(false, null, "Request cancelled by client");
|
||||
}
|
||||
catch (SiteUnreachableException)
|
||||
{
|
||||
// C3: a routed Route.To(...).Call(...) reached a site that could not be
|
||||
// contacted. Surface the machine-readable SITE_UNREACHABLE code (spec
|
||||
// Component-InboundAPI failure body) instead of the generic SCRIPT_ERROR.
|
||||
_logger.LogWarning("Routed site unreachable for method {Method}", method.Name);
|
||||
return new InboundScriptResult(false, null, "Site unreachable", "SITE_UNREACHABLE");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Script execution failed for method {Method}", method.Name);
|
||||
// Safe error message, no internal details
|
||||
return new InboundScriptResult(false, null, "Internal script error");
|
||||
return new InboundScriptResult(false, null, "Internal script error", "SCRIPT_ERROR");
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -537,7 +545,17 @@ public class InboundScriptContext
|
||||
/// <summary>
|
||||
/// Result of executing an inbound API script.
|
||||
/// </summary>
|
||||
/// <param name="Success">Whether the script executed successfully.</param>
|
||||
/// <param name="ResultJson">The serialized script return value on success; null otherwise.</param>
|
||||
/// <param name="ErrorMessage">A sanitized, caller-safe error message on failure; null on success.</param>
|
||||
/// <param name="ErrorCode">
|
||||
/// C3: an additive, machine-readable error code the endpoint surfaces in the failure
|
||||
/// body's <c>code</c> field (e.g. <c>TIMEOUT</c>, <c>SITE_UNREACHABLE</c>,
|
||||
/// <c>SCRIPT_COMPILE_FAILED</c>, <c>SCRIPT_ERROR</c>). Null when the executor does not
|
||||
/// classify the failure; the endpoint then falls back to <c>SCRIPT_ERROR</c>.
|
||||
/// </param>
|
||||
public record InboundScriptResult(
|
||||
bool Success,
|
||||
string? ResultJson,
|
||||
string? ErrorMessage);
|
||||
string? ErrorMessage,
|
||||
string? ErrorCode = null);
|
||||
|
||||
Reference in New Issue
Block a user