Skip to content

feat(helm): worker concurrency and extraArgs support#16

Merged
lewisjared merged 1 commit into
mainfrom
feat/worker-concurrency-args
Jul 1, 2026
Merged

feat(helm): worker concurrency and extraArgs support#16
lewisjared merged 1 commit into
mainfrom
feat/worker-concurrency-args

Conversation

@lewisjared

@lewisjared lewisjared commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Provider workers were rendered with a hardcoded celery start-worker arg list with no extension point, so tuning a worker (e.g. pinning Celery concurrency) required a downstream postRenderers kustomize patch that replaced the entire args array — fragile, since it silently freezes a copy of the base args and misses any future chart changes.

This adds two chart values, both rendered as Celery worker options after the -- separator:

  • concurrency (first-class) → --concurrency=<n>
  • extraArgs (free-form list) → concatenated verbatim, for options not exposed as first-class values

The -- separator is only emitted when at least one worker option is set, so providers with neither render exactly as before.

It also sets providers.esmvaltool.concurrency: 1 as a chart default: each esmvaltool execution already fans out through its own Dask cluster, so running multiple Celery workers per pod multiplies the memory footprint and OOM-kills the node. This upstreams a fix previously carried as a home-infra postRenderer patch, which can now be removed.

Rendered output

Provider Args tail
esmvaltool (default) --provider esmvaltool -- --concurrency=1
pmp (concurrency: 4) --provider pmp -- --concurrency=4
ilamb (extraArgs: [--pool=solo]) --provider ilamb -- --pool=solo
orchestrator / unset unchanged (no --)

Testing

  • helm lint passes.
  • helm template verified for all four cases above (first-class, free-form, combined, and unset).
  • towncrier build --draft renders the changelog fragment.

Summary by CodeRabbit

  • New Features
    • Added support for tuning worker concurrency and passing extra worker arguments.
    • Worker command-line options are now included after the -- separator where applicable.
  • Bug Fixes
    • Set the esmvaltool worker to run with a single process per pod to help prevent out-of-memory issues.

…ne worker

Provider workers had a hardcoded arg list with no way to pass Celery
worker options, forcing downstream overrides to replace the entire args
array. Add a first-class `concurrency` value rendered as
`--concurrency=<n>` and a free-form `extraArgs` list, both appended
after the Celery `--` separator. Pin the esmvaltool worker to
`concurrency: 1` so its Dask fan-out does not OOM-kill the node.
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Helm chart support for configuring Celery worker concurrency and extraArgs per provider, with new defaults in values.yaml, template logic in deployment.yaml to render these as CLI arguments after --, an esmvaltool override pinning concurrency to 1, and a corresponding changelog entry.

Changes

Worker concurrency/extraArgs configuration

Layer / File(s) Summary
Values defaults and esmvaltool override
helm/values.yaml
Adds defaults.concurrency: null and defaults.extraArgs: [], plus providers.esmvaltool.concurrency: 1 override with explanatory comments.
Deployment template arg assembly
helm/templates/providers/deployment.yaml
Builds $workerArgs from spec.concurrency and spec.extraArgs, appending -- and the worker args to the container's args list when non-empty.
Changelog entry
changelog/16.feature.md
Documents the new concurrency/extraArgs support and the esmvaltool pin.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main Helm change: adding worker concurrency and extraArgs support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/worker-concurrency-args

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 023137c2-25fe-4be8-b2d1-c65d5f2eb782

📥 Commits

Reviewing files that changed from the base of the PR and between 2600752 and c2ef599.

📒 Files selected for processing (3)
  • changelog/16.feature.md
  • helm/templates/providers/deployment.yaml
  • helm/values.yaml

Comment thread helm/values.yaml
Comment on lines +180 to +184
concurrency: null

# Additional arguments appended to the Celery worker after the `--` separator,
# for options not exposed as first-class values (e.g. ["--pool=solo"]).
extraArgs: []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify provider overrides render after defaults define the same keys.
set -eu

if ! command -v helm >/dev/null 2>&1; then
  echo "helm is not installed; run this locally in an environment with Helm."
  exit 0
fi

helm template verify ./helm \
  --set providers.esmvaltool.concurrency=1 \
  --set 'providers.esmvaltool.extraArgs[0]=--pool=solo' |
  awk '
    /name: .*esmvaltool/ { in_esm=1 }
    in_esm && /args:/ { in_args=1 }
    in_args { print }
    in_args && /envFrom:/ { exit }
  '
# Expect the esmvaltool container args to include:
# - --
# - --concurrency=1
# - --pool=solo

Repository: Climate-REF/climate-ref-aft

Length of output: 234


🏁 Script executed:

#!/bin/bash
set -eu

printf '\n## helm/values.yaml (around the changed lines)\n'
sed -n '160,210p' helm/values.yaml

printf '\n## helm/templates/providers/deployment.yaml\n'
sed -n '1,240p' helm/templates/providers/deployment.yaml

printf '\n## any other merge/mergeOverwrite usage in helm/\n'
rg -n '\bmergeOverwrite\b|\bmerge\b' helm -g '*.yaml' -g '*.tpl' -g '*.yml'

Repository: Climate-REF/climate-ref-aft

Length of output: 6153


🌐 Web query:

Sprig merge mergeOverwrite precedence destination precedence Helm docs

💡 Result:

In Helm and the underlying Sprig library, the merge and mergeOverwrite functions handle dictionary precedence differently [1][2]. Both functions perform a deep merge, meaning they recursively merge nested dictionaries, but they do not perform a deep copy; nested objects remain shared instances across the merged dictionaries [1][3]. merge The merge function gives precedence to the destination (the first) dictionary [1][4]. When merging multiple dictionaries, if a key exists in both the destination dictionary and the source dictionaries, the value in the destination dictionary is preserved [1][2]. mergeOverwrite The mergeOverwrite function gives precedence from right to left [1][4]. In this operation, values in the source dictionaries overwrite values in the destination dictionary [1][3]. This is particularly useful for overriding default configurations, as it ensures that values provided in later arguments take priority over those in earlier ones [5]. Key Differences in Behavior A notable quirk often encountered is that merge may not overwrite boolean fields set to true in the destination dictionary, whereas mergeOverwrite correctly overwrites these values [5][6]. Because these functions mutate the destination dictionary (the first argument), it is common practice to pass an empty dictionary (dict) as the first argument or to use deepCopy to avoid unintended side effects on source objects [5][7]. Example Usage To merge with overwrite precedence: {{ $newdict:= mergeOverwrite (dict) $defaultValues $userOverrides }} To ensure a deep copy during the merge: {{ $newdict:= mergeOverwrite (dict) (deepCopy $defaultValues) $userOverrides }}

Citations:


Switch this merge to right-precedence.

merge (deepCopy $.Values.defaults) $spec keeps the new default concurrency: null and extraArgs: [] values, so provider overrides like providers.esmvaltool.concurrency=1 and extraArgs never make it into the worker args. Use mergeOverwrite here so provider-specific settings win.

@lewisjared lewisjared merged commit 62db0f0 into main Jul 1, 2026
10 checks passed
@lewisjared lewisjared deleted the feat/worker-concurrency-args branch July 1, 2026 12:13
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.

1 participant