diff --git a/config/channels/in-memory-channel/resources/in-memory-channel.yaml b/config/channels/in-memory-channel/resources/in-memory-channel.yaml index be5a469d060..047af5262bc 100644 --- a/config/channels/in-memory-channel/resources/in-memory-channel.yaml +++ b/config/channels/in-memory-channel/resources/in-memory-channel.yaml @@ -43,7 +43,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). @@ -93,7 +93,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/broker.yaml b/config/core/resources/broker.yaml index c8e3eea5f39..84a99034927 100644 --- a/config/core/resources/broker.yaml +++ b/config/core/resources/broker.yaml @@ -59,7 +59,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/channel.yaml b/config/core/resources/channel.yaml index 4ca65afb239..a694b2374a6 100644 --- a/config/core/resources/channel.yaml +++ b/config/core/resources/channel.yaml @@ -71,7 +71,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). @@ -121,7 +121,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/parallel.yaml b/config/core/resources/parallel.yaml index 492e3f119f4..2d4907916d4 100644 --- a/config/core/resources/parallel.yaml +++ b/config/core/resources/parallel.yaml @@ -57,7 +57,7 @@ spec: - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is - backoffDelay*2^.' + backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff diff --git a/config/core/resources/requestreply.yaml b/config/core/resources/requestreply.yaml index 70d4c8cc3fa..65af2736057 100644 --- a/config/core/resources/requestreply.yaml +++ b/config/core/resources/requestreply.yaml @@ -62,7 +62,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/sequence.yaml b/config/core/resources/sequence.yaml index f0021d89c88..610f93cbba7 100644 --- a/config/core/resources/sequence.yaml +++ b/config/core/resources/sequence.yaml @@ -91,7 +91,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/subscription.yaml b/config/core/resources/subscription.yaml index 71edb78ae03..081003cf608 100644 --- a/config/core/resources/subscription.yaml +++ b/config/core/resources/subscription.yaml @@ -57,7 +57,7 @@ spec: type: object properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/config/core/resources/trigger.yaml b/config/core/resources/trigger.yaml index 712d3cd576b..65677b36aec 100644 --- a/config/core/resources/trigger.yaml +++ b/config/core/resources/trigger.yaml @@ -79,7 +79,7 @@ spec: x-kubernetes-preserve-unknown-fields: true # This is necessary to enable the experimental feature delivery-timeout properties: backoffDelay: - description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^.' + description: 'BackoffDelay is the delay before retrying. More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601 For linear policy, backoff delay is backoffDelay*. For exponential policy, backoff delay is backoffDelay*2^(-1).' type: string backoffPolicy: description: BackoffPolicy is the retry backoff policy (linear, exponential). diff --git a/docs/delivery/README.md b/docs/delivery/README.md index 8026087a156..db2ce59f4ae 100644 --- a/docs/delivery/README.md +++ b/docs/delivery/README.md @@ -99,7 +99,7 @@ type DeliverySpec struct { // - https://en.wikipedia.org/wiki/ISO_8601 // // For linear policy, backoff delay is backoffDelay*. - // For exponential policy, backoff delay is backoffDelay*2^. + // For exponential policy, backoff delay is backoffDelay*2^(-1). // +optional BackoffDelay *string `json:"backoffDelay,omitempty"` } diff --git a/docs/eventing-api.md b/docs/eventing-api.md index e9e7bc425c1..515d7eb3864 100644 --- a/docs/eventing-api.md +++ b/docs/eventing-api.md @@ -479,7 +479,7 @@ More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601

For linear policy, backoff delay is backoffDelay*. -For exponential policy, backoff delay is backoffDelay*2^.

+For exponential policy, backoff delay is backoffDelay*2^(-1).

@@ -1512,7 +1512,7 @@ More information on Duration format: - https://www.iso.org/iso-8601-date-and-time-format.html - https://en.wikipedia.org/wiki/ISO_8601

For linear policy, backoff delay is backoffDelay*. -For exponential policy, backoff delay is backoffDelay*2^.

+For exponential policy, backoff delay is backoffDelay*2^(-1).

diff --git a/pkg/apis/duck/v1/delivery_types.go b/pkg/apis/duck/v1/delivery_types.go index f0fef5fc2ae..a982878cdec 100644 --- a/pkg/apis/duck/v1/delivery_types.go +++ b/pkg/apis/duck/v1/delivery_types.go @@ -58,7 +58,7 @@ type DeliverySpec struct { // - https://en.wikipedia.org/wiki/ISO_8601 // // For linear policy, backoff delay is backoffDelay*. - // For exponential policy, backoff delay is backoffDelay*2^. + // For exponential policy, backoff delay is backoffDelay*2^(-1). // +optional BackoffDelay *string `json:"backoffDelay,omitempty"` diff --git a/pkg/apis/duck/v1beta1/delivery_types.go b/pkg/apis/duck/v1beta1/delivery_types.go index 7a444fc0e0e..fcdb8e8cf96 100644 --- a/pkg/apis/duck/v1beta1/delivery_types.go +++ b/pkg/apis/duck/v1beta1/delivery_types.go @@ -55,7 +55,7 @@ type DeliverySpec struct { // - https://en.wikipedia.org/wiki/ISO_8601 // // For linear policy, backoff delay is backoffDelay*. - // For exponential policy, backoff delay is backoffDelay*2^. + // For exponential policy, backoff delay is backoffDelay*2^(-1). // +optional BackoffDelay *string `json:"backoffDelay,omitempty"` } diff --git a/pkg/kncloudevents/retries.go b/pkg/kncloudevents/retries.go index c6199917aeb..05560293b22 100644 --- a/pkg/kncloudevents/retries.go +++ b/pkg/kncloudevents/retries.go @@ -162,17 +162,17 @@ func saturatingPeriodDuration(p period.Period) time.Duration { } func linearBackoff(delay time.Duration, attemptNum int, configuredMax *time.Duration) time.Duration { - if attemptNum <= 0 || delay <= 0 { + if attemptNum < 0 || delay <= 0 { return 0 } limit := maxBackoffDuration if configuredMax != nil { limit = *configuredMax } - if delay >= limit || time.Duration(attemptNum) > limit/delay { + if delay >= limit || time.Duration(attemptNum) >= limit/delay { return limit } - return delay * time.Duration(attemptNum) + return delay * (time.Duration(attemptNum) + 1) } func exponentialBackoff(delay time.Duration, attemptNum int, configuredMax *time.Duration) time.Duration { diff --git a/pkg/kncloudevents/retries_test.go b/pkg/kncloudevents/retries_test.go index f7d29cede2a..8b967059010 100644 --- a/pkg/kncloudevents/retries_test.go +++ b/pkg/kncloudevents/retries_test.go @@ -76,7 +76,7 @@ func TestRetryConfigBackoffMax(t *testing.T) { policy: linear, delay: "PT3S", backoffMax: ptr.String("PT10S"), - attempts: []int{1, 2, 3, 4, int(^uint(0) >> 1)}, + attempts: []int{0, 1, 2, 3, int(^uint(0) >> 1)}, wantBackoffs: []time.Duration{ 3 * time.Second, 6 * time.Second, @@ -110,7 +110,7 @@ func TestRetryConfigBackoffMax(t *testing.T) { name: "uncapped linear saturates", policy: linear, delay: "PT1S", - attempts: []int{1, int(^uint(0) >> 1)}, + attempts: []int{0, int(^uint(0) >> 1)}, wantBackoffs: []time.Duration{time.Second, maxBackoffDuration}, }, { @@ -189,6 +189,7 @@ func TestRetryConfigBackoffMax(t *testing.T) { func TestDoWithRetriesBackoffMax(t *testing.T) { tests := []struct { name string + policy v1.BackoffPolicyType delay string backoffMax *string retryAfter string @@ -197,38 +198,61 @@ func TestDoWithRetriesBackoffMax(t *testing.T) { }{ { name: "exponential backoff is capped", + policy: v1.BackoffPolicyExponential, delay: "PT1S", backoffMax: ptr.String("PT2S"), wantTimes: []time.Duration{0, time.Second, 3 * time.Second, 5 * time.Second, 7 * time.Second}, }, { name: "exponential backoff without a maximum", + policy: v1.BackoffPolicyExponential, delay: "PT1S", wantTimes: []time.Duration{0, time.Second, 3 * time.Second, 7 * time.Second, 15 * time.Second}, }, { name: "maximum below the initial delay", + policy: v1.BackoffPolicyExponential, delay: "PT3S", backoffMax: ptr.String("PT2S"), wantTimes: []time.Duration{0, 2 * time.Second, 4 * time.Second, 6 * time.Second, 8 * time.Second}, }, { name: "retry after can exceed the backoff maximum", + policy: v1.BackoffPolicyExponential, delay: "PT1S", backoffMax: ptr.String("PT2S"), retryAfter: "3", retryAfterMax: ptr.String("PT5S"), wantTimes: []time.Duration{0, 3 * time.Second, 6 * time.Second, 9 * time.Second, 12 * time.Second}, }, + { + name: "linear backoff waits one delay before the first retry", + policy: v1.BackoffPolicyLinear, + delay: "PT1S", + wantTimes: []time.Duration{0, time.Second, 3 * time.Second, 6 * time.Second, 10 * time.Second}, + }, + { + name: "linear backoff is capped", + policy: v1.BackoffPolicyLinear, + delay: "PT1S", + backoffMax: ptr.String("PT2S"), + wantTimes: []time.Duration{0, time.Second, 3 * time.Second, 5 * time.Second, 7 * time.Second}, + }, + { + name: "linear maximum below the initial delay", + policy: v1.BackoffPolicyLinear, + delay: "PT3S", + backoffMax: ptr.String("PT2S"), + wantTimes: []time.Duration{0, 2 * time.Second, 4 * time.Second, 6 * time.Second, 8 * time.Second}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { synctest.Test(t, func(t *testing.T) { - policy := v1.BackoffPolicyExponential config, err := RetryConfigFromDeliverySpec(v1.DeliverySpec{ Retry: ptr.Int32(4), - BackoffPolicy: &policy, + BackoffPolicy: &tt.policy, BackoffDelay: &tt.delay, BackoffMax: tt.backoffMax, RetryAfterMax: tt.retryAfterMax, @@ -328,22 +352,22 @@ func TestRetryConfigFromDeliverySpec(t *testing.T) { backoffPolicy: v1.BackoffPolicyExponential, backoffDelay: "PT1.5S", expectedBackoffDurations: []time.Duration{ + 1500 * time.Millisecond, 3 * time.Second, 6 * time.Second, 12 * time.Second, 24 * time.Second, - 48 * time.Second, }, }, { name: "Successful Exponential Backoff 500ms, 5 retries", backoffPolicy: v1.BackoffPolicyExponential, backoffDelay: "PT0.5S", expectedBackoffDurations: []time.Duration{ + 500 * time.Millisecond, 1 * time.Second, 2 * time.Second, 4 * time.Second, 8 * time.Second, - 16 * time.Second, }, }, { name: "Invalid Backoff Delay", @@ -356,11 +380,11 @@ func TestRetryConfigFromDeliverySpec(t *testing.T) { backoffDelay: "PT0.5S", timeout: &validISO8601DurationString, expectedBackoffDurations: []time.Duration{ + 500 * time.Millisecond, 1 * time.Second, 2 * time.Second, 4 * time.Second, 8 * time.Second, - 16 * time.Second, }, }, { name: "Invalid Timeout", @@ -374,11 +398,11 @@ func TestRetryConfigFromDeliverySpec(t *testing.T) { backoffDelay: "PT0.5S", retryAfterMax: &validISO8601DurationString, expectedBackoffDurations: []time.Duration{ + 500 * time.Millisecond, 1 * time.Second, 2 * time.Second, 4 * time.Second, 8 * time.Second, - 16 * time.Second, }, }, { name: "Invalid RetryAfterMax", @@ -422,8 +446,8 @@ func TestRetryConfigFromDeliverySpec(t *testing.T) { assert.Nil(t, retryConfig.RetryAfterMaxDuration) } - for i := 1; i < retry; i++ { - expectedBackoffDuration := tc.expectedBackoffDurations[i-1] + for i := 0; i < retry; i++ { + expectedBackoffDuration := tc.expectedBackoffDurations[i] actualBackoffDuration := retryConfig.Backoff(i, nil) assert.Equal(t, expectedBackoffDuration, actualBackoffDuration) } diff --git a/pkg/reconciler/inmemorychannel/dispatcher/inmemorychannel_test.go b/pkg/reconciler/inmemorychannel/dispatcher/inmemorychannel_test.go index c0fdca8ddd1..ca70f789504 100644 --- a/pkg/reconciler/inmemorychannel/dispatcher/inmemorychannel_test.go +++ b/pkg/reconciler/inmemorychannel/dispatcher/inmemorychannel_test.go @@ -553,7 +553,8 @@ func TestReconciler_ReconcileKind(t *testing.T) { WithInMemoryChannelEventPoliciesReady()), subs: []fanout.Subscription{*previousSubscription}, wantBackoffs: map[int]time.Duration{ - 3: 3 * time.Second, + 0: 1 * time.Second, + 2: 3 * time.Second, 20: 10 * time.Second, }, wantSubs: []fanout.Subscription{{