Portal Community

What Is Persisted

DataField in Process_SuspendedExecutions
All node outputs collected so farExecutionMemory (JSON)
Global variables set by SetVariable nodesInside ExecutionMemory
Which node is suspendedSuspendedNodeId
The correlation tokenExecutionResId
The full process definitionReferenced by ProcessId + ThreadId — loaded fresh on resume
Timeout configurationExpiresAt, TimeoutBehavior, EscalationActorId

Serialisation

// ExecutionMemorySerializer.cs
public string Serialize(ExecutionMemory memory)
{
    // Uses System.Text.Json with custom converters for object type preservation
    var options = new JsonSerializerOptions
    {
        WriteIndented = false,
        Converters    = { new ExecutionMemoryTypeConverter() }
    };
    return JsonSerializer.Serialize(memory, options);
}

public ExecutionMemory Deserialize(string json)
{
    return JsonSerializer.Deserialize<ExecutionMemory>(json, _deserializeOptions)
           ?? throw new InvalidOperationException("Failed to deserialise ExecutionMemory");
}

Object Type Preservation

The nodeOutputs dictionary stores object values. The serialiser uses type discriminators to preserve the original .NET type, so GetNodeOutput<T> returns the correct strongly-typed object after deserialisation:

// Serialised as:
{
  "nodeOutputs": {
    "httpRequest1": {
      "$type": "BizFirst.Ai.ExecutionNodes.Http.HttpRequestOutput",
      "statusCode": 200,
      "body": "{ \"id\": 123 }"
    }
  }
}
Non-serialisable objects: Node output objects must be JSON-serialisable. If an executor returns an output containing non-serialisable types (e.g., raw streams, delegates), suspension will fail with a SerializationException. Use DTOs or primitives in output types.

Storage Size Limits

The ExecutionMemory column is NVARCHAR(MAX) — no hard SQL limit. However, very large memories (e.g., workflows that process large documents and store them in node outputs) can cause performance issues. Recommendations: