syntax = "proto3";

package envoy.config.retry.previous_priorities;

import "udpa/annotations/migrate.proto";
import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.config.retry.previous_priorities";
option java_outer_classname = "PreviousPrioritiesConfigProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/config/retry/previous_priorities";
option (udpa.annotations.file_migrate).move_to_package =
    "envoy.extensions.retry.priority.previous_priorities.v3";
option (udpa.annotations.file_status).package_version_status = FROZEN;

// [#protodoc-title: Previous priorities retry selector]

// A retry host selector that attempts to spread retries between priorities, even if certain
// priorities would not normally be attempted due to higher priorities being available.
//
// As priorities get excluded, load will be distributed amongst the remaining healthy priorities
// based on the relative health of the priorities, matching how load is distributed during regular
// host selection. For example, given priority healths of {100, 50, 50}, the original load will be
// {100, 0, 0} (since P0 has capacity to handle 100% of the traffic). If P0 is excluded, the load
// changes to {0, 50, 50}, because P1 is only able to handle 50% of the traffic, causing the
// remaining to spill over to P2.
//
// Each priority attempted will be excluded until there are no healthy priorities left, at which
// point the list of attempted priorities will be reset, essentially starting from the beginning.
// For example, given three priorities P0, P1, P2 with healthy % of 100, 0 and 50 respectively, the
// following sequence of priorities would be selected (assuming update_frequency = 1):
// Attempt 1: P0 (P0 is 100% healthy)
// Attempt 2: P2 (P0 already attempted, P2 only healthy priority)
// Attempt 3: P0 (no healthy priorities, reset)
// Attempt 4: P2
//
// In the case of all upstream hosts being unhealthy, no adjustments will be made to the original
// priority load, so behavior should be identical to not using this plugin.
//
// Using this PriorityFilter requires rebuilding the priority load, which runs in O(# of
// priorities), which might incur significant overhead for clusters with many priorities.
// [#extension: envoy.retry_priorities.previous_priorities]
message PreviousPrioritiesConfig {
  // How often the priority load should be updated based on previously attempted priorities. Useful
  // to allow each priorities to receive more than one request before being excluded or to reduce
  // the number of times that the priority load has to be recomputed.
  //
  // For example, by setting this to 2, then the first two attempts (initial attempt and first
  // retry) will use the unmodified priority load. The third and fourth attempt will use priority
  // load which excludes the priorities routed to with the first two attempts, and the fifth and
  // sixth attempt will use the priority load excluding the priorities used for the first four
  // attempts.
  //
  // Must be greater than 0.
  int32 update_frequency = 1 [(validate.rules).int32 = {gt: 0}];
}
