Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 43 additions & 2 deletions Engine/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemb
// Algorithm runtime error:
if (algorithm.RunTimeError != null)
{
HandleAlgorithmError(job, algorithm.RunTimeError);
HandleAlgorithmError(job, algorithm, algorithm.RunTimeError);
}

// notify the LEAN manager that the algorithm has finished
Expand Down Expand Up @@ -477,13 +477,18 @@ public void Run(AlgorithmNodePacket job, AlgorithmManager manager, string assemb
/// Handle an error in the algorithm.Run method.
/// </summary>
/// <param name="job">Job we're processing</param>
/// <param name="algorithm">The algorithm instance that raised the error</param>
/// <param name="err">Error from algorithm stack</param>
private void HandleAlgorithmError(AlgorithmNodePacket job, Exception err)
private void HandleAlgorithmError(AlgorithmNodePacket job, IAlgorithm algorithm, Exception err)
{
AlgorithmHandlers.DataFeed?.Exit();
if (AlgorithmHandlers.Results != null)
{
var message = $"Runtime Error: {err.Message}";
if (TryGetOutOfMemoryErrorDetails(job, algorithm, err, out var outOfMemoryDetails))
{
message += outOfMemoryDetails;
}
Log.Trace("Engine.Run(): Sending runtime error to user...");
AlgorithmHandlers.Results.LogMessage(message);

Expand All @@ -495,6 +500,42 @@ private void HandleAlgorithmError(AlgorithmNodePacket job, Exception err)
}
}

/// <summary>
/// Checks whether the given exception is an <see cref="OutOfMemoryException"/>,
/// producing details about the algorithm state and the common causes to be appended to the runtime error message
/// </summary>
/// <param name="job">Job we're processing</param>
/// <param name="algorithm">The algorithm instance that raised the error</param>
/// <param name="err">Error from algorithm stack</param>
/// <param name="details">The out of memory details, null if the error is not an out of memory error</param>
/// <returns>True if the error is an out of memory error</returns>
private static bool TryGetOutOfMemoryErrorDetails(AlgorithmNodePacket job, IAlgorithm algorithm, Exception err, out string details)
{
details = null;
if (err is not OutOfMemoryException)
{
return false;
}

details = Invariant($" The algorithm exhausted its {job.RamAllocation}MB of RAM.");
if (algorithm != null)
{
try
{
details += Invariant($" State: {algorithm.Securities.Count} securities, {algorithm.SubscriptionManager.Count} subscriptions, {algorithm.UniverseManager.Count} universes.");
}
catch (Exception stateException)
{
// best effort: don't let diagnostics collection replace the original error
Log.Error(stateException);
}
}
details += " Common causes: universe/subscription count too high for the allocated RAM; unbounded buffers such as rolling windows," +
" consolidators or accumulated history results. Fixes: reduce universe size/subscriptions, use coarser resolutions," +
" or bound buffers.";
return true;
}

/// <summary>
/// Load the history provider from the Composer
/// </summary>
Expand Down
Loading