diff --git a/src/Azos.Sky.Server/Fabric/Server/FiberMemory.cs b/src/Azos.Sky.Server/Fabric/Server/FiberMemory.cs
index 805df68b4..5981f254a 100644
--- a/src/Azos.Sky.Server/Fabric/Server/FiberMemory.cs
+++ b/src/Azos.Sky.Server/Fabric/Server/FiberMemory.cs
@@ -162,10 +162,12 @@ public void Crash(Exception error)
/// Creates s snapshot of data changes which can be commited back into
/// using .
/// This only succeeds if the is
- /// otherwise Delta can not be obtained
+ /// otherwise Delta can not be obtained.
+ /// Performs validation and throws if slots are in invalid state
///
- public FiberMemoryDelta MakeDeltaSnapshot(FiberStep? nextStep, FiberState currentState)
+ public FiberMemoryDelta MakeDeltaSnapshot(IApplication app, FiberStep? nextStep, FiberState currentState)
{
+ app.NonNull(nameof(app));
(m_Status == MemoryStatus.LockedForCaller).IsTrue("Delta obtained for LockedForCaller memory");
var result = new FiberMemoryDelta
@@ -188,7 +190,24 @@ public FiberMemoryDelta MakeDeltaSnapshot(FiberStep? nextStep, FiberState curren
result.NextSliceInterval = nxt.NextSliceInterval;
result.ExitCode = nxt.ExitCode;
result.Result = nxt.Result;
- result.Changes = currentState.SlotChanges.ToArray();
+
+ var changes = currentState.SlotChanges.ToArray();
+ foreach(var change in changes)
+ {
+ app.InjectInto(change.Value);
+
+ var error = change.Value.Validate();
+ if (error != null)
+ {
+ throw new FabricStateValidationException(
+ "Validation error for state slot `{0}.{1}` validation failed: {2}".Args(
+ currentState.GetType().DisplayNameWithExpandedGenericArgs(),
+ change.Value.GetType().DisplayNameWithExpandedGenericArgs(),
+ error.ToMessageWithType()), error);
+ }
+ }
+
+ result.Changes = changes;
}
return result;
diff --git a/src/Azos.Sky.Server/Fabric/Server/FiberProcessorDaemon.cs b/src/Azos.Sky.Server/Fabric/Server/FiberProcessorDaemon.cs
index e071a2602..ae77eea16 100644
--- a/src/Azos.Sky.Server/Fabric/Server/FiberProcessorDaemon.cs
+++ b/src/Azos.Sky.Server/Fabric/Server/FiberProcessorDaemon.cs
@@ -403,7 +403,7 @@ private async Task processFiberQuantumUnsafe(ShardMapping shard, Guid logRel)
var (wasHandled, nextStep, fiberState) = await processFiberQuantumCore(memory).ConfigureAwait(false);//<===================== FIBER SLICE gets called
if (!wasHandled) return;//get out asap
- var delta = memory.MakeDeltaSnapshot(nextStep, fiberState);
+ var delta = memory.MakeDeltaSnapshot(App, nextStep, fiberState);//this can throw on invalid state
var saveErrorCount = 0;
while(true)
diff --git a/src/Azos.Sky/Fabric/Exceptions.cs b/src/Azos.Sky/Fabric/Exceptions.cs
index f183f4405..23c8c0007 100644
--- a/src/Azos.Sky/Fabric/Exceptions.cs
+++ b/src/Azos.Sky/Fabric/Exceptions.cs
@@ -48,6 +48,18 @@ public FabricProcessorException(string message, Exception inner) : base(message,
protected FabricProcessorException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
+ ///
+ /// Thrown to indicate state validation error
+ ///
+ [Serializable]
+ public class FabricStateValidationException : FabricProcessorException
+ {
+ public FabricStateValidationException() : base() { }
+ public FabricStateValidationException(string message) : base(message) { }
+ public FabricStateValidationException(string message, Exception inner) : base(message, inner) { }
+ protected FabricStateValidationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
+ }
+
///
/// Thrown to indicate errors when fibers are not derived from
///
diff --git a/src/Azos.Sky/Fabric/FiberStep.cs b/src/Azos.Sky/Fabric/FiberStep.cs
index fc844d4a8..5e954c992 100644
--- a/src/Azos.Sky/Fabric/FiberStep.cs
+++ b/src/Azos.Sky/Fabric/FiberStep.cs
@@ -21,6 +21,9 @@ public struct FiberStep
{
public const string CONVENTION_STEP_METHOD_NAME_PREFIX = "Step_";
+ public static readonly Atom START = Atom.Encode("Start");
+
+
public static readonly FiberStep ZERO = new FiberStep();
private static readonly FiniteSetLookup<(Type t, Atom s), MethodInfo> STEP_MI_CACHE =
diff --git a/src/testing/Azos.Tests.Unit/Fabric/MemoryDeltaFormatTests.cs b/src/testing/Azos.Tests.Unit/Fabric/MemoryDeltaFormatTests.cs
index d585165d5..c2ced90ea 100644
--- a/src/testing/Azos.Tests.Unit/Fabric/MemoryDeltaFormatTests.cs
+++ b/src/testing/Azos.Tests.Unit/Fabric/MemoryDeltaFormatTests.cs
@@ -9,7 +9,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-
+using Azos.Apps;
using Azos.Data;
using Azos.Scripting;
using Azos.Serialization.Bix;
@@ -73,7 +73,7 @@ public void Test01_Roundtrip_NextStep_NoResult()
gotState.AccountNumber = 223322;//mutate state <====================
Aver.IsTrue(got.HasDelta(gotState));
- var delta = got.MakeDeltaSnapshot(FiberStep.ContinueImmediately(Atom.Encode("step2")), gotState);
+ var delta = got.MakeDeltaSnapshot(NOPApplication.Instance, FiberStep.ContinueImmediately(Atom.Encode("step2")), gotState);
Aver.AreEqual("step2", delta.NextStep.Value);
Aver.AreEqual(new TimeSpan(0), delta.NextSliceInterval);
@@ -156,7 +156,7 @@ public void Test02_Roundtrip_FinalStep_WithResult()
String1 = "Dallas"
};
- var delta = got.MakeDeltaSnapshot(FiberStep.FinishWithResult(123, result), gotState);
+ var delta = got.MakeDeltaSnapshot(NOPApplication.Instance, FiberStep.FinishWithResult(123, result), gotState);
Aver.IsTrue(delta.NextStep.IsZero);
Aver.AreEqual(new TimeSpan(0), delta.NextSliceInterval);
@@ -241,7 +241,7 @@ public void Test03_Roundtrip_FinalStep_NoResult()
Aver.IsTrue(got.HasDelta(gotState));
- var delta = got.MakeDeltaSnapshot(FiberStep.Finish(321), gotState);
+ var delta = got.MakeDeltaSnapshot(NOPApplication.Instance, FiberStep.Finish(321), gotState);
Aver.IsTrue(delta.NextStep.IsZero);
Aver.AreEqual(new TimeSpan(0), delta.NextSliceInterval);
@@ -323,7 +323,7 @@ public void Test04_Roundtrip_Crash()
Aver.IsFalse(got.HasDelta(gotState));
got.Crash(new FabricException("Problem X"));//crash memory
- var delta = got.MakeDeltaSnapshot(FiberStep.Finish(321), gotState);
+ var delta = got.MakeDeltaSnapshot(NOPApplication.Instance, FiberStep.Finish(321), gotState);
Aver.IsTrue(delta.NextStep.IsZero);
Aver.AreEqual(new TimeSpan(0), delta.NextSliceInterval);