Skip to content

[INFRA-456] - feat(plane-enterprise): expose gunicorn rotation and Celery broker envs; add PLANE_INTERNAL_API_HOST to pi-api#271

Open
akshat5302 wants to merge 4 commits into
masterfrom
feat/gunicorn-celery-envs
Open

[INFRA-456] - feat(plane-enterprise): expose gunicorn rotation and Celery broker envs; add PLANE_INTERNAL_API_HOST to pi-api#271
akshat5302 wants to merge 4 commits into
masterfrom
feat/gunicorn-celery-envs

Conversation

@akshat5302

@akshat5302 akshat5302 commented Jul 23, 2026

Copy link
Copy Markdown
Member

What

Adds 5 new env vars to the plane-enterprise chart across two ConfigMaps:

app-vars ConfigMap (templates/config-secrets/app-env.yaml):

GUNICORN_MAX_REQUESTS: "0"          # env.gunicorn_max_requests
GUNICORN_MAX_REQUESTS_JITTER: "0"   # env.gunicorn_max_requests_jitter
CELERY_TASK_PUBLISH_RETRY: "True"   # env.celery_task_publish_retry
CELERY_BROKER_POOL_LIMIT: "10"      # env.celery_broker_pool_limit

pi-api-vars ConfigMap (templates/config-secrets/pi-api-env.yaml):

PLANE_INTERNAL_API_HOST: "http://<release>-api.<namespace>.svc.<cluster-domain>:8000"

Defaults declared in values.yaml; Rancher form entries added in questions.yml; README table updated.

Chart version bumped 3.0.0 → 3.0.1.

Why

Reported in #261 (leedsjb): a 50% silent CSV export failure rate caused by two compounding issues:

  1. Gunicorn worker rotation--max-requests 1200 is hardcoded in the image entrypoint, rotating each worker every ~1,200–2,200 requests. Each rotation produces a ~10–30 s AMQP reconnect window. During that window, task.delay() either hits a broken connection (returning without raising) or writes to a kernel-accepted-but-broker-closed socket — both paths silently discard the task, leaving the exporters record stuck in "queued" forever.

  2. No publish retry + unbounded broker pool — without CELERY_TASK_PUBLISH_RETRY, Kombu treats a failed publish as final. Without a pool limit, stale connections accumulate and are reused without health-checking.

PLANE_INTERNAL_API_HOST is added so PI can reach the backend API directly over the cluster network without going through the ingress.

Scope / behavior

Var Default Changes default behavior?
GUNICORN_MAX_REQUESTS 0 (disabled) Yes — disables gunicorn rotation. Image previously hardcoded 1200; this env allows override.
GUNICORN_MAX_REQUESTS_JITTER 0 Yes — jitter also disabled by default.
CELERY_TASK_PUBLISH_RETRY True Yes — enables publish retry on all deployments.
CELERY_BROKER_POOL_LIMIT 10 Yes — bounds the previously unlimited pool.
PLANE_INTERNAL_API_HOST in-cluster API URL Not configurable; always renders to http://<release>-api.<ns>.svc.<domain>:8000.

GUNICORN_MAX_REQUESTS and GUNICORN_MAX_REQUESTS_JITTER only take effect if the image entrypoint reads these env vars (the fix in the application image is a prerequisite for the rotation changes to work). CELERY_TASK_PUBLISH_RETRY and CELERY_BROKER_POOL_LIMIT are Celery settings consumed by the Django/Celery app directly.

PLANE_INTERNAL_API_HOST is rendered unconditionally whenever services.pi.enabled=true (the template is already gated by that condition).

Testing

helm lint — clean, 0 failures.

helm template output (defaults):

GUNICORN_MAX_REQUESTS: "0"
GUNICORN_MAX_REQUESTS_JITTER: "0"
CELERY_TASK_PUBLISH_RETRY: "True"
CELERY_BROKER_POOL_LIMIT: "10"
PLANE_INTERNAL_API_HOST: "http://test-api.default.svc.cluster.local:8000"

helm template with --set env.gunicorn_max_requests=1200 --set env.gunicorn_max_requests_jitter=200 --set env.celery_task_publish_retry=false --set env.celery_broker_pool_limit=5:

GUNICORN_MAX_REQUESTS: "1200"
GUNICORN_MAX_REQUESTS_JITTER: "200"
CELERY_TASK_PUBLISH_RETRY: "False"
CELERY_BROKER_POOL_LIMIT: "5"

Related

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added configurable Gunicorn worker request limits and restart jitter.
    • Added Celery task publish retry and broker pool limit settings.
    • Added an in-cluster internal API host configuration for the API service.
  • Documentation
    • Updated the enterprise chart README and configuration prompts to include the new tunables (with defaults and descriptions).
  • Chores
    • Bumped the enterprise Helm chart version to 3.0.1.

akshat5302 and others added 3 commits July 23, 2026 15:47
…v vars

Add GUNICORN_MAX_REQUESTS, GUNICORN_MAX_REQUESTS_JITTER,
CELERY_TASK_PUBLISH_RETRY, and CELERY_BROKER_POOL_LIMIT to the
app-vars ConfigMap so operators can tune worker rotation and broker
pool behaviour without rebuilding the image.

Defaults set to Kubernetes-friendly values (rotation disabled,
publish retry enabled, pool bounded to 10) to eliminate the
silent task-dispatch failures reported in issue #261.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ERNAL_API_HOST to pi-api

Add to app-vars ConfigMap (configurable via values.yaml):
- GUNICORN_MAX_REQUESTS (default 0 — rotation disabled, recommended for K8s)
- GUNICORN_MAX_REQUESTS_JITTER (default 0)
- CELERY_TASK_PUBLISH_RETRY (default True — prevent silent task drops on AMQP reconnect)
- CELERY_BROKER_POOL_LIMIT (default 10 — bound connection pool to avoid stale accumulation)

Add to pi-api-vars ConfigMap (hardcoded internal cluster URL):
- PLANE_INTERNAL_API_HOST — points directly to the in-cluster API service

Fixes the silent CSV export failures reported in issue #261 where
gunicorn worker rotation caused stale AMQP connections to silently
discard published tasks.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ETRY

Align with existing boolean pattern (ternary without default) so that
setting celery_task_publish_retry: false in values.yaml is respected.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 912d3294-0a42-4a0e-aedc-82a2d7e69d88

📥 Commits

Reviewing files that changed from the base of the PR and between dfa566f and 8f61938.

📒 Files selected for processing (4)
  • charts/plane-enterprise/README.md
  • charts/plane-enterprise/questions.yml
  • charts/plane-enterprise/templates/config-secrets/app-env.yaml
  • charts/plane-enterprise/values.yaml
🚧 Files skipped from review as they are similar to previous changes (4)
  • charts/plane-enterprise/values.yaml
  • charts/plane-enterprise/README.md
  • charts/plane-enterprise/questions.yml
  • charts/plane-enterprise/templates/config-secrets/app-env.yaml

Walkthrough

The enterprise Helm chart adds configurable Gunicorn and Celery environment settings, renders them into application configuration, adds an internal API host, documents the new options, and increments the chart version.

Changes

Enterprise chart configuration

Layer / File(s) Summary
Environment tuning configuration
charts/plane-enterprise/values.yaml, charts/plane-enterprise/questions.yml, charts/plane-enterprise/README.md, charts/plane-enterprise/templates/config-secrets/app-env.yaml
Adds Gunicorn request-rotation and Celery retry/broker-pool settings, with defaults, configuration questions, documentation, and ConfigMap rendering.
Internal API host and chart release metadata
charts/plane-enterprise/Chart.yaml, charts/plane-enterprise/templates/config-secrets/pi-api-env.yaml
Updates the chart version to 3.0.1 and adds the in-cluster PLANE_INTERNAL_API_HOST value to the PI API ConfigMap.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: sriramveeraghanta, mguptahub

Poem

A rabbit hops through Helm’s bright tune,
Four new knobs rise beneath the moon.
Gunicorn spins, Celery sings,
An inner API sprouts its wings.
Chart 3.0.1 greets spring.

🚥 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 summarizes the main Helm chart changes: new Gunicorn/Celery envs and PLANE_INTERNAL_API_HOST.
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/gunicorn-celery-envs

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
charts/plane-enterprise/questions.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

charts/plane-enterprise/templates/config-secrets/app-env.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

charts/plane-enterprise/values.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

@makeplane

makeplane Bot commented Jul 23, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@charts/plane-enterprise/README.md`:
- Around line 503-504: Update the Celery settings entries
env.celery_task_publish_retry and env.celery_broker_pool_limit in the README
configuration documentation to place them in a shared API/worker environment
section or explicitly identify both workloads as consumers. Preserve their
existing defaults and descriptions.

In `@charts/plane-enterprise/templates/config-secrets/app-env.yaml`:
- Line 82: Update the CELERY_BROKER_POOL_LIMIT template expression to preserve
an explicitly configured value of 0 instead of allowing default to replace it
with 10. Use presence-based handling such as hasKey on
.Values.env.celery_broker_pool_limit, while retaining 10 only when the key is
absent.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 30bc2b85-10b9-4fc4-b6b0-7c1bedd3e104

📥 Commits

Reviewing files that changed from the base of the PR and between bfd3047 and dfa566f.

📒 Files selected for processing (6)
  • charts/plane-enterprise/Chart.yaml
  • charts/plane-enterprise/README.md
  • charts/plane-enterprise/questions.yml
  • charts/plane-enterprise/templates/config-secrets/app-env.yaml
  • charts/plane-enterprise/templates/config-secrets/pi-api-env.yaml
  • charts/plane-enterprise/values.yaml

Comment thread charts/plane-enterprise/README.md
GUNICORN_MAX_REQUESTS: {{ .Values.env.gunicorn_max_requests | default 0 | quote }}
GUNICORN_MAX_REQUESTS_JITTER: {{ .Values.env.gunicorn_max_requests_jitter | default 0 | quote }}
CELERY_TASK_PUBLISH_RETRY: {{ .Values.env.celery_task_publish_retry | ternary "True" "False" | quote }}
CELERY_BROKER_POOL_LIMIT: {{ .Values.env.celery_broker_pool_limit | default 10 | quote }}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

helm template plane-enterprise charts/plane-enterprise \
  --set env.celery_broker_pool_limit=0 |
  grep -F 'CELERY_BROKER_POOL_LIMIT: "0"'

Repository: makeplane/helm-charts

Length of output: 197


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== candidate files =="
fd -a 'app-env.yaml|values.yaml|Chart.yaml' charts 2>/dev/null | sort

echo
echo "== app-env relevant section =="
if [ -f charts/plane-enterprise/templates/config-secrets/app-env.yaml ]; then
  nl -ba charts/plane-enterprise/templates/config-secrets/app-env.yaml | sed -n '70,90p'
fi

echo
echo "== values references for celery_broker_pool_limit =="
rg -n "celery_broker_pool_limit|broker_pool_limit|CELERY_BROKER_POOL_LIMIT" -S .

Repository: makeplane/helm-charts

Length of output: 610


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
# Read-only behavioral probe of Helm Go `default` equivalent semantics as described:
# numeric 0 is treated empty by the chart template, so an explicit 0 via default 10 becomes 10.
from functools import reduce
values = {'env': {'celery_broker_pool_limit': 0}}
actual = values.get('env') or {}
actual = actual.get('celery_broker_pool_limit')
result = actual if actual is not None and actual != '' else 10
print('env.celery_broker_pool_limit 0 ->', result)

values = {'env': {'celery_broker_pool_limit': None}}
actual = values.get('env') or {}
actual = actual.get('celery_broker_pool_limit')
result = actual if actual is not None and actual != '' else 10
print('missing default fallback key ->', result)
PY

Repository: makeplane/helm-charts

Length of output: 230


🌐 Web query:

Helm chart function default zero numeric treated empty documentation

💡 Result:

In Helm charts, the default function treats a numeric 0 as an "empty" value [1][2]. Consequently, if you use {{ default "fallback".Values.myValue }} and.Values.myValue is set to 0, Helm will return "fallback" instead of 0 [3][4]. This behavior is intended by the template engine, which considers the following types "empty" [1][2]: - Numeric: 0 - String: "" - Lists: [] - Dictionaries: {} - Boolean: false - Nil (null) Because 0 is categorized as empty, the default function cannot natively distinguish between a value that is missing (nil) and a value that is explicitly set to 0 [4][5]. Workarounds If your use case requires treating 0 as a valid value while still providing a default for truly missing/null values, you must implement logic to explicitly check the value instead of relying on the default function [3][4]: 1. Explicit Check with if/else: You can check if the value is specifically 0 before applying a default [5]: {{- if eq (toString.Values.myValue) "0" }} myValue: 0 {{- else }} myValue: {{ default "fallback".Values.myValue }} {{- end }} 2. Kind Checking: Some developers use the kindIs function to verify if the value is set before deciding how to handle it, which helps avoid type-related comparison errors [6]: {{- if or (kindIs "int64".Values.myValue) (kindIs "float64".Values.myValue) }} myValue: {{.Values.myValue }} {{- else }} myValue: {{ default "fallback".Values.myValue }} {{- end }} 3. Setting Defaults in values.yaml: The most robust practice is to define static default values directly in your values.yaml file rather than using the default function in templates [7][8][5]. This ensures the value is explicitly defined and avoids the ambiguity of the default function [5].

Citations:


🌐 Web query:

Celery broker_pool_limit 0 disable connection pool documentation

💡 Result:

According to official Celery documentation, setting the broker_pool_limit configuration option to 0 or None will disable the broker connection pool [1][2][3]. When disabled, Celery will establish and close a connection for every individual use [1][2][3]. While this is the documented behavior, it is worth noting that some users have reported issues in recent versions of Celery where setting this parameter to 0 or None does not appear to have the expected effect of disabling the pool, leading to potential connection exhaustion in certain client configurations [4]. The broker connection pool has been enabled by default since Celery version 2.5, with a default limit of 10 connections [1][2][3]. Increasing this limit is generally recommended to minimize contention in environments with high numbers of active threads or green-threads [5][1][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path("charts/plane-enterprise/templates/config-secrets/app-env.yaml")
text = p.read_text()
idx = text.find("CELERY_BROKER_POOL_LIMIT")
print(text[idx-120: idx+160])

path = Path("charts/plane-enterprise/values.yaml")
print("\n=== values.yaml celery_broker_pool_limit context ==")
lines = [ln.splitlines()[0] for ln in path.read_text().splitlines()]
for i, line in enumerate(lines, 1):
    if "celery_broker_pool_limit" in line:
        for offset in range(-3, 4):
            j = i + offset
            if 0 < j <= len(lines):
                print(f"{j}: {lines[j-1]}")
PY

Repository: makeplane/helm-charts

Length of output: 642


Preserve an explicit 0 broker pool limit.

default treats numeric 0 as empty, so --set env.celery_broker_pool_limit=0 renders CELERY_BROKER_POOL_LIMIT: "10". Since Celery allows 0 and None to disable the connection pool, use presence-based handling such as hasKey or validate/reject 0 explicitly.

🤖 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 `@charts/plane-enterprise/templates/config-secrets/app-env.yaml` at line 82,
Update the CELERY_BROKER_POOL_LIMIT template expression to preserve an
explicitly configured value of 0 instead of allowing default to replace it with
10. Use presence-based handling such as hasKey on
.Values.env.celery_broker_pool_limit, while retaining 10 only when the key is
absent.

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