From 42bd8b1d80e02520726c73446d8431b3eb0f39e8 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 f3e523e197ce9f8bd878b4762e26b75c7d545c7e 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