From 9c8a44a2b38a2909b83e4841a050a4ed51ce4193 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 4 Aug 2026 10:39:11 +0300 Subject: [PATCH 1/2] chore: cap ImageMagick resources + server GC for the merge service (MAPCO-11324) - ImageMagick: pin the per-operation thread count to 1 (tiles are already parallelized at the app level, so Magick's internal threading only causes oversubscription) and cap native memory at 50% of the host so a single large image cannot exhaust it. - MergerService: enable server + concurrent GC for the long-running, allocation-heavy merge workload. Scope: the hygiene ticket also lists renames / dead-code / DI dedup. The app DI registrations were checked and contain no duplicates. Broad renames and dead-code removal are deferred to avoid merge churn against the sibling MAPCO-11317 PRs (they touch the same files); this PR keeps to the self-contained resource-limit wins. Co-Authored-By: Claude Opus 4.8 (1M context) --- MergerLogic/Extensions/ServiceCollectionExtensions.cs | 6 ++++++ MergerService/MergerService.csproj | 3 +++ 2 files changed, 9 insertions(+) diff --git a/MergerLogic/Extensions/ServiceCollectionExtensions.cs b/MergerLogic/Extensions/ServiceCollectionExtensions.cs index e3eeda97..d6e96a06 100644 --- a/MergerLogic/Extensions/ServiceCollectionExtensions.cs +++ b/MergerLogic/Extensions/ServiceCollectionExtensions.cs @@ -43,6 +43,12 @@ public static IServiceCollection RegisterMergerLogicType(this IServiceCollection public static IServiceCollection RegisterImageProcessors(this IServiceCollection collection) { + // Tiles are already processed in parallel at the app level, so keep ImageMagick single-threaded + // per operation to avoid thread oversubscription, and cap its native memory so one large image + // cannot exhaust the host. + ImageMagick.ResourceLimits.Thread = 1; + ImageMagick.ResourceLimits.LimitMemory(new ImageMagick.Percentage(50)); + return collection .AddSingleton() .AddSingleton(); diff --git a/MergerService/MergerService.csproj b/MergerService/MergerService.csproj index f495bdcd..c0131939 100644 --- a/MergerService/MergerService.csproj +++ b/MergerService/MergerService.csproj @@ -5,6 +5,9 @@ enable Linux $(MSBuildProjectDirectory) + + true + true From d5c29dfb11d1f62a1be3948dfed704544acf24dc Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Wed, 5 Aug 2026 17:10:39 +0300 Subject: [PATCH 2/2] refactor: isolate ImageMagick tuning, drop host-relative memory cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the process-global ImageMagick.ResourceLimits setup out of RegisterImageProcessors (a DI service-registration method) into an explicit ConfigureImageMagick() called once at the composition root, so the global side effect isn't hidden behind a "register services" call. Remove ResourceLimits.LimitMemory(Percentage(50)): the percentage resolves against host RAM, not the container cgroup, so it never bounded the pod (4Gi limit) and only gave false safety. Not an issue today (256x256 tiles keep the pixel cache tiny); a container-aware absolute limit is tracked as a follow-up. Thread=1 is kept — it prevents oversubscription against app-level parallelism. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../Extensions/ServiceCollectionExtensions.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/MergerLogic/Extensions/ServiceCollectionExtensions.cs b/MergerLogic/Extensions/ServiceCollectionExtensions.cs index d6e96a06..b5748a8c 100644 --- a/MergerLogic/Extensions/ServiceCollectionExtensions.cs +++ b/MergerLogic/Extensions/ServiceCollectionExtensions.cs @@ -26,6 +26,8 @@ public static class ServiceCollectionExtensions { public static IServiceCollection RegisterMergerLogicType(this IServiceCollection collection, bool includeServiceProvider = true) { + ConfigureImageMagick(); + if (includeServiceProvider) { collection = collection.RegisterServiceProvider(); @@ -43,17 +45,20 @@ public static IServiceCollection RegisterMergerLogicType(this IServiceCollection public static IServiceCollection RegisterImageProcessors(this IServiceCollection collection) { - // Tiles are already processed in parallel at the app level, so keep ImageMagick single-threaded - // per operation to avoid thread oversubscription, and cap its native memory so one large image - // cannot exhaust the host. - ImageMagick.ResourceLimits.Thread = 1; - ImageMagick.ResourceLimits.LimitMemory(new ImageMagick.Percentage(50)); - return collection .AddSingleton() .AddSingleton(); } + // Process-global ImageMagick tuning. Applied once at composition root, kept out of the DI + // registration methods so runtime side effects aren't hidden behind a "register services" call. + private static void ConfigureImageMagick() + { + // Tiles are already processed in parallel at the app level, so keep ImageMagick single-threaded + // per operation to avoid thread oversubscription. + ImageMagick.ResourceLimits.Thread = 1; + } + public static IServiceCollection RegisterMergerUtils(this IServiceCollection collection) { return collection