From c1b254e69f9b488ac82cb09f8600d7504593f90b Mon Sep 17 00:00:00 2001 From: Gurkan Gul Date: Thu, 12 Nov 2026 10:47:13 +0300 Subject: [PATCH] feat(executor): make the maintenance interval configurable The executor's maintenance pass, which removes idle runtimes, ran every 3600 seconds because the chart hard-coded OPR_EXECUTOR_MAINTENANCE_INTERVAL. Add compute.executor.maintenanceInterval (3600 by default, so the rendered values don't change) and document it, with the tests and the chart README, values.schema.json and changelog entry that go with it. --- CHANGELOG.md | 4 ++++ charts/appwrite/README.md | 3 ++- charts/appwrite/templates/executor/deployment.yaml | 2 +- charts/appwrite/tests/executor_test.yaml | 12 ++++++++++++ charts/appwrite/values.schema.json | 7 ++++++- charts/appwrite/values.yaml | 8 +++++--- docs/executor.md | 7 ++++--- 7 files changed, 34 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fff3ed..5dd049d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,10 @@ annotation in `charts/appwrite/Chart.yaml`. ### Added +- `compute.executor.maintenanceInterval` sets how often the executor's + maintenance pass removes idle runtimes (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`, + 3600 seconds by default, as before), so a lower interval frees their memory + sooner. - The render fails when `compute.secrets.orchestratorSecret` is Appwrite's placeholder `your-secret-key`, which Appwrite 2.6.2 refuses for job callbacks, unless `compute.secrets.existingSecret` supplies the secret diff --git a/charts/appwrite/README.md b/charts/appwrite/README.md index 42de5fe..ea39216 100644 --- a/charts/appwrite/README.md +++ b/charts/appwrite/README.md @@ -905,7 +905,8 @@ The build orchestrator and the executor. | compute.executor.image.repository | string | `"openruntimes/executor"` | Image repository. | | compute.executor.image.tag | string | `"1.3.3"` | Image tag. | | compute.executor.images | list | `[]` | Runtime images to pull when the executor starts (`OPR_EXECUTOR_IMAGES`). Empty derives them from `functionsRuntimes` and `sitesRuntimes`, e.g. `node-22` becomes `openruntimes/node:v5-22`; with both of those empty too, nothing is pulled ahead of the first executions. | -| compute.executor.inactiveThreshold | int | `60` | Seconds a runtime may stay idle before it's removed (`OPR_EXECUTOR_INACTIVE_THRESHOLD`). The executor removes idle runtimes in its maintenance pass, which the chart runs hourly (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`), so a runtime can stay up to an hour longer. | +| compute.executor.inactiveThreshold | int | `60` | Seconds a runtime may stay idle before it's removed (`OPR_EXECUTOR_INACTIVE_THRESHOLD`). The executor removes idle runtimes in its maintenance pass, so a runtime can stay up to one `maintenanceInterval` longer. | +| compute.executor.maintenanceInterval | int | `3600` | Seconds between the executor's maintenance passes, which remove idle runtimes (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`). | | compute.executor.namespace | string | `""` | Namespace of the executor. Defaults to `-executor`. Use a different one per release when several releases share a namespace. | | compute.executor.networkPolicy.deniedCIDRs | list | `[]` | CIDRs executor pods may not reach, on top of the private, link-local, CGNAT and special-purpose ranges always blocked. | | compute.executor.networkPolicy.enabled | bool | `true` | Restrict executor pods' traffic: incoming only from Appwrite pods of this release; outgoing (which includes every runtime) only to DNS, the S3 endpoint and public addresses. Takes effect only with a CNI that enforces NetworkPolicies. | diff --git a/charts/appwrite/templates/executor/deployment.yaml b/charts/appwrite/templates/executor/deployment.yaml index 53533ec..0bcf228 100644 --- a/charts/appwrite/templates/executor/deployment.yaml +++ b/charts/appwrite/templates/executor/deployment.yaml @@ -169,7 +169,7 @@ spec: - name: OPR_EXECUTOR_INACTIVE_THRESHOLD value: {{ include "appwrite.envValue" $e.inactiveThreshold | quote }} - name: OPR_EXECUTOR_MAINTENANCE_INTERVAL - value: "3600" + value: {{ include "appwrite.envValue" $e.maintenanceInterval | quote }} {{- with $e.extraEnv }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/appwrite/tests/executor_test.yaml b/charts/appwrite/tests/executor_test.yaml index 1df73a3..3606365 100644 --- a/charts/appwrite/tests/executor_test.yaml +++ b/charts/appwrite/tests/executor_test.yaml @@ -220,6 +220,9 @@ tests: - contains: path: spec.template.spec.containers[0].env content: {name: OPR_EXECUTOR_INACTIVE_THRESHOLD, value: "60"} + - contains: + path: spec.template.spec.containers[0].env + content: {name: OPR_EXECUTOR_MAINTENANCE_INTERVAL, value: "3600"} - contains: path: spec.template.spec.containers[0].env content: @@ -227,6 +230,15 @@ tests: valueFrom: secretKeyRef: {name: aw-appwrite-executor, key: s3-secret-key} + - it: takes a maintenance interval of your own + template: templates/executor/deployment.yaml + set: + compute.executor.maintenanceInterval: 60 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: {name: OPR_EXECUTOR_MAINTENANCE_INTERVAL, value: "60"} + - it: pulls the runtime images you list template: templates/executor/deployment.yaml set: diff --git a/charts/appwrite/values.schema.json b/charts/appwrite/values.schema.json index 2517115..ab1a7fb 100644 --- a/charts/appwrite/values.schema.json +++ b/charts/appwrite/values.schema.json @@ -1326,9 +1326,14 @@ } }, "inactiveThreshold": { - "description": "Seconds a runtime may stay idle before it's removed (`OPR_EXECUTOR_INACTIVE_THRESHOLD`). The executor removes idle runtimes in its maintenance pass, which the chart runs hourly (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`), so a runtime can stay up to an hour longer.", + "description": "Seconds a runtime may stay idle before it's removed (`OPR_EXECUTOR_INACTIVE_THRESHOLD`). The executor removes idle runtimes in its maintenance pass, so a runtime can stay up to one `maintenanceInterval` longer.", "type": "integer" }, + "maintenanceInterval": { + "description": "Seconds between the executor's maintenance passes, which remove idle runtimes (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`).", + "type": "integer", + "minimum": 1 + }, "namespace": { "description": "Namespace of the executor. Defaults to `-executor`. Use a different one per release when several releases share a namespace.", "type": "string" diff --git a/charts/appwrite/values.yaml b/charts/appwrite/values.yaml index 03639f5..6d04a9e 100644 --- a/charts/appwrite/values.yaml +++ b/charts/appwrite/values.yaml @@ -896,10 +896,12 @@ compute: memory: 4Gi # -- Seconds a runtime may stay idle before it's removed # (`OPR_EXECUTOR_INACTIVE_THRESHOLD`). The executor removes idle runtimes - # in its maintenance pass, which the chart runs hourly - # (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`), so a runtime can stay up to an - # hour longer. + # in its maintenance pass, so a runtime can stay up to one + # `maintenanceInterval` longer. inactiveThreshold: 60 + # -- Seconds between the executor's maintenance passes, which remove idle + # runtimes (`OPR_EXECUTOR_MAINTENANCE_INTERVAL`). + maintenanceInterval: 3600 # @schema minimum: 1 # -- Runtime images to pull when the executor starts (`OPR_EXECUTOR_IMAGES`). # Empty derives them from `functionsRuntimes` and `sitesRuntimes`, e.g. # `node-22` becomes `openruntimes/node:v5-22`; with both of those empty diff --git a/docs/executor.md b/docs/executor.md index 4ecf3a1..9e2d16b 100644 --- a/docs/executor.md +++ b/docs/executor.md @@ -334,10 +334,11 @@ Set them before users create functions and sites: existing ones keep the specification they have. Then size the `dind` limits for the runtimes you expect at once. -Runtimes stay warm after use. The executor checks for idle runtimes once an -hour and removes those idle for longer than +Runtimes stay warm after use. The executor checks for idle runtimes every +`compute.executor.maintenanceInterval` seconds (3600, an hour, by default) +and removes those idle for longer than `compute.executor.inactiveThreshold` seconds (60 by default), so an idle -runtime holds its memory for up to an hour. +runtime holds its memory for up to one interval longer than that. `compute.executor.replicaCount` (1 by default) adds executor pods, each with its own daemon, spread across nodes where possible. Appwrite calls the