Merge pull request #6207 from elsa-workflows/bug/6193

Improve variable parsing with error handling and logging
This commit is contained in:
Sipke Schoorstra 2024-12-12 23:10:30 +01:00 committed by GitHub
commit cc75bb65ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 4 deletions

View file

@ -4,6 +4,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
using Elsa.Expressions.Helpers;
using Elsa.Expressions.Models;
using Elsa.Workflows;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Serialization.Converters;
@ -62,6 +63,19 @@ public static class VariableExtensions
variable.StorageDriverType = storageDriverType;
return variable;
}
public static void Set(this Variable variable, ActivityExecutionContext context, object? value)
{
// Validate type compatibility.
if (!variable.TryParseValue(value, out var parsedValue))
{
var variableType = variable.GetVariableType();
throw new InvalidCastException($"The value '{value}' is not compatible with the variable '{variable.Name}' of type '{variableType.FullName}'.");
}
// Set the value.
((MemoryBlockReference)variable).Set(context, parsedValue);
}
/// <summary>
/// Converts the specified value into a type that is compatible with the variable.
@ -73,6 +87,24 @@ public static class VariableExtensions
var converterOptions = new ObjectConverterOptions(SerializerOptions);
return genericType == null ? value : value?.ConvertTo(genericType, converterOptions);
}
/// <summary>
/// Converts the specified value into a type that is compatible with the variable.
/// </summary>
[RequiresUnreferencedCode("Calls System.Text.Json.JsonSerializer.Serialize<TValue>(TValue, JsonSerializerOptions)")]
public static bool TryParseValue(this Variable variable, object? value, out object? parsedValue)
{
try
{
parsedValue = variable.ParseValue(value);
return true;
}
catch
{
parsedValue = null;
return false;
}
}
/// <summary>
/// Return the type of the variable.

View file

@ -1,17 +1,19 @@
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Workflows.Memory;
using Microsoft.Extensions.Logging;
namespace Elsa.Workflows;
/// <inheritdoc />
public class VariablePersistenceManager(IStorageDriverManager storageDriverManager) : IVariablePersistenceManager
public class VariablePersistenceManager(IStorageDriverManager storageDriverManager, ILogger<VariablePersistenceManager> logger) : IVariablePersistenceManager
{
/// <inheritdoc />
public async Task LoadVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable<string>? excludeTags = default)
public async Task LoadVariablesAsync(WorkflowExecutionContext workflowExecutionContext, IEnumerable<string>? excludeTags = null)
{
var cancellationToken = workflowExecutionContext.CancellationToken;
var contexts = workflowExecutionContext.ActivityExecutionContexts.ToList();
var excludeTagsList = excludeTags?.ToList();
foreach (var context in contexts)
{
@ -34,15 +36,21 @@ public class VariablePersistenceManager(IStorageDriverManager storageDriverManag
if (driver == null)
continue;
if (excludeTags != null && driver.Tags.Any(excludeTags!.Contains))
if (excludeTagsList != null && driver.Tags.Any(excludeTagsList.Contains))
continue;
var id = GetStateId(variable);
var value = await driver.ReadAsync(id, storageDriverContext);
if (value == null) continue;
var parsedValue = variable.ParseValue(value);
register.Declare(variable);
if (!variable.TryParseValue(value, out var parsedValue))
{
logger.LogWarning("Failed to parse value for variable {VariableId} of type {VariableType} with value {Value}", variable.Id, variable.GetVariableType().FullName, value);
continue;
}
variable.Set(register, parsedValue);
}
}