Skip to content

feat(binary): лимит памяти для ДвоичныеДанные из конфигурации (#1667)#1670

Open
johnnyshut wants to merge 3 commits into
EvilBeaver:developfrom
johnnyshut:fix/1667
Open

feat(binary): лимит памяти для ДвоичныеДанные из конфигурации (#1667)#1670
johnnyshut wants to merge 3 commits into
EvilBeaver:developfrom
johnnyshut:fix/1667

Conversation

@johnnyshut
Copy link
Copy Markdown
Contributor

@johnnyshut johnnyshut commented Apr 30, 2026

Зачем

Закрывает #1667: порог «держать двоичные данные в памяти до перехода на временный файл» больше не зашит константой только в коде — задаётся через конфигурацию.

Что сделали

  • Добавили ключ binaryData.inMemoryMaxBytes (целое число байт) в oscript.cfg и в состав настроек из OSCRIPT_CONFIG. Если ключ не задан или значение некорректно — используется 50 МБ (BinaryDataConfigurationDefaults.InMemoryMaxBytes).
  • Добавили IBinaryDataMemoryLimit и регистрацию в SetDefaultOptions (singleton на основе OneScriptCoreOptions).
  • Добавили BinaryDataRuntimeSettings: на время выполнения BslProcess.Run лимит попадает в AsyncLocal и используется BinaryDataContext и параметрless FileBackingStream(); вне процесса BSL остаётся значение по умолчанию.
  • Обновили FileBackingConstants.DEFAULT_MEMORY_LIMIT — тот же дефолт, что и в ScriptEngine.
  • Для CGI: WebRequestContext получает лимит из контейнера после сборки движка (до CreateProcess), т.к. запрос создаётся раньше старта BSL-процесса.

Как проверить

  • В oscript.cfg раскомментировать/задать, например: binaryData.inMemoryMaxBytes=1048576, убедиться, что поведение буферизации соответствует ожиданиям для больших потоков.
  • Сборка основных .NET-проектов: dotnet build src/oscript/oscript.csproj (как минимум).

Summary by CodeRabbit

  • New Features

    • Added configurable in-memory memory limit for binary data processing, replacing the hardcoded threshold
    • Added configuration option to tune when binary data switches from memory to temporary file storage
  • Bug Fixes

    • Fixed executor notification ordering during process startup and cleanup sequence
  • Chores

    • Added x64 platform build configuration support

Review Change Stack

Добавили ключ binaryData.inMemoryMaxBytes (байты) в oscript.cfg и переменную OSCRIPT_CONFIG.

Изменили OneScriptCoreOptions: разбор значения с проверкой и запасным значением по умолчанию (50 МБ).

Добавили BinaryDataConfigurationDefaults, IBinaryDataMemoryLimit и регистрацию в SetDefaultOptions.

Добавили BinaryDataRuntimeSettings (AsyncLocal): на время BslProcess.Run лимит берётся из DI; вне процесса — дефолт.

Изменили BinaryDataContext и конструктор FileBackingStream без параметров для использования эффективного лимита.

Изменили FileBackingConstants.DEFAULT_MEMORY_LIMIT — ссылка на общий дефолт из ScriptEngine.

Изменили CGI: WebRequestContext принимает лимит из сервисов до CreateProcess.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

This PR introduces configurable in-memory memory limits for binary data handling in OneScript by creating a new library with DI-backed configuration, updating binary components to use runtime settings, and integrating host applications. It also improves process executor lifecycle management and extends solution build configuration for x64 platform support.

Changes

Binary Data Memory Limit Configuration

Layer / File(s) Summary
Core Binary Data Library Types and Configuration
src/OneScript.BinaryData/IBinaryDataMemoryLimit.cs, src/OneScript.BinaryData/BinaryDataConfigurationDefaults.cs, src/OneScript.BinaryData/BinaryDataMemoryLimitConfiguration.cs, src/OneScript.BinaryData/BinaryDataRuntimeSettings.cs, src/OneScript.BinaryData/BinaryDataMemoryLimit.cs, src/OneScript.BinaryData/OneScript.BinaryData.csproj
New OneScript.BinaryData library defines IBinaryDataMemoryLimit contract, BinaryDataConfigurationDefaults with 50 MiB default, BinaryDataMemoryLimitConfiguration for config parsing/validation, BinaryDataRuntimeSettings for DI-based application and getter, and BinaryDataMemoryLimit implementation.
Integrating Configurable Limits into Binary Components
src/OneScript.StandardLibrary/Binary/FileBackingStream.cs, src/OneScript.StandardLibrary/Binary/BinaryDataContext.cs, src/OneScript.StandardLibrary/Binary/FileBackingConstants.cs, src/oscript/Web/WebRequestContext.cs, src/oscript/CgiBehavior.cs
FileBackingStream and BinaryDataContext use BinaryDataRuntimeSettings.GetEffectiveInMemoryMaxBytes() for runtime limits; FileBackingConstants delegates to BinaryDataConfigurationDefaults; WebRequestContext adds configurable constructor with validation; CgiBehavior passes runtime limit to WebRequestContext.
Dependency Injection Wiring and Runtime Initialization
src/OneScript.StandardLibrary/EngineBuilderExtensions.cs, src/ScriptEngine/Hosting/EngineBuilderExtensions.cs, src/ScriptEngine/ScriptingEngine.cs, src/TestApp/MainWindow.xaml.cs, src/oscript/ConsoleHostBuilder.cs, src/ScriptEngine/ScriptEngine.csproj
New RegisterBinaryDataMemoryLimitFromConfig() extension reads config and registers IBinaryDataMemoryLimit singleton; ScriptEngine DI registration creates limit from OneScriptCoreOptions; ScriptingEngine applies settings during construction; TestApp and ConsoleHostBuilder call registration method; ScriptEngine.csproj adds OneScript.BinaryData reference.
Solution and Build Configuration
src/1Script.sln
Adds OneScript.BinaryData project entry; introduces Debug|x64, LinuxDebug|x64, and Release|x64 platform configurations; updates ProjectConfigurationPlatforms mappings for all projects to support x64.

Process Executor Lifecycle Management

Layer / File(s) Summary
Executor Notification and Cleanup Reliability
src/ScriptEngine/BslProcess.cs
Run method tracks which executors successfully received BeforeProcessStart via startedExecutors list inside try block; moves BeforeProcessStart execution into try to allow partial startup failure handling; invokes AfterProcessExit in finally only for started executors in reverse order; uses nested finally to guarantee _isRunning reset to false even if AfterProcessExit throws.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • EvilBeaver

🐰 Binary bounds now bend to the config, dear friend,
No hardcoded walls where streams must end.
Process executors dance with safer grace,
Cleanup and reset find their place. 🔧✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding a memory limit configuration for binary data (ДвоичныеДанные) from configuration settings, which is reflected throughout the changeset with new configuration infrastructure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs (1)

20-24: ⚡ Quick win

Harden runtime settings against invalid DI-provided limits

PushFromServices currently trusts IBinaryDataMemoryLimit.MaxBytesInMemory. A custom host registration can pass invalid values and break downstream buffering behavior; sanitize here before storing to AsyncLocal.

💡 Suggested fix
         internal static void PushFromServices(IServiceContainer services)
         {
             var opts = services.TryResolve<IBinaryDataMemoryLimit>();
-            InMemoryMaxBytes.Value = opts?.MaxBytesInMemory ?? BinaryDataConfigurationDefaults.InMemoryMaxBytes;
+            var maxBytes = opts?.MaxBytesInMemory ?? BinaryDataConfigurationDefaults.InMemoryMaxBytes;
+            if (maxBytes <= 0 || maxBytes == int.MaxValue)
+                maxBytes = BinaryDataConfigurationDefaults.InMemoryMaxBytes;
+
+            InMemoryMaxBytes.Value = maxBytes;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs` around lines 20 - 24,
PushFromServices currently writes IBinaryDataMemoryLimit.MaxBytesInMemory
directly into the AsyncLocal InMemoryMaxBytes.Value; validate and sanitize the
DI-provided value first so invalid or negative numbers don't corrupt runtime
buffering. In PushFromServices, read opts?.MaxBytesInMemory into a local, check
for null/<=0 and replace with BinaryDataConfigurationDefaults.InMemoryMaxBytes,
and optionally clamp extremely large values to a sane upper bound before
assigning to InMemoryMaxBytes.Value; reference IBinaryDataMemoryLimit,
PushFromServices, InMemoryMaxBytes and
BinaryDataConfigurationDefaults.InMemoryMaxBytes when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/oscript/CgiBehavior.cs`:
- Around line 72-73: Replace the hard Resolve call so CGI startup uses a safe DI
lookup with a default fallback: try to get IBinaryDataMemoryLimit from
engine.Services (avoid engine.Services.Resolve which throws) and if null or
missing use BinaryDataConfigurationDefaults.InMemoryMaxBytes, then pass that
value into the WebRequestContext constructor; update the code locations
referencing IBinaryDataMemoryLimit, engine.Services.Resolve and the
WebRequestContext creation to use this conditional/fallback logic.

In `@src/oscript/Web/WebRequestContext.cs`:
- Around line 37-40: Validate the constructor parameter in WebRequestContext by
checking postBodyInMemoryMaxBytes at the start of the WebRequestContext(int
postBodyInMemoryMaxBytes) constructor and throw an ArgumentOutOfRangeException
(with a clear message mentioning _postBodyInMemoryMaxBytes and expected positive
byte count) when the value is invalid (e.g., <= 0 or otherwise out of allowed
range) so the error fails fast instead of propagating later into
FileBackingStream.
- Line 79: The code constructs FileBackingStream with the full content length
which causes MemoryStream to preallocate huge buffers; change the capacity
argument so initial allocation is capped by _postBodyInMemoryMaxBytes (e.g.,
pass Math.Min(len, _postBodyInMemoryMaxBytes) instead of len) when creating the
FileBackingStream (the call that assigns dest = new FileBackingStream(...)) so
the in-memory buffer is limited and spilling-to-disk behavior works as intended.

In `@src/ScriptEngine/BslProcess.cs`:
- Around line 45-46: Wrap the runtime push/pop and _isRunning mutation in a
try/finally so Pop() and _isRunning reset always run even if executor hooks
throw: call BinaryDataRuntimeSettings.PushFromServices and set _isRunning = true
before invoking Array.ForEach(_executorProviders, e =>
e.BeforeProcessStart(this)), then ensure BinaryDataRuntimeSettings.Pop() and
_isRunning = false are executed in a finally block; similarly, ensure any
Array.ForEach(_executorProviders, e => e.AfterProcessExit(this)) failures do not
prevent the finally from running (catch per-hook exceptions if desired) so Pop()
and _isRunning reset cannot be skipped.

---

Nitpick comments:
In `@src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs`:
- Around line 20-24: PushFromServices currently writes
IBinaryDataMemoryLimit.MaxBytesInMemory directly into the AsyncLocal
InMemoryMaxBytes.Value; validate and sanitize the DI-provided value first so
invalid or negative numbers don't corrupt runtime buffering. In
PushFromServices, read opts?.MaxBytesInMemory into a local, check for null/<=0
and replace with BinaryDataConfigurationDefaults.InMemoryMaxBytes, and
optionally clamp extremely large values to a sane upper bound before assigning
to InMemoryMaxBytes.Value; reference IBinaryDataMemoryLimit, PushFromServices,
InMemoryMaxBytes and BinaryDataConfigurationDefaults.InMemoryMaxBytes when
making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22f9a33d-f478-4b86-9fcf-a6bc6faba769

📥 Commits

Reviewing files that changed from the base of the PR and between c455964 and a7f38e3.

📒 Files selected for processing (12)
  • src/OneScript.StandardLibrary/Binary/BinaryDataContext.cs
  • src/OneScript.StandardLibrary/Binary/FileBackingConstants.cs
  • src/OneScript.StandardLibrary/Binary/FileBackingStream.cs
  • src/ScriptEngine.HostedScript/oscript.cfg
  • src/ScriptEngine/BinaryDataConfigurationDefaults.cs
  • src/ScriptEngine/BslProcess.cs
  • src/ScriptEngine/Hosting/EngineBuilderExtensions.cs
  • src/ScriptEngine/IBinaryDataMemoryLimit.cs
  • src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs
  • src/ScriptEngine/OneScriptCoreOptions.cs
  • src/oscript/CgiBehavior.cs
  • src/oscript/Web/WebRequestContext.cs

Comment thread src/oscript/CgiBehavior.cs Outdated
Comment thread src/oscript/Web/WebRequestContext.cs
Comment thread src/oscript/Web/WebRequestContext.cs Outdated
Comment thread src/ScriptEngine/BslProcess.cs Outdated
… обработки ошибок

Логика уведомлений исполнителя перемещена в единый условный блок для большей ясности.
Улучшена обработка ошибок при завершении процесса для обеспечения надлежащей очистки ресурсов.
Обновлены параметры BinaryDataRuntimeSettings для обеспечения положительных ограничений памяти и резервных значений по умолчанию.
Скорректирован WebRequestContext для проверки ограничений памяти при создании экземпляра.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
src/oscript/Web/WebRequestContext.cs (1)

37-42: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject Int32.MaxValue at the constructor boundary too.

FileBackingStream treats Int32.MaxValue as SYSTEM_IN_MEMORY_LIMIT and throws, so WebRequestContext(int) still accepts a value it cannot actually use. Failing fast here keeps the public API consistent and avoids a later exception from ProcessPostData().

Suggested fix
-            if (postBodyInMemoryMaxBytes <= 0)
+            if (postBodyInMemoryMaxBytes <= 0 || postBodyInMemoryMaxBytes == int.MaxValue)
                 throw new ArgumentOutOfRangeException(nameof(postBodyInMemoryMaxBytes),
-                    "Лимит памяти для тела POST-запроса должен быть положительным числом байт.");
+                    "Лимит памяти для тела POST-запроса должен быть положительным числом байт и меньше Int32.MaxValue.");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/oscript/Web/WebRequestContext.cs` around lines 37 - 42, The
WebRequestContext constructor currently only rejects non-positive values but
must also reject Int32.MaxValue because FileBackingStream treats that value as
SYSTEM_IN_MEMORY_LIMIT and will throw later; update the WebRequestContext(int
postBodyInMemoryMaxBytes) constructor to validate that postBodyInMemoryMaxBytes
is > 0 and < Int32.MaxValue (or != Int32.MaxValue) and throw an
ArgumentOutOfRangeException with a clear message if the value is Int32.MaxValue
so callers fail fast (this keeps behavior consistent with FileBackingStream and
avoids a later exception in ProcessPostData()).
src/ScriptEngine/BslProcess.cs (1)

49-68: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Unwind executors that already started when a later BeforeProcessStart throws.

_isRunning becomes true only after the whole startup loop succeeds, so a failure in any later BeforeProcessStart skips AfterProcessExit for executors that already initialized state. StackMachineExecutor.BeforeProcessStart() allocates machine/debugger state (src/ScriptEngine/Machine/StackMachineExecutor.cs:25-45), so failed startup can still leak per-process setup here.

Suggested direction
+            var startedExecutors = new List<IExecutorProvider>();
             try
             {
                 if (notifyExecutors)
-                    Array.ForEach(_executorProviders, e => e.BeforeProcessStart(this));
+                {
+                    foreach (var executor in _executorProviders)
+                    {
+                        executor.BeforeProcessStart(this);
+                        startedExecutors.Add(executor);
+                    }
+                }
 
                 _isRunning = true;
 
                 return _bslExecutorsByModule[module.GetType()](this, target, module, method, arguments);
             }
             finally
             {
                 if (notifyExecutors)
                 {
                     try
                     {
-                        if (_isRunning)
-                            Array.ForEach(_executorProviders, e => e.AfterProcessExit(this));
+                        for (var i = startedExecutors.Count - 1; i >= 0; i--)
+                            startedExecutors[i].AfterProcessExit(this);
                     }
                     finally
                     {
                         BinaryDataRuntimeSettings.Pop();
                         _isRunning = false;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ScriptEngine/BslProcess.cs` around lines 49 - 68, When calling each
executor's BeforeProcessStart (via Array.ForEach over _executorProviders) a
later exception can skip AfterProcessExit for earlier executors; modify
BslProcess.Start (the block invoking BeforeProcessStart/AfterProcessExit) to
track which providers successfully completed BeforeProcessStart (e.g., a local
list/flag per provider) and set _isRunning only for the process-level state,
then in the finally ensure you call AfterProcessExit for every provider that was
marked started (not gated solely on _isRunning), and still call
BinaryDataRuntimeSettings.Pop() and clear _isRunning; in short: record started
executors during the BeforeProcessStart loop and unwind them via their
AfterProcessExit even if startup throws.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/oscript/Web/WebRequestContext.cs`:
- Around line 37-42: The WebRequestContext constructor currently only rejects
non-positive values but must also reject Int32.MaxValue because
FileBackingStream treats that value as SYSTEM_IN_MEMORY_LIMIT and will throw
later; update the WebRequestContext(int postBodyInMemoryMaxBytes) constructor to
validate that postBodyInMemoryMaxBytes is > 0 and < Int32.MaxValue (or !=
Int32.MaxValue) and throw an ArgumentOutOfRangeException with a clear message if
the value is Int32.MaxValue so callers fail fast (this keeps behavior consistent
with FileBackingStream and avoids a later exception in ProcessPostData()).

In `@src/ScriptEngine/BslProcess.cs`:
- Around line 49-68: When calling each executor's BeforeProcessStart (via
Array.ForEach over _executorProviders) a later exception can skip
AfterProcessExit for earlier executors; modify BslProcess.Start (the block
invoking BeforeProcessStart/AfterProcessExit) to track which providers
successfully completed BeforeProcessStart (e.g., a local list/flag per provider)
and set _isRunning only for the process-level state, then in the finally ensure
you call AfterProcessExit for every provider that was marked started (not gated
solely on _isRunning), and still call BinaryDataRuntimeSettings.Pop() and clear
_isRunning; in short: record started executors during the BeforeProcessStart
loop and unwind them via their AfterProcessExit even if startup throws.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67fd241a-6dc6-485e-962b-7b19be63e644

📥 Commits

Reviewing files that changed from the base of the PR and between a7f38e3 and 2c90bbf.

📒 Files selected for processing (4)
  • src/ScriptEngine/BslProcess.cs
  • src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs
  • src/oscript/CgiBehavior.cs
  • src/oscript/Web/WebRequestContext.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/ScriptEngine/Machine/BinaryDataRuntimeSettings.cs

Comment thread src/OneScript.StandardLibrary/Binary/FileBackingConstants.cs
/// </summary>
public static class BinaryDataRuntimeSettings
{
private static readonly AsyncLocal<int?> InMemoryMaxBytes = new AsyncLocal<int?>();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Просьба пояснить зачем этот класс и что он призвать делать. Меня пугают AsyncLocal-ы тут.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лимит нужен в стандартной либе, а конфиг живёт у движка. Через AsyncLocal просто кладём число «на время выполнения скрипта», чтобы из BinaryData/FileBackingStream можно было его прочитать, не таская сервисы через все методы

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В этом и проблема. Почему не сделать конфиг там, где он нужен - в либе. Это первое, второе - зачем так часть "актуализировать" значение, ведь оно просто достается из конфига один раз на весь процесс oscript.exe и потом не меняется?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Понял, переделаю.

Comment thread src/ScriptEngine/BslProcess.cs Outdated

_isRunning = true;
if (notifyExecutors)
BinaryDataRuntimeSettings.PushFromServices(Services);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вот это тоже мне непонятно зачем и что делает.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мы один раз подтягиваем лимит из настроек движка и записываем его в это AsyncLocal. Дальше код двоичных данных сам берёт уже это значение. Без этого конструктор FileBackingStream вообще не узнал бы лимит.

Comment thread src/ScriptEngine/BslProcess.cs Outdated
}
finally
{
BinaryDataRuntimeSettings.Pop();
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Стекоподобная установка настроек двоичных данных чтобы что?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Push в начале Run, Pop в finally в конце, чтобы после выполнения значение не осталось висеть на потоке и не попало случайно в следующий запуск. Если название сбивает с толку - могу переформулировать

/// Лимит объёма данных в памяти для объектов «ДвоичныеДанные» и смежных потоков
/// до выгрузки во временный файл (байты).
/// </summary>
public interface IBinaryDataMemoryLimit
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне не нравится размазывание вот этого параметра по разным сборкам. Пользоваться этим будут только классы из StandardLibrary, но знание про настройку живет в CoreOptions сборки ScriptingEngine,

По-моему, лучше было бы, если те, кто потребляет этот параметр и объявляли бы у себя эту опцию.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если перетащить всё только в StandardLibrary - надо будет думать как не разъехаться с конфигом и oscript

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

надо будет думать как не разъехаться с конфигом и oscript

Вот эта фраза непонятна, нужно пояснение

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сейчас число одно и берётся из конфига движка. Если продублировать настройку «у потребителей», можно случайно получить два разных лимита или один забудут поправить. Про oscript имел в виду, что это как раз тот конфиг, откуда уже читают настройки.

…ичных данных

Созданы новые классы и интерфейсы для управления лимитом памяти двоичных данных, включая BinaryDataConfigurationDefaults, IBinaryDataMemoryLimit и BinaryDataMemoryLimit. Реализована регистрация лимита памяти в EngineBuilderExtensions и обновлены соответствующие классы для использования нового механизма. Удален устаревший BinaryDataRuntimeSettings. Обновлены тестовые и основные приложения для интеграции новых настроек.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/ScriptEngine/BslProcess.cs (1)

64-75: 💤 Low value

Consider wrapping each AfterProcessExit call to ensure all executors receive cleanup notification.

If one executor's AfterProcessExit throws, the loop exits and remaining executors won't be notified. Depending on what executors do (e.g., release resources, pop state), this could leave other executors in an inconsistent state.

If best-effort cleanup for all executors is desired:

♻️ Optional: catch-and-aggregate exceptions per executor
                     if (startedExecutors != null)
                     {
+                        List<Exception> cleanupExceptions = null;
                         for (var i = startedExecutors.Count - 1; i >= 0; i--)
-                            startedExecutors[i].AfterProcessExit(this);
+                        {
+                            try
+                            {
+                                startedExecutors[i].AfterProcessExit(this);
+                            }
+                            catch (Exception ex)
+                            {
+                                cleanupExceptions ??= new List<Exception>();
+                                cleanupExceptions.Add(ex);
+                            }
+                        }
+                        if (cleanupExceptions != null)
+                            throw new AggregateException(cleanupExceptions);
                     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ScriptEngine/BslProcess.cs` around lines 64 - 75, The loop calling
startedExecutors[i].AfterProcessExit(this) can abort if one executor throws;
modify the loop in BslProcess (where startedExecutors and _isRunning are used)
to call each executor inside its own try/catch so all executors get notified
even if one fails, and optionally collect/aggregate exceptions (e.g., into a
List<Exception>) to rethrow or log after the loop; preserve the existing finally
that sets _isRunning = false.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/ScriptEngine/BslProcess.cs`:
- Around line 64-75: The loop calling startedExecutors[i].AfterProcessExit(this)
can abort if one executor throws; modify the loop in BslProcess (where
startedExecutors and _isRunning are used) to call each executor inside its own
try/catch so all executors get notified even if one fails, and optionally
collect/aggregate exceptions (e.g., into a List<Exception>) to rethrow or log
after the loop; preserve the existing finally that sets _isRunning = false.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a0f91c0b-43c7-4ece-9f63-ae751783b71c

📥 Commits

Reviewing files that changed from the base of the PR and between 2c90bbf and ae3651f.

📒 Files selected for processing (19)
  • src/1Script.sln
  • src/OneScript.BinaryData/BinaryDataConfigurationDefaults.cs
  • src/OneScript.BinaryData/BinaryDataMemoryLimit.cs
  • src/OneScript.BinaryData/BinaryDataMemoryLimitConfiguration.cs
  • src/OneScript.BinaryData/BinaryDataRuntimeSettings.cs
  • src/OneScript.BinaryData/IBinaryDataMemoryLimit.cs
  • src/OneScript.BinaryData/OneScript.BinaryData.csproj
  • src/OneScript.StandardLibrary/Binary/BinaryDataContext.cs
  • src/OneScript.StandardLibrary/Binary/FileBackingConstants.cs
  • src/OneScript.StandardLibrary/Binary/FileBackingStream.cs
  • src/OneScript.StandardLibrary/EngineBuilderExtensions.cs
  • src/ScriptEngine/BslProcess.cs
  • src/ScriptEngine/Hosting/EngineBuilderExtensions.cs
  • src/ScriptEngine/ScriptEngine.csproj
  • src/ScriptEngine/ScriptingEngine.cs
  • src/TestApp/MainWindow.xaml.cs
  • src/oscript/CgiBehavior.cs
  • src/oscript/ConsoleHostBuilder.cs
  • src/oscript/Web/WebRequestContext.cs
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/OneScript.StandardLibrary/Binary/BinaryDataContext.cs
  • src/ScriptEngine/Hosting/EngineBuilderExtensions.cs
  • src/oscript/Web/WebRequestContext.cs
  • src/OneScript.StandardLibrary/Binary/FileBackingStream.cs

Comment on lines +17 to +31
private static volatile int _inMemoryMaxBytes = BinaryDataConfigurationDefaults.InMemoryMaxBytes;

/// <summary>
/// Читает лимит из DI и сохраняет для использования кодом без доступа к контейнеру (конструктор «Файловый поток с буфером» и т.п.).
/// Вызывается при создании экземпляра основного движка скриптов.
/// </summary>
public static void ApplyFromServices(IServiceContainer services)
{
var opts = services.TryResolve<IBinaryDataMemoryLimit>();
var maxBytes = opts?.MaxBytesInMemory ?? BinaryDataConfigurationDefaults.InMemoryMaxBytes;
if (maxBytes <= 0 || maxBytes == int.MaxValue)
maxBytes = BinaryDataConfigurationDefaults.InMemoryMaxBytes;

_inMemoryMaxBytes = maxBytes;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Scope the runtime limit per execution context, not as a process-wide mutable static.

Line 17 and Line 30 make the effective memory limit global for the whole process. That can bleed config between concurrently running engines and make behavior depend on initialization order.

💡 Refactor direction
+using System.Threading;
 ...
-        private static volatile int _inMemoryMaxBytes = BinaryDataConfigurationDefaults.InMemoryMaxBytes;
+        private static readonly AsyncLocal<int?> _currentInMemoryMaxBytes = new AsyncLocal<int?>();
 ...
-        public static void ApplyFromServices(IServiceContainer services)
+        public static int ResolveFromServices(IServiceContainer services)
         {
             var opts = services.TryResolve<IBinaryDataMemoryLimit>();
             var maxBytes = opts?.MaxBytesInMemory ?? BinaryDataConfigurationDefaults.InMemoryMaxBytes;
             if (maxBytes <= 0 || maxBytes == int.MaxValue)
                 maxBytes = BinaryDataConfigurationDefaults.InMemoryMaxBytes;
-
-            _inMemoryMaxBytes = maxBytes;
+            return maxBytes;
         }
 ...
-        public static int GetEffectiveInMemoryMaxBytes() => _inMemoryMaxBytes;
+        public static int GetEffectiveInMemoryMaxBytes() =>
+            _currentInMemoryMaxBytes ?? BinaryDataConfigurationDefaults.InMemoryMaxBytes;
+
+        public static void SetCurrentInMemoryMaxBytes(int maxBytes) =>
+            _currentInMemoryMaxBytes.Value =
+                (maxBytes <= 0 || maxBytes == int.MaxValue)
+                    ? BinaryDataConfigurationDefaults.InMemoryMaxBytes
+                    : maxBytes;
+
+        public static void ClearCurrentInMemoryMaxBytes() =>
+            _currentInMemoryMaxBytes.Value = null;

Also applies to: 37-37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants