Skip to content

[feat][r2] optionally split rrGitServer into its own deployment#309

Open
JatinNanda wants to merge 1 commit into
r2-cleanupfrom
jatin/separate-git-server
Open

[feat][r2] optionally split rrGitServer into its own deployment#309
JatinNanda wants to merge 1 commit into
r2-cleanupfrom
jatin/separate-git-server

Conversation

@JatinNanda

Copy link
Copy Markdown
Contributor

Summary

Adds rrGitServer.separate.enabled to optionally run the git server as a dedicated deployment + service instead of in-process on the main backend, mirroring how the workload is split in Retool Cloud. The split-out git server is reached over normal Kubernetes service discovery.

Stacks on top of the in-process git server work (#296), so this PR targets r2-cleanup.

When rrGitServer.separate.enabled: true

  • A dedicated <release>-git-server Deployment runs SERVICE_TYPE=RR_GIT_SERVER on RR_GIT_SERVER_PORT, with the Postgres connection, bootstrap secrets (license/JWT/encryption/pg password), blob-storage env, and telemetry. A matching Service (+ PDB) is rendered.
  • The main backend drops RR_GIT_SERVER from its SERVICE_TYPE and proxies git traffic to the service via RR_GIT_SERVER_HOST / RR_GIT_SERVER_PORT.
  • The MCP server (if enabled) is auto-pointed at the service via RETOOL_GIT_SERVER_URL, unless mcp.config.retoolGitServerUrl is set explicitly.

In-process mode (rrGitServer.enabled without separate) is unchanged.

Implementation notes

  • Extracted the blob-storage + repack env block into a shared helper retool.rrGitServer.commonEnv so the in-process backend and the standalone deployment stay in sync.
  • New helpers: retool.rrGitServer.{name,separateEnabled,port,url}.
  • Both values.yaml files kept byte-identical (sync check).

⚠️ Needs confirmation

The backend→remote git server contract uses RR_GIT_SERVER_HOST (bare service DNS) + RR_GIT_SERVER_PORT, extending the documented in-process RR_GIT_SERVER_PORT. If the backend expects a different var (e.g. a full URL), it's a one-line change in deployment_backend.yaml. Default rrGitServer.separate.port is 3010.

Testing

  • helm lint passes.
  • Rendered + verified: separate mode (correct Service, backend pointer, git-server env, MCP URL, RR_GIT_SERVER absent from backend), in-process mode (unchanged), and default-off mode. All parse as valid YAML.
  • Added ci/test-rr-git-server-separate-option.yaml exercising the split + S3 blob storage + MCP auto-wiring.

🤖 Generated with Claude Code

@JatinNanda JatinNanda force-pushed the jatin/separate-git-server branch from ccc2f8f to 3cd2a94 Compare June 8, 2026 20:18
@JatinNanda JatinNanda marked this pull request as ready for review June 9, 2026 02:48
Adds rrGitServer.separate.enabled to run the git server as a dedicated
deployment + service instead of in-process on the main backend, mirroring
how the workload is split in Retool Cloud (reached via normal k8s service
discovery).

When enabled:
- a dedicated <release>-git-server Deployment runs SERVICE_TYPE=RR_GIT_SERVER
  on RR_GIT_SERVER_PORT, with the Postgres connection, bootstrap secrets,
  blob-storage env, and telemetry
- the main backend drops RR_GIT_SERVER from its SERVICE_TYPE and proxies git
  traffic to the service via RR_GIT_SERVER_HOST / RR_GIT_SERVER_PORT
- the MCP server (if enabled) is auto-pointed at the service unless
  mcp.config.retoolGitServerUrl is set explicitly

The blob-storage env block is extracted into a shared helper
(retool.rrGitServer.commonEnv) so the in-process backend and the standalone
deployment stay in sync. In-process mode (rrGitServer.enabled without
separate) is unchanged.

Adds ci/test-rr-git-server-separate-option.yaml exercising the split + S3
blob storage + MCP auto-wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JatinNanda JatinNanda force-pushed the jatin/separate-git-server branch from 3cd2a94 to 903816e Compare June 9, 2026 02:50
@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds rrGitServer.separate.enabled to optionally run the Retool git server as a dedicated Kubernetes Deployment + Service instead of in-process on the main backend, mirroring Retool Cloud's topology. The blob-storage env block is extracted into a shared retool.rrGitServer.commonEnv helper so both modes stay in sync, and the MCP server is auto-wired to the standalone git server URL unless overridden.

  • New deployment_git_server.yaml: Renders a Service + Deployment with SERVICE_TYPE=RR_GIT_SERVER, Postgres credentials, blob-storage env, and all global env/secret overrides; the main backend drops RR_GIT_SERVER from its SERVICE_TYPE and instead sets RR_GIT_SERVER_HOST/RR_GIT_SERVER_PORT proxy vars.
  • Helper additions in _helpers.tpl: Four new named templates (retool.rrGitServer.{name,separateEnabled,port,url}) and the extracted retool.rrGitServer.commonEnv block keep both code paths DRY.
  • MCP auto-wiring in deployment_mcp.yaml: When separate mode is on and no explicit mcp.config.retoolGitServerUrl is set, RETOOL_GIT_SERVER_URL is automatically pointed at the in-cluster git server service URL.

Confidence Score: 4/5

The core routing logic is sound — SERVICE_TYPE exclusion, RR_GIT_SERVER_HOST/PORT proxy vars, and MCP auto-wiring are all correct. The standalone git server deployment is missing a PodDisruptionBudget (claimed in the PR description) and telemetry env vars, both of which affect production observability and availability rather than basic functionality.

The helper extraction and mode-switching logic in the backend and MCP deployments are clean and well-guarded. The main gap is in the new deployment_git_server.yaml: it omits retool.telemetry.includeEnvVars (which every other service deployment includes, and which the PR description explicitly promises) and has no PodDisruptionBudget despite all peer deployments having one and the PR description stating one is rendered. Neither omission prevents the feature from working in a basic sense, but both reduce production readiness for a deployment that supports multiple replicas.

charts/retool/templates/deployment_git_server.yaml — missing PDB, missing telemetry env vars, and shared annotations applied to both Service and Pod without differentiation.

Important Files Changed

Filename Overview
charts/retool/templates/deployment_git_server.yaml New file rendering the standalone git server Service + Deployment; missing PDB (claimed by PR description), missing telemetry env vars, and shared annotations applied to both Service and Pod template without differentiation.
charts/retool/templates/_helpers.tpl Adds retool.rrGitServer.{name,separateEnabled,port,url} helpers and extracts the blob-storage/repack env block into retool.rrGitServer.commonEnv; logic is correct and the separateEnabled guard properly requires both flags.
charts/retool/templates/deployment_backend.yaml Correctly removes RR_GIT_SERVER from SERVICE_TYPE in separate mode and switches from commonEnv to RR_GIT_SERVER_HOST/PORT proxy vars; blob-storage vars are no longer duplicated onto the backend when git server is split out.
charts/retool/templates/deployment_mcp.yaml MCP auto-wiring to the standalone git server URL is clean; explicit mcp.config.retoolGitServerUrl correctly takes precedence over the auto-computed URL.
charts/retool/values.yaml Adds rrGitServer.separate stanza with sensible defaults (disabled, port 3010, 1 replica, empty affinity/resources/annotations/labels); mirrored identically to values.yaml at repo root.
charts/retool/ci/test-rr-git-server-separate-option.yaml CI test values exercising separate mode with S3 blob storage and MCP auto-wiring; covers the main happy path.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Backend as Main Backend
    participant GitSvc as git-server Service (ClusterIP)
    participant GitDep as git-server Deployment
    participant MCP as MCP Server
    participant PG as PostgreSQL
    participant Blob as Blob Storage

    Note over Backend,GitDep: rrGitServer.separate.enabled = true

    Client->>Backend: "/api/ai/rr/git/v2/* request"
    Backend->>GitSvc: proxy via RR_GIT_SERVER_HOST:RR_GIT_SERVER_PORT
    GitSvc->>GitDep: route to git-server pod
    GitDep->>PG: read/write git metadata
    GitDep->>Blob: read/write git objects
    GitDep-->>Backend: git response
    Backend-->>Client: response

    MCP->>GitSvc: RETOOL_GIT_SERVER_URL (auto-wired)
    GitSvc->>GitDep: route to git-server pod
Loading

Reviews (1): Last reviewed commit: "[feat][r2] optionally split rrGitServer ..." | Re-trigger Greptile

Comment on lines +88 to +167
env:
- name: DEPLOYMENT_TEMPLATE_TYPE
value: {{ template "retool.deploymentTemplateType" . }}
- name: DEPLOYMENT_TEMPLATE_VERSION
value: {{ template "retool.deploymentTemplateVersion" . }}
- name: NODE_ENV
value: production
- name: SERVICE_TYPE
value: RR_GIT_SERVER
- name: RR_GIT_SERVER_PORT
value: {{ $gitServerPort | quote }}
# The standalone git server does not run migrations; the main backend owns them.
- name: DISABLE_DATABASE_MIGRATIONS
value: "true"
- name: COOKIE_INSECURE
value: {{ .Values.config.useInsecureCookies | quote }}
- name: POSTGRES_HOST
value: {{ template "retool.postgresql.host" . }}
- name: POSTGRES_PORT
value: {{ template "retool.postgresql.port" . }}
- name: POSTGRES_DB
value: {{ template "retool.postgresql.database" . }}
- name: POSTGRES_USER
value: {{ template "retool.postgresql.user" . }}
- name: POSTGRES_SSL_ENABLED
value: {{ template "retool.postgresql.ssl_enabled" . }}
{{- if include "shouldIncludeConfigSecretsEnvVars" . }}
- name: LICENSE_KEY
valueFrom:
secretKeyRef:
{{- if .Values.config.licenseKeySecretName }}
name: {{ .Values.config.licenseKeySecretName }}
key: {{ .Values.config.licenseKeySecretKey | default "license-key" }}
{{- else }}
name: {{ template "retool.fullname" . }}
key: license-key
{{- end }}
- name: JWT_SECRET
valueFrom:
secretKeyRef:
{{- if .Values.config.jwtSecretSecretName }}
name: {{ .Values.config.jwtSecretSecretName }}
key: {{ .Values.config.jwtSecretSecretKey | default "jwt-secret" }}
{{- else }}
name: {{ template "retool.fullname" . }}
key: jwt-secret
{{- end }}
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
{{- if .Values.config.encryptionKeySecretName }}
name: {{ .Values.config.encryptionKeySecretName }}
key: {{ .Values.config.encryptionKeySecretKey | default "encryption-key" }}
{{- else }}
name: {{ template "retool.fullname" . }}
key: encryption-key
{{- end }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
{{- if .Values.postgresql.enabled }}
name: {{ template "retool.postgresql.fullname" . }}
# `postgres` is the default admin username for postgres in the subchart we use, so it needs the admin password
# if a different username is picked, then it needs the custom password instead.
{{- if eq .Values.postgresql.auth.username "postgres" }}
key: postgres-password
{{- else }}
key: password
{{- end }}
{{- else }}
{{- if .Values.config.postgresql.passwordSecretName }}
name: {{ .Values.config.postgresql.passwordSecretName }}
key: {{ .Values.config.postgresql.passwordSecretKey | default "postgresql-password" }}
{{- else }}
name: {{ template "retool.fullname" . }}
key: postgresql-password
{{- end }}
{{- end }}
{{- end }}
{{- include "retool.rrGitServer.commonEnv" . | nindent 10 }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Missing telemetry env vars on git server pod

Every other Retool service deployment (backend, jobs, workflows, workers, code-executor, js-executor) calls {{- include "retool.telemetry.includeEnvVars" . | nindent 10 }} to inject RTEL_ENABLED, RTEL_SERVICE_NAME, STATSD_HOST/PORT, and the K8S_* field refs that feed the telemetry sidecar. The standalone git server deployment omits this call entirely. The PR description explicitly lists "telemetry" as one of the env var groups the git server receives, but it is absent from the rendered pod spec. Additionally, the pod template does not set the telemetry.retool.com/service-name label required by RTEL_SERVICE_NAME, so if telemetry were added without that label the service-name fieldRef would resolve to an empty string.

Comment on lines +1 to +30
{{- if include "retool.rrGitServer.separateEnabled" . }}
{{- include "retool.rrGitServer.validateBlobStorage" . }}
{{- $gitServerPort := include "retool.rrGitServer.port" . }}
{{- $gitServerValues := .Values.rrGitServer.separate }}
apiVersion: v1
kind: Service
metadata:
name: {{ template "retool.rrGitServer.name" . }}
labels:
{{- include "retool.labels" . | nindent 4 }}
{{- with $gitServerValues.labels }}
{{- range $key, $value := . }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
{{- with $gitServerValues.annotations }}
annotations:
{{- range $key, $value := . }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
spec:
selector:
retoolService: {{ template "retool.rrGitServer.name" . }}
ports:
- name: http-server
protocol: TCP
port: {{ $gitServerPort }}
targetPort: {{ $gitServerPort }}
---

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 No PodDisruptionBudget rendered for git server

Every other multi-replica Retool service (backend, dbconnector, code-executor, js-executor, workflows, workers) renders a PodDisruptionBudget alongside its Deployment. The PR description states "A matching Service (+ PDB) is rendered" but the template ends after the Deployment — there is no PDB block. If this deployment is set to replicaCount: 2 (as the CI test does), a rolling node drain can take down all git-server pods simultaneously with no protection.

Comment on lines +16 to +54
{{- with $gitServerValues.annotations }}
annotations:
{{- range $key, $value := . }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
spec:
selector:
retoolService: {{ template "retool.rrGitServer.name" . }}
ports:
- name: http-server
protocol: TCP
port: {{ $gitServerPort }}
targetPort: {{ $gitServerPort }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "retool.rrGitServer.name" . }}
labels:
{{- include "retool.labels" . | nindent 4 }}
{{- if .Values.deployment.annotations }}
annotations:
{{ toYaml .Values.deployment.annotations | indent 4 }}
{{- end }}
spec:
replicas: {{ $gitServerValues.replicaCount | default 1 }}
selector:
matchLabels:
retoolService: {{ template "retool.rrGitServer.name" . }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
template:
metadata:
annotations:
{{- if .Values.podAnnotations }}
{{ toYaml .Values.podAnnotations | indent 8 }}
{{- end }}
{{- with $gitServerValues.annotations }}
{{ toYaml . | indent 8 }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Same annotations key applied to both the Service and the Pod template

$gitServerValues.annotations (i.e., rrGitServer.separate.annotations) is rendered into metadata.annotations on the Service (lines 16-21) and into the pod template metadata.annotations inside the Deployment (lines 53-55). Annotations for these two resources have different semantics: Service annotations are typically used for cloud load-balancer configuration or external-DNS, while pod annotations are used for things like Prometheus scraping or Vault injection. A user who sets a pod annotation (e.g., prometheus.io/scrape: "true") would also have it land on the Service, and vice versa. Consider splitting this into rrGitServer.separate.podAnnotations and rrGitServer.separate.serviceAnnotations, or at minimum document the dual application.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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