diff --git a/chart/templates/s3proxy/deployment.yaml b/chart/templates/s3proxy/deployment.yaml index 87f58f5..c01169f 100644 --- a/chart/templates/s3proxy/deployment.yaml +++ b/chart/templates/s3proxy/deployment.yaml @@ -95,9 +95,18 @@ spec: runAsUser: 1000 readOnlyRootFilesystem: true allowPrivilegeEscalation: false + # Drain on scale-in: the sleep keeps the pod accepting while it drops + # out of the headless-service DNS (HAProxy stops routing new + # connections), then SIGTERM lets uvicorn finish in-flight requests. + # Killing a pod mid-UploadPart/UploadPartCopy orphans multipart state + # and the client's CompleteMultipartUpload fails with InvalidPart. + lifecycle: + preStop: + exec: + command: ["sleep", "10"] securityContext: fsGroup: 1000 - terminationGracePeriodSeconds: 30 + terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/chart/values.yaml b/chart/values.yaml index 441ddb9..da27f30 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -152,6 +152,13 @@ resources: cpu: "500m" memory: "512Mi" +# Must cover the longest single request: one large UploadPart/UploadPartCopy +# can run for minutes against a slow backend, and cutting it off mid-flight +# orphans multipart state (InvalidPart on complete). uvicorn exits as soon as +# in-flight requests finish, so a generous ceiling costs nothing in the +# common case. +terminationGracePeriodSeconds: 600 + # s3proxy container probes. Overridable so deployments can tolerate a busy # single event loop: under heavy upload load a probe can take seconds to be # served, and a tight liveness timeout restarts a live pod (drops in-flight