diff --git a/api/v1/coherence_types.go b/api/v1/coherence_types.go index 3876788c..c77c0371 100644 --- a/api/v1/coherence_types.go +++ b/api/v1/coherence_types.go @@ -2320,6 +2320,19 @@ type ReadinessProbeSpec struct { // Minimum consecutive failures for the probe to be considered failed after having succeeded. // +optional FailureThreshold *int32 `json:"failureThreshold,omitempty"` + // TerminationGracePeriodSeconds is the optional duration in seconds the pod needs to terminate gracefully + // upon probe failure. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + // value overrides the value provided by the pod spec. + // Value must be non-negative integer. The value zero indicates stop immediately via + // the kill signal (no opportunity to shut down). + // This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + // The minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + // +optional + TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` } // ProbeHandler is the definition of a probe handler. @@ -2371,6 +2384,7 @@ func (in *ReadinessProbeSpec) UpdateProbeSpec(port int32, path string, probe *co if in.TimeoutSeconds != nil { probe.TimeoutSeconds = *in.TimeoutSeconds } + probe.TerminationGracePeriodSeconds = in.TerminationGracePeriodSeconds } } diff --git a/api/v1/coherenceresource_types.go b/api/v1/coherenceresource_types.go index 2901e2db..66a53a72 100644 --- a/api/v1/coherenceresource_types.go +++ b/api/v1/coherenceresource_types.go @@ -677,6 +677,7 @@ func (in *CoherenceStatefulSetResourceSpec) CreateStatefulSet(deployment *Cohere sts.Labels[LabelComponent] = LabelComponentCoherenceStatefulSet sts.Spec = appsv1.StatefulSetSpec{ Replicas: &replicas, + MinReadySeconds: in.GetMinReadySeconds(), PodManagementPolicy: appsv1.ParallelPodManagement, UpdateStrategy: updateStrategy, RevisionHistoryLimit: ptr.To(int32(5)), diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 6aa3ad83..c0b61dc0 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -290,6 +290,11 @@ type CoherenceResourceSpec struct { // Cannot be updated. // +optional Lifecycle *corev1.Lifecycle `json:"lifecycle,omitempty"` + // Minimum number of seconds for which a newly created pod should be ready + // without any of its container crashing for it to be considered available. + // Defaults to 0 (pod will be considered available as soon as it is ready) + // +optional + MinReadySeconds *int32 `json:"minReadySeconds,omitempty"` } // Action is an action to execute when the StatefulSet becomes ready. @@ -399,6 +404,15 @@ func (in *CoherenceResourceSpec) GetDefaultScalingProbe() *Probe { return probe.DeepCopy() } +// GetMinReadySeconds returns the minReadySeconds value or zero if +// minReadySeconds is not configured. +func (in *CoherenceResourceSpec) GetMinReadySeconds() int32 { + if in == nil || in.MinReadySeconds == nil { + return 0 + } + return *in.MinReadySeconds +} + // GetCoherencePersistence returns the Coherence PersistenceSpec or nil if // persistence is not configured. func (in *CoherenceResourceSpec) GetCoherencePersistence() *PersistenceSpec { diff --git a/api/v1/create_statefulset_probes_test.go b/api/v1/create_statefulset_probes_test.go index f9a0ee9a..505f3d9b 100644 --- a/api/v1/create_statefulset_probes_test.go +++ b/api/v1/create_statefulset_probes_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Licensed under the Universal Permissive License v 1.0 as shown at * http://oss.oracle.com/licenses/upl. */ @@ -10,6 +10,7 @@ import ( coh "github.com/oracle/coherence-operator/api/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" "testing" ) @@ -37,11 +38,12 @@ func TestCreateStatefulSetWithEmptyReadinessProbeSpec(t *testing.T) { func TestCreateStatefulSetWithReadinessProbeSpec(t *testing.T) { probe := coh.ReadinessProbeSpec{ - InitialDelaySeconds: int32Ptr(10), - TimeoutSeconds: int32Ptr(20), - PeriodSeconds: int32Ptr(30), - SuccessThreshold: int32Ptr(40), - FailureThreshold: int32Ptr(50), + InitialDelaySeconds: int32Ptr(10), + TimeoutSeconds: int32Ptr(20), + PeriodSeconds: int32Ptr(30), + SuccessThreshold: int32Ptr(40), + FailureThreshold: int32Ptr(50), + TerminationGracePeriodSeconds: ptr.To(int64(1234)), } spec := coh.CoherenceResourceSpec{ @@ -62,11 +64,12 @@ func TestCreateStatefulSetWithReadinessProbeSpec(t *testing.T) { }, TCPSocket: nil, }, - InitialDelaySeconds: 10, - TimeoutSeconds: 20, - PeriodSeconds: 30, - SuccessThreshold: 40, - FailureThreshold: 50, + InitialDelaySeconds: 10, + TimeoutSeconds: 20, + PeriodSeconds: 30, + SuccessThreshold: 40, + FailureThreshold: 50, + TerminationGracePeriodSeconds: ptr.To(int64(1234)), } // assert that the StatefulSet is as expected diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index d0298955..d9bc53ac 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -797,3 +797,33 @@ func TestCreateStatefulUsingJava8(t *testing.T) { // assert that the StatefulSet is as expected assertStatefulSetCreation(t, deployment, stsExpected) } + +func TestCreateStatefulSetWithMinReadySeconds(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + MinReadySeconds: ptr.To(int32(19)), + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.MinReadySeconds = 19 + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + +func TestCreateStatefulSetWithMinReadySecondsSetToZero(t *testing.T) { + spec := coh.CoherenceResourceSpec{ + MinReadySeconds: ptr.To(int32(0)), + } + + // Create the test deployment + deployment := createTestDeployment(spec) + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.MinReadySeconds = 0 + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +}