diff --git a/packages/grpc-js-xds/gulpfile.ts b/packages/grpc-js-xds/gulpfile.ts index 5f5d9dfc3..9c9f295c6 100644 --- a/packages/grpc-js-xds/gulpfile.ts +++ b/packages/grpc-js-xds/gulpfile.ts @@ -72,6 +72,7 @@ const runTests = checkTask(() => { process.env.GRPC_EXPERIMENTAL_XDS_FEDERATION = 'true'; process.env.GRPC_EXPERIMENTAL_PICKFIRST_LB_CONFIG = 'true'; process.env.GRPC_XDS_EXPERIMENTAL_RBAC = 'true'; + process.env.GRPC_EXPERIMENTAL_XDS_WRR_LB = 'true'; if (Number(process.versions.node.split('.')[0]) <= 14) { process.env.GRPC_XDS_EXPERIMENTAL_ENABLE_RING_HASH = 'false'; } diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index dda1c043d..110576bcb 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run generate-types && npm run generate-interop-types && npm run generate-test-types && npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto envoy/extensions/clusters/aggregate/v3/cluster.proto envoy/extensions/transport_sockets/tls/v3/tls.proto envoy/config/rbac/v3/rbac.proto envoy/extensions/filters/http/rbac/v3/rbac.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto envoy/extensions/clusters/aggregate/v3/cluster.proto envoy/extensions/transport_sockets/tls/v3/tls.proto envoy/config/rbac/v3/rbac.proto envoy/extensions/filters/http/rbac/v3/rbac.proto envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto", "generate-test-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O test/generated --grpcLib @grpc/grpc-js grpc/testing/echo.proto" }, diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index a7770776d..39ba2028d 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -28,3 +28,4 @@ export const EXPERIMENTAL_PICK_FIRST = (process.env.GRPC_EXPERIMENTAL_PICKFIRST_ export const EXPERIMENTAL_DUALSTACK_ENDPOINTS = (process.env.GRPC_EXPERIMENTAL_XDS_DUALSTACK_ENDPOINTS ?? 'true') === 'true'; export const AGGREGATE_CLUSTER_BACKWARDS_COMPAT = (process.env.GRPC_XDS_AGGREGATE_CLUSTER_BACKWARD_COMPAT ?? 'false') === 'true'; export const EXPERIMENTAL_RBAC = (process.env.GRPC_XDS_EXPERIMENTAL_RBAC ?? 'false') === 'true'; +export const EXPERIMENTAL_WRR_LB = (process.env.GRPC_EXPERIMENTAL_XDS_WRR_LB ?? 'false') === 'true'; diff --git a/packages/grpc-js-xds/src/generated/client_side_weighted_round_robin.ts b/packages/grpc-js-xds/src/generated/client_side_weighted_round_robin.ts new file mode 100644 index 000000000..bf89c6cf2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/client_side_weighted_round_robin.ts @@ -0,0 +1,153 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import type { ClientSideWeightedRoundRobin as _envoy_extensions_load_balancing_policies_client_side_weighted_round_robin_v3_ClientSideWeightedRoundRobin, ClientSideWeightedRoundRobin__Output as _envoy_extensions_load_balancing_policies_client_side_weighted_round_robin_v3_ClientSideWeightedRoundRobin__Output } from './envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import type { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import type { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import type { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import type { ExtensionRangeOptions as _google_protobuf_ExtensionRangeOptions, ExtensionRangeOptions__Output as _google_protobuf_ExtensionRangeOptions__Output } from './google/protobuf/ExtensionRangeOptions'; +import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from './google/protobuf/FeatureSet'; +import type { FeatureSetDefaults as _google_protobuf_FeatureSetDefaults, FeatureSetDefaults__Output as _google_protobuf_FeatureSetDefaults__Output } from './google/protobuf/FeatureSetDefaults'; +import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import type { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import type { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import type { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import type { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import type { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import type { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import type { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import type { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import type { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import type { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import type { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import type { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import type { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import type { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import type { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import type { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import type { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import type { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import type { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import type { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import type { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import type { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import type { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import type { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import type { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import type { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import type { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import type { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import type { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import type { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import type { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import type { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import type { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import type { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import type { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import type { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import type { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + extensions: { + load_balancing_policies: { + client_side_weighted_round_robin: { + v3: { + ClientSideWeightedRoundRobin: MessageTypeDefinition<_envoy_extensions_load_balancing_policies_client_side_weighted_round_robin_v3_ClientSideWeightedRoundRobin, _envoy_extensions_load_balancing_policies_client_side_weighted_round_robin_v3_ClientSideWeightedRoundRobin__Output> + } + } + } + } + } + google: { + protobuf: { + BoolValue: MessageTypeDefinition<_google_protobuf_BoolValue, _google_protobuf_BoolValue__Output> + BytesValue: MessageTypeDefinition<_google_protobuf_BytesValue, _google_protobuf_BytesValue__Output> + DescriptorProto: MessageTypeDefinition<_google_protobuf_DescriptorProto, _google_protobuf_DescriptorProto__Output> + DoubleValue: MessageTypeDefinition<_google_protobuf_DoubleValue, _google_protobuf_DoubleValue__Output> + Duration: MessageTypeDefinition<_google_protobuf_Duration, _google_protobuf_Duration__Output> + Edition: EnumTypeDefinition + EnumDescriptorProto: MessageTypeDefinition<_google_protobuf_EnumDescriptorProto, _google_protobuf_EnumDescriptorProto__Output> + EnumOptions: MessageTypeDefinition<_google_protobuf_EnumOptions, _google_protobuf_EnumOptions__Output> + EnumValueDescriptorProto: MessageTypeDefinition<_google_protobuf_EnumValueDescriptorProto, _google_protobuf_EnumValueDescriptorProto__Output> + EnumValueOptions: MessageTypeDefinition<_google_protobuf_EnumValueOptions, _google_protobuf_EnumValueOptions__Output> + ExtensionRangeOptions: MessageTypeDefinition<_google_protobuf_ExtensionRangeOptions, _google_protobuf_ExtensionRangeOptions__Output> + FeatureSet: MessageTypeDefinition<_google_protobuf_FeatureSet, _google_protobuf_FeatureSet__Output> + FeatureSetDefaults: MessageTypeDefinition<_google_protobuf_FeatureSetDefaults, _google_protobuf_FeatureSetDefaults__Output> + FieldDescriptorProto: MessageTypeDefinition<_google_protobuf_FieldDescriptorProto, _google_protobuf_FieldDescriptorProto__Output> + FieldOptions: MessageTypeDefinition<_google_protobuf_FieldOptions, _google_protobuf_FieldOptions__Output> + FileDescriptorProto: MessageTypeDefinition<_google_protobuf_FileDescriptorProto, _google_protobuf_FileDescriptorProto__Output> + FileDescriptorSet: MessageTypeDefinition<_google_protobuf_FileDescriptorSet, _google_protobuf_FileDescriptorSet__Output> + FileOptions: MessageTypeDefinition<_google_protobuf_FileOptions, _google_protobuf_FileOptions__Output> + FloatValue: MessageTypeDefinition<_google_protobuf_FloatValue, _google_protobuf_FloatValue__Output> + GeneratedCodeInfo: MessageTypeDefinition<_google_protobuf_GeneratedCodeInfo, _google_protobuf_GeneratedCodeInfo__Output> + Int32Value: MessageTypeDefinition<_google_protobuf_Int32Value, _google_protobuf_Int32Value__Output> + Int64Value: MessageTypeDefinition<_google_protobuf_Int64Value, _google_protobuf_Int64Value__Output> + MessageOptions: MessageTypeDefinition<_google_protobuf_MessageOptions, _google_protobuf_MessageOptions__Output> + MethodDescriptorProto: MessageTypeDefinition<_google_protobuf_MethodDescriptorProto, _google_protobuf_MethodDescriptorProto__Output> + MethodOptions: MessageTypeDefinition<_google_protobuf_MethodOptions, _google_protobuf_MethodOptions__Output> + OneofDescriptorProto: MessageTypeDefinition<_google_protobuf_OneofDescriptorProto, _google_protobuf_OneofDescriptorProto__Output> + OneofOptions: MessageTypeDefinition<_google_protobuf_OneofOptions, _google_protobuf_OneofOptions__Output> + ServiceDescriptorProto: MessageTypeDefinition<_google_protobuf_ServiceDescriptorProto, _google_protobuf_ServiceDescriptorProto__Output> + ServiceOptions: MessageTypeDefinition<_google_protobuf_ServiceOptions, _google_protobuf_ServiceOptions__Output> + SourceCodeInfo: MessageTypeDefinition<_google_protobuf_SourceCodeInfo, _google_protobuf_SourceCodeInfo__Output> + StringValue: MessageTypeDefinition<_google_protobuf_StringValue, _google_protobuf_StringValue__Output> + SymbolVisibility: EnumTypeDefinition + Timestamp: MessageTypeDefinition<_google_protobuf_Timestamp, _google_protobuf_Timestamp__Output> + UInt32Value: MessageTypeDefinition<_google_protobuf_UInt32Value, _google_protobuf_UInt32Value__Output> + UInt64Value: MessageTypeDefinition<_google_protobuf_UInt64Value, _google_protobuf_UInt64Value__Output> + UninterpretedOption: MessageTypeDefinition<_google_protobuf_UninterpretedOption, _google_protobuf_UninterpretedOption__Output> + } + } + udpa: { + annotations: { + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition<_udpa_annotations_StatusAnnotation, _udpa_annotations_StatusAnnotation__Output> + } + } + validate: { + AnyRules: MessageTypeDefinition<_validate_AnyRules, _validate_AnyRules__Output> + BoolRules: MessageTypeDefinition<_validate_BoolRules, _validate_BoolRules__Output> + BytesRules: MessageTypeDefinition<_validate_BytesRules, _validate_BytesRules__Output> + DoubleRules: MessageTypeDefinition<_validate_DoubleRules, _validate_DoubleRules__Output> + DurationRules: MessageTypeDefinition<_validate_DurationRules, _validate_DurationRules__Output> + EnumRules: MessageTypeDefinition<_validate_EnumRules, _validate_EnumRules__Output> + FieldRules: MessageTypeDefinition<_validate_FieldRules, _validate_FieldRules__Output> + Fixed32Rules: MessageTypeDefinition<_validate_Fixed32Rules, _validate_Fixed32Rules__Output> + Fixed64Rules: MessageTypeDefinition<_validate_Fixed64Rules, _validate_Fixed64Rules__Output> + FloatRules: MessageTypeDefinition<_validate_FloatRules, _validate_FloatRules__Output> + Int32Rules: MessageTypeDefinition<_validate_Int32Rules, _validate_Int32Rules__Output> + Int64Rules: MessageTypeDefinition<_validate_Int64Rules, _validate_Int64Rules__Output> + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition<_validate_MapRules, _validate_MapRules__Output> + MessageRules: MessageTypeDefinition<_validate_MessageRules, _validate_MessageRules__Output> + RepeatedRules: MessageTypeDefinition<_validate_RepeatedRules, _validate_RepeatedRules__Output> + SFixed32Rules: MessageTypeDefinition<_validate_SFixed32Rules, _validate_SFixed32Rules__Output> + SFixed64Rules: MessageTypeDefinition<_validate_SFixed64Rules, _validate_SFixed64Rules__Output> + SInt32Rules: MessageTypeDefinition<_validate_SInt32Rules, _validate_SInt32Rules__Output> + SInt64Rules: MessageTypeDefinition<_validate_SInt64Rules, _validate_SInt64Rules__Output> + StringRules: MessageTypeDefinition<_validate_StringRules, _validate_StringRules__Output> + TimestampRules: MessageTypeDefinition<_validate_TimestampRules, _validate_TimestampRules__Output> + UInt32Rules: MessageTypeDefinition<_validate_UInt32Rules, _validate_UInt32Rules__Output> + UInt64Rules: MessageTypeDefinition<_validate_UInt64Rules, _validate_UInt64Rules__Output> + } +} + diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin.ts new file mode 100644 index 000000000..607ca3a37 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin.ts @@ -0,0 +1,129 @@ +// Original file: deps/envoy-api/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto + +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../google/protobuf/BoolValue'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../google/protobuf/Duration'; +import type { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from '../../../../../google/protobuf/FloatValue'; + +/** + * Configuration for the client_side_weighted_round_robin LB policy. + * + * This policy differs from the built-in ROUND_ROBIN policy in terms of + * how the endpoint weights are determined. In the ROUND_ROBIN policy, + * the endpoint weights are sent by the control plane via EDS. However, + * in this policy, the endpoint weights are instead determined via qps (queries + * per second), eps (errors per second), and utilization metrics sent by the + * endpoint using the Open Request Cost Aggregation (ORCA) protocol. Utilization + * is determined by using the ORCA application_utilization field, if set, or + * else falling back to the cpu_utilization field. All queries count toward qps, + * regardless of result. Only failed queries count toward eps. A config + * parameter error_utilization_penalty controls the penalty to adjust endpoint + * weights using eps and qps. The weight of a given endpoint is computed as: + * qps / (utilization + eps/qps * error_utilization_penalty) + * + * See the :ref:`load balancing architecture overview` for more information. + * + * [#next-free-field: 7] + */ +export interface ClientSideWeightedRoundRobin { + /** + * Whether to enable out-of-band utilization reporting collection from + * the endpoints. By default, per-request utilization reporting is used. + */ + 'enable_oob_load_report'?: (_google_protobuf_BoolValue | null); + /** + * Load reporting interval to request from the server. Note that the + * server may not provide reports as frequently as the client requests. + * Used only when enable_oob_load_report is true. Default is 10 seconds. + */ + 'oob_reporting_period'?: (_google_protobuf_Duration | null); + /** + * A given endpoint must report load metrics continuously for at least + * this long before the endpoint weight will be used. This avoids + * churn when the set of endpoint addresses changes. Takes effect + * both immediately after we establish a connection to an endpoint and + * after weight_expiration_period has caused us to stop using the most + * recent load metrics. Default is 10 seconds. + */ + 'blackout_period'?: (_google_protobuf_Duration | null); + /** + * If a given endpoint has not reported load metrics in this long, + * then we stop using the reported weight. This ensures that we do + * not continue to use very stale weights. Once we stop using a stale + * value, if we later start seeing fresh reports again, the + * blackout_period applies. Defaults to 3 minutes. + */ + 'weight_expiration_period'?: (_google_protobuf_Duration | null); + /** + * How often endpoint weights are recalculated. Values less than 100ms are + * capped at 100ms. Default is 1 second. + */ + 'weight_update_period'?: (_google_protobuf_Duration | null); + /** + * The multiplier used to adjust endpoint weights with the error rate + * calculated as eps/qps. Configuration is rejected if this value is negative. + * Default is 1.0. + */ + 'error_utilization_penalty'?: (_google_protobuf_FloatValue | null); +} + +/** + * Configuration for the client_side_weighted_round_robin LB policy. + * + * This policy differs from the built-in ROUND_ROBIN policy in terms of + * how the endpoint weights are determined. In the ROUND_ROBIN policy, + * the endpoint weights are sent by the control plane via EDS. However, + * in this policy, the endpoint weights are instead determined via qps (queries + * per second), eps (errors per second), and utilization metrics sent by the + * endpoint using the Open Request Cost Aggregation (ORCA) protocol. Utilization + * is determined by using the ORCA application_utilization field, if set, or + * else falling back to the cpu_utilization field. All queries count toward qps, + * regardless of result. Only failed queries count toward eps. A config + * parameter error_utilization_penalty controls the penalty to adjust endpoint + * weights using eps and qps. The weight of a given endpoint is computed as: + * qps / (utilization + eps/qps * error_utilization_penalty) + * + * See the :ref:`load balancing architecture overview` for more information. + * + * [#next-free-field: 7] + */ +export interface ClientSideWeightedRoundRobin__Output { + /** + * Whether to enable out-of-band utilization reporting collection from + * the endpoints. By default, per-request utilization reporting is used. + */ + 'enable_oob_load_report': (_google_protobuf_BoolValue__Output | null); + /** + * Load reporting interval to request from the server. Note that the + * server may not provide reports as frequently as the client requests. + * Used only when enable_oob_load_report is true. Default is 10 seconds. + */ + 'oob_reporting_period': (_google_protobuf_Duration__Output | null); + /** + * A given endpoint must report load metrics continuously for at least + * this long before the endpoint weight will be used. This avoids + * churn when the set of endpoint addresses changes. Takes effect + * both immediately after we establish a connection to an endpoint and + * after weight_expiration_period has caused us to stop using the most + * recent load metrics. Default is 10 seconds. + */ + 'blackout_period': (_google_protobuf_Duration__Output | null); + /** + * If a given endpoint has not reported load metrics in this long, + * then we stop using the reported weight. This ensures that we do + * not continue to use very stale weights. Once we stop using a stale + * value, if we later start seeing fresh reports again, the + * blackout_period applies. Defaults to 3 minutes. + */ + 'weight_expiration_period': (_google_protobuf_Duration__Output | null); + /** + * How often endpoint weights are recalculated. Values less than 100ms are + * capped at 100ms. Default is 1 second. + */ + 'weight_update_period': (_google_protobuf_Duration__Output | null); + /** + * The multiplier used to adjust endpoint weights with the error rate + * calculated as eps/qps. Configuration is rejected if this value is negative. + * Default is 1.0. + */ + 'error_utilization_penalty': (_google_protobuf_FloatValue__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts index 57de00a2b..b8361bab4 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts @@ -2,7 +2,6 @@ import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from '../../google/protobuf/FeatureSet'; import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumOptions { 'allowAlias'?: (boolean); @@ -13,7 +12,6 @@ export interface EnumOptions { 'deprecatedLegacyJsonFieldConflicts'?: (boolean); 'features'?: (_google_protobuf_FeatureSet | null); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation | null); } export interface EnumOptions__Output { @@ -25,5 +23,4 @@ export interface EnumOptions__Output { 'deprecatedLegacyJsonFieldConflicts': (boolean); 'features': (_google_protobuf_FeatureSet__Output | null); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.enum_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts index ee39c7db4..d9290c550 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts @@ -3,7 +3,6 @@ import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from '../../google/protobuf/FeatureSet'; import type { _google_protobuf_FieldOptions_FeatureSupport, _google_protobuf_FieldOptions_FeatureSupport__Output } from '../../google/protobuf/FieldOptions'; import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumValueOptions { 'deprecated'?: (boolean); @@ -11,9 +10,6 @@ export interface EnumValueOptions { 'debugRedact'?: (boolean); 'featureSupport'?: (_google_protobuf_FieldOptions_FeatureSupport | null); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.envoy.annotations.disallowed_by_default_enum'?: (boolean); - '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation | null); - '.envoy.annotations.deprecated_at_minor_version_enum'?: (string); } export interface EnumValueOptions__Output { @@ -22,7 +18,4 @@ export interface EnumValueOptions__Output { 'debugRedact': (boolean); 'featureSupport': (_google_protobuf_FieldOptions_FeatureSupport__Output | null); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.envoy.annotations.disallowed_by_default_enum': (boolean); - '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); - '.envoy.annotations.deprecated_at_minor_version_enum': (string); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 7404c61f0..dc5d85c96 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -3,8 +3,6 @@ import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from '../../google/protobuf/FeatureSet'; import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; -import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; -import type { FieldStatusAnnotation as _xds_annotations_v3_FieldStatusAnnotation, FieldStatusAnnotation__Output as _xds_annotations_v3_FieldStatusAnnotation__Output } from '../../xds/annotations/v3/FieldStatusAnnotation'; import type { Edition as _google_protobuf_Edition, Edition__Output as _google_protobuf_Edition__Output } from '../../google/protobuf/Edition'; // Original file: null @@ -143,10 +141,6 @@ export interface FieldOptions { 'featureSupport'?: (_google_protobuf_FieldOptions_FeatureSupport | null); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules | null); - '.envoy.annotations.deprecated_at_minor_version'?: (string); - '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation | null); - '.envoy.annotations.disallowed_by_default'?: (boolean); - '.xds.annotations.v3.field_status'?: (_xds_annotations_v3_FieldStatusAnnotation | null); } export interface FieldOptions__Output { @@ -168,8 +162,4 @@ export interface FieldOptions__Output { 'featureSupport': (_google_protobuf_FieldOptions_FeatureSupport__Output | null); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules': (_validate_FieldRules__Output | null); - '.envoy.annotations.deprecated_at_minor_version': (string); - '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output | null); - '.envoy.annotations.disallowed_by_default': (boolean); - '.xds.annotations.v3.field_status': (_xds_annotations_v3_FieldStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts index a9fd83af7..3ca371a84 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts @@ -2,9 +2,7 @@ import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from '../../google/protobuf/FeatureSet'; import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; -import type { FileStatusAnnotation as _xds_annotations_v3_FileStatusAnnotation, FileStatusAnnotation__Output as _xds_annotations_v3_FileStatusAnnotation__Output } from '../../xds/annotations/v3/FileStatusAnnotation'; // Original file: null @@ -49,9 +47,7 @@ export interface FileOptions { 'rubyPackage'?: (string); 'features'?: (_google_protobuf_FeatureSet | null); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation | null); '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation | null); - '.xds.annotations.v3.file_status'?: (_xds_annotations_v3_FileStatusAnnotation | null); } export interface FileOptions__Output { @@ -79,7 +75,5 @@ export interface FileOptions__Output { 'rubyPackage': (string); 'features': (_google_protobuf_FeatureSet__Output | null); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output | null); '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output | null); - '.xds.annotations.v3.file_status': (_xds_annotations_v3_FileStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index 0e374c84a..6d6d45961 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -2,9 +2,6 @@ import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from '../../google/protobuf/FeatureSet'; import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { VersioningAnnotation as _udpa_annotations_VersioningAnnotation, VersioningAnnotation__Output as _udpa_annotations_VersioningAnnotation__Output } from '../../udpa/annotations/VersioningAnnotation'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; -import type { MessageStatusAnnotation as _xds_annotations_v3_MessageStatusAnnotation, MessageStatusAnnotation__Output as _xds_annotations_v3_MessageStatusAnnotation__Output } from '../../xds/annotations/v3/MessageStatusAnnotation'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); @@ -18,9 +15,6 @@ export interface MessageOptions { 'features'?: (_google_protobuf_FeatureSet | null); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.disabled'?: (boolean); - '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation | null); - '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation | null); - '.xds.annotations.v3.message_status'?: (_xds_annotations_v3_MessageStatusAnnotation | null); } export interface MessageOptions__Output { @@ -35,7 +29,4 @@ export interface MessageOptions__Output { 'features': (_google_protobuf_FeatureSet__Output | null); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); - '.udpa.annotations.versioning': (_udpa_annotations_VersioningAnnotation__Output | null); - '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); - '.xds.annotations.v3.message_status': (_xds_annotations_v3_MessageStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/typed_struct.ts b/packages/grpc-js-xds/src/generated/typed_struct.ts index 2ac34157a..bdf59972e 100644 --- a/packages/grpc-js-xds/src/generated/typed_struct.ts +++ b/packages/grpc-js-xds/src/generated/typed_struct.ts @@ -1,58 +1,10 @@ import type * as grpc from '@grpc/grpc-js'; import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import type { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import type { ExtensionRangeOptions as _google_protobuf_ExtensionRangeOptions, ExtensionRangeOptions__Output as _google_protobuf_ExtensionRangeOptions__Output } from './google/protobuf/ExtensionRangeOptions'; -import type { FeatureSet as _google_protobuf_FeatureSet, FeatureSet__Output as _google_protobuf_FeatureSet__Output } from './google/protobuf/FeatureSet'; -import type { FeatureSetDefaults as _google_protobuf_FeatureSetDefaults, FeatureSetDefaults__Output as _google_protobuf_FeatureSetDefaults__Output } from './google/protobuf/FeatureSetDefaults'; -import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import type { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import type { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import type { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import type { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import type { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; import type { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import type { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import type { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import type { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import type { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import type { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import type { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import type { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import type { TypedStruct as _udpa_type_v1_TypedStruct, TypedStruct__Output as _udpa_type_v1_TypedStruct__Output } from './udpa/type/v1/TypedStruct'; -import type { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import type { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import type { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import type { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import type { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import type { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import type { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import type { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import type { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import type { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import type { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import type { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import type { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import type { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import type { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import type { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import type { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import type { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import type { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import type { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import type { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import type { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; import type { TypedStruct as _xds_type_v3_TypedStruct, TypedStruct__Output as _xds_type_v3_TypedStruct__Output } from './xds/type/v3/TypedStruct'; type SubtypeConstructor any, Subtype> = { @@ -62,36 +14,9 @@ type SubtypeConstructor any, Subtype> export interface ProtoGrpcType { google: { protobuf: { - DescriptorProto: MessageTypeDefinition<_google_protobuf_DescriptorProto, _google_protobuf_DescriptorProto__Output> - Duration: MessageTypeDefinition<_google_protobuf_Duration, _google_protobuf_Duration__Output> - Edition: EnumTypeDefinition - EnumDescriptorProto: MessageTypeDefinition<_google_protobuf_EnumDescriptorProto, _google_protobuf_EnumDescriptorProto__Output> - EnumOptions: MessageTypeDefinition<_google_protobuf_EnumOptions, _google_protobuf_EnumOptions__Output> - EnumValueDescriptorProto: MessageTypeDefinition<_google_protobuf_EnumValueDescriptorProto, _google_protobuf_EnumValueDescriptorProto__Output> - EnumValueOptions: MessageTypeDefinition<_google_protobuf_EnumValueOptions, _google_protobuf_EnumValueOptions__Output> - ExtensionRangeOptions: MessageTypeDefinition<_google_protobuf_ExtensionRangeOptions, _google_protobuf_ExtensionRangeOptions__Output> - FeatureSet: MessageTypeDefinition<_google_protobuf_FeatureSet, _google_protobuf_FeatureSet__Output> - FeatureSetDefaults: MessageTypeDefinition<_google_protobuf_FeatureSetDefaults, _google_protobuf_FeatureSetDefaults__Output> - FieldDescriptorProto: MessageTypeDefinition<_google_protobuf_FieldDescriptorProto, _google_protobuf_FieldDescriptorProto__Output> - FieldOptions: MessageTypeDefinition<_google_protobuf_FieldOptions, _google_protobuf_FieldOptions__Output> - FileDescriptorProto: MessageTypeDefinition<_google_protobuf_FileDescriptorProto, _google_protobuf_FileDescriptorProto__Output> - FileDescriptorSet: MessageTypeDefinition<_google_protobuf_FileDescriptorSet, _google_protobuf_FileDescriptorSet__Output> - FileOptions: MessageTypeDefinition<_google_protobuf_FileOptions, _google_protobuf_FileOptions__Output> - GeneratedCodeInfo: MessageTypeDefinition<_google_protobuf_GeneratedCodeInfo, _google_protobuf_GeneratedCodeInfo__Output> ListValue: MessageTypeDefinition<_google_protobuf_ListValue, _google_protobuf_ListValue__Output> - MessageOptions: MessageTypeDefinition<_google_protobuf_MessageOptions, _google_protobuf_MessageOptions__Output> - MethodDescriptorProto: MessageTypeDefinition<_google_protobuf_MethodDescriptorProto, _google_protobuf_MethodDescriptorProto__Output> - MethodOptions: MessageTypeDefinition<_google_protobuf_MethodOptions, _google_protobuf_MethodOptions__Output> NullValue: EnumTypeDefinition - OneofDescriptorProto: MessageTypeDefinition<_google_protobuf_OneofDescriptorProto, _google_protobuf_OneofDescriptorProto__Output> - OneofOptions: MessageTypeDefinition<_google_protobuf_OneofOptions, _google_protobuf_OneofOptions__Output> - ServiceDescriptorProto: MessageTypeDefinition<_google_protobuf_ServiceDescriptorProto, _google_protobuf_ServiceDescriptorProto__Output> - ServiceOptions: MessageTypeDefinition<_google_protobuf_ServiceOptions, _google_protobuf_ServiceOptions__Output> - SourceCodeInfo: MessageTypeDefinition<_google_protobuf_SourceCodeInfo, _google_protobuf_SourceCodeInfo__Output> Struct: MessageTypeDefinition<_google_protobuf_Struct, _google_protobuf_Struct__Output> - SymbolVisibility: EnumTypeDefinition - Timestamp: MessageTypeDefinition<_google_protobuf_Timestamp, _google_protobuf_Timestamp__Output> - UninterpretedOption: MessageTypeDefinition<_google_protobuf_UninterpretedOption, _google_protobuf_UninterpretedOption__Output> Value: MessageTypeDefinition<_google_protobuf_Value, _google_protobuf_Value__Output> } } @@ -102,32 +27,6 @@ export interface ProtoGrpcType { } } } - validate: { - AnyRules: MessageTypeDefinition<_validate_AnyRules, _validate_AnyRules__Output> - BoolRules: MessageTypeDefinition<_validate_BoolRules, _validate_BoolRules__Output> - BytesRules: MessageTypeDefinition<_validate_BytesRules, _validate_BytesRules__Output> - DoubleRules: MessageTypeDefinition<_validate_DoubleRules, _validate_DoubleRules__Output> - DurationRules: MessageTypeDefinition<_validate_DurationRules, _validate_DurationRules__Output> - EnumRules: MessageTypeDefinition<_validate_EnumRules, _validate_EnumRules__Output> - FieldRules: MessageTypeDefinition<_validate_FieldRules, _validate_FieldRules__Output> - Fixed32Rules: MessageTypeDefinition<_validate_Fixed32Rules, _validate_Fixed32Rules__Output> - Fixed64Rules: MessageTypeDefinition<_validate_Fixed64Rules, _validate_Fixed64Rules__Output> - FloatRules: MessageTypeDefinition<_validate_FloatRules, _validate_FloatRules__Output> - Int32Rules: MessageTypeDefinition<_validate_Int32Rules, _validate_Int32Rules__Output> - Int64Rules: MessageTypeDefinition<_validate_Int64Rules, _validate_Int64Rules__Output> - KnownRegex: EnumTypeDefinition - MapRules: MessageTypeDefinition<_validate_MapRules, _validate_MapRules__Output> - MessageRules: MessageTypeDefinition<_validate_MessageRules, _validate_MessageRules__Output> - RepeatedRules: MessageTypeDefinition<_validate_RepeatedRules, _validate_RepeatedRules__Output> - SFixed32Rules: MessageTypeDefinition<_validate_SFixed32Rules, _validate_SFixed32Rules__Output> - SFixed64Rules: MessageTypeDefinition<_validate_SFixed64Rules, _validate_SFixed64Rules__Output> - SInt32Rules: MessageTypeDefinition<_validate_SInt32Rules, _validate_SInt32Rules__Output> - SInt64Rules: MessageTypeDefinition<_validate_SInt64Rules, _validate_SInt64Rules__Output> - StringRules: MessageTypeDefinition<_validate_StringRules, _validate_StringRules__Output> - TimestampRules: MessageTypeDefinition<_validate_TimestampRules, _validate_TimestampRules__Output> - UInt32Rules: MessageTypeDefinition<_validate_UInt32Rules, _validate_UInt32Rules__Output> - UInt64Rules: MessageTypeDefinition<_validate_UInt64Rules, _validate_UInt64Rules__Output> - } xds: { type: { v3: { diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts index 9d1f6b43d..aba2e50cf 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts @@ -8,8 +8,8 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ */ export interface _xds_core_v3_CollectionEntry_InlineEntry { /** - * Optional name to describe the inlined resource. Resource names must - * [a-zA-Z0-9_-\./]+ (TODO(htuch): turn this into a PGV constraint once + * Optional name to describe the inlined resource. Resource names must match + * ``[a-zA-Z0-9_-\./]+`` (TODO(htuch): turn this into a PGV constraint once * finalized, probably should be a RFC3986 pchar). This name allows * reference via the #entry directive in ResourceLocator. */ @@ -30,8 +30,8 @@ export interface _xds_core_v3_CollectionEntry_InlineEntry { */ export interface _xds_core_v3_CollectionEntry_InlineEntry__Output { /** - * Optional name to describe the inlined resource. Resource names must - * [a-zA-Z0-9_-\./]+ (TODO(htuch): turn this into a PGV constraint once + * Optional name to describe the inlined resource. Resource names must match + * ``[a-zA-Z0-9_-\./]+`` (TODO(htuch): turn this into a PGV constraint once * finalized, probably should be a RFC3986 pchar). This name allows * reference via the #entry directive in ResourceLocator. */ @@ -52,6 +52,8 @@ export interface _xds_core_v3_CollectionEntry_InlineEntry__Output { * appearing inside a list collection resource. List collection resources are * regular Resource messages of type: * + * .. code-block:: proto + * * message Collection { * repeated CollectionEntry resources = 1; * } @@ -73,6 +75,8 @@ export interface CollectionEntry { * appearing inside a list collection resource. List collection resources are * regular Resource messages of type: * + * .. code-block:: proto + * * message Collection { * repeated CollectionEntry resources = 1; * } diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts index 19a8a99bb..ee37353a7 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts @@ -6,6 +6,7 @@ * global context parameters, per-resource type client feature capabilities and per-resource * type functional attributes. All per-resource type attributes will be `xds.resource.` * prefixed and some of these are documented below: + * * `xds.resource.listening_address`: The value is "IP:port" (e.g. "10.1.1.3:8080") which is * the listening address of a Listener. Used in a Listener resource query. */ @@ -18,6 +19,7 @@ export interface ContextParams { * global context parameters, per-resource type client feature capabilities and per-resource * type functional attributes. All per-resource type attributes will be `xds.resource.` * prefixed and some of these are documented below: + * * `xds.resource.listening_address`: The value is "IP:port" (e.g. "10.1.1.3:8080") which is * the listening address of a Listener. Used in a Listener resource query. */ diff --git a/packages/grpc-js-xds/src/generated/xds/type/matcher/v3/Matcher.ts b/packages/grpc-js-xds/src/generated/xds/type/matcher/v3/Matcher.ts index 85500aaf8..70fa6fca7 100644 --- a/packages/grpc-js-xds/src/generated/xds/type/matcher/v3/Matcher.ts +++ b/packages/grpc-js-xds/src/generated/xds/type/matcher/v3/Matcher.ts @@ -271,10 +271,9 @@ export interface Matcher { */ 'matcher_tree'?: (_xds_type_matcher_v3_Matcher_MatcherTree | null); /** - * Optional OnMatch to use if the matcher failed. - * If specified, the OnMatch is used, and the matcher is considered - * to have matched. - * If not specified, the matcher is considered not to have matched. + * Optional OnMatch to use if no matcher above matched (e.g., if there are no matchers specified + * above, or if none of the matches specified above succeeded). + * If no matcher above matched and this field is not populated, the match will be considered unsuccessful. */ 'on_no_match'?: (_xds_type_matcher_v3_Matcher_OnMatch | null); 'matcher_type'?: "matcher_list"|"matcher_tree"; @@ -297,10 +296,9 @@ export interface Matcher__Output { */ 'matcher_tree'?: (_xds_type_matcher_v3_Matcher_MatcherTree__Output | null); /** - * Optional OnMatch to use if the matcher failed. - * If specified, the OnMatch is used, and the matcher is considered - * to have matched. - * If not specified, the matcher is considered not to have matched. + * Optional OnMatch to use if no matcher above matched (e.g., if there are no matchers specified + * above, or if none of the matches specified above succeeded). + * If no matcher above matched and this field is not populated, the match will be considered unsuccessful. */ 'on_no_match': (_xds_type_matcher_v3_Matcher_OnMatch__Output | null); 'matcher_type'?: "matcher_list"|"matcher_tree"; diff --git a/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts b/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts index a0df831d2..44b20ea53 100644 --- a/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts +++ b/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts @@ -13,6 +13,7 @@ import type { Struct as _google_protobuf_Struct, Struct__Output as _google_proto * When packing an opaque extension config, packing the expected type into Any is preferred * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor * is not available, for example if: + * * - A control plane sends opaque message that is originally from external source in human readable * format such as JSON or YAML. * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot @@ -23,6 +24,7 @@ import type { Struct as _google_protobuf_Struct, Struct__Output as _google_proto * When a DPLB receives a TypedStruct in Any, it should: * - Check if the type_url of the TypedStruct matches the type the extension expects. * - Convert value to the type described in type_url and perform validation. + * * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). */ @@ -50,6 +52,7 @@ export interface TypedStruct { * When packing an opaque extension config, packing the expected type into Any is preferred * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor * is not available, for example if: + * * - A control plane sends opaque message that is originally from external source in human readable * format such as JSON or YAML. * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot @@ -60,6 +63,7 @@ export interface TypedStruct { * When a DPLB receives a TypedStruct in Any, it should: * - Check if the type_url of the TypedStruct matches the type the extension expects. * - Convert value to the type described in type_url and perform validation. + * * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). */ diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 8db8b44e0..457a7c209 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -30,6 +30,7 @@ import * as csds from './csds'; import * as round_robin_lb from './lb-policy-registry/round-robin'; import * as typed_struct_lb from './lb-policy-registry/typed-struct'; import * as pick_first_lb from './lb-policy-registry/pick-first'; +import * as weighted_round_robin_lb from './lb-policy-registry/weighted-round-robin'; export { XdsServer } from './server'; export { XdsChannelCredentials, XdsServerCredentials } from './xds-credentials'; @@ -59,4 +60,5 @@ export function register() { round_robin_lb.setup(); typed_struct_lb.setup(); pick_first_lb.setup(); + weighted_round_robin_lb.setup(); } diff --git a/packages/grpc-js-xds/src/lb-policy-registry/weighted-round-robin.ts b/packages/grpc-js-xds/src/lb-policy-registry/weighted-round-robin.ts new file mode 100644 index 000000000..01bdc2de9 --- /dev/null +++ b/packages/grpc-js-xds/src/lb-policy-registry/weighted-round-robin.ts @@ -0,0 +1,80 @@ +/* + * Copyright 2025 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { LoadBalancingConfig } from "@grpc/grpc-js"; +import { LoadBalancingPolicy__Output } from "../generated/envoy/config/cluster/v3/LoadBalancingPolicy"; +import { TypedExtensionConfig__Output } from "../generated/envoy/config/core/v3/TypedExtensionConfig"; +import { loadProtosWithOptionsSync } from "@grpc/proto-loader/build/src/util"; +import { Any__Output } from "../generated/google/protobuf/Any"; +import { ClientSideWeightedRoundRobin__Output } from "../generated/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin"; +import { EXPERIMENTAL_WRR_LB } from "../environment"; +import { registerLbPolicy } from "../lb-policy-registry"; + +const WEIGHTED_ROUND_ROBIN_TYPE_URL = 'type.googleapis.com/envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin'; + +const resourceRoot = loadProtosWithOptionsSync([ + 'envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto'], { + keepCase: true, + includeDirs: [ + // Paths are relative to src/build/lb-policy-registry + __dirname + '/../../../deps/envoy-api/', + __dirname + '/../../../deps/xds/', + __dirname + '/../../../deps/protoc-gen-validate' + ], + } +); + +const toObjectOptions = { + longs: String, + enums: String, + defaults: true, + oneofs: true +}; + +function decodeWeightedRoundRobinConfig(message: Any__Output): ClientSideWeightedRoundRobin__Output { + const name = message.type_url.substring(message.type_url.lastIndexOf('/') + 1); + const type = resourceRoot.lookup(name); + if (type) { + const decodedMessage = (type as any).decode(message.value); + return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as ClientSideWeightedRoundRobin__Output; + } else { + throw new Error(`TypedStruct parsing error: unexpected type URL ${message.type_url}`); + } +} + +function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig | null { + if (protoPolicy.typed_config?.type_url !== WEIGHTED_ROUND_ROBIN_TYPE_URL) { + throw new Error(`Pick first LB policy parsing error: unexpected type URL ${protoPolicy.typed_config?.type_url}`); + } + const wrrMessage = decodeWeightedRoundRobinConfig(protoPolicy.typed_config); + return { + weighted_round_robin: { + enable_oob_load_report: wrrMessage.enable_oob_load_report?.value, + oob_load_reporting_period: wrrMessage.oob_reporting_period, + blackout_period: wrrMessage.blackout_period, + weight_expiration_period: wrrMessage.weight_expiration_period, + weight_update_period: wrrMessage.weight_update_period, + error_utilization_penalty: wrrMessage.error_utilization_penalty?.value + } + } +} + +export function setup() { + if (EXPERIMENTAL_WRR_LB) { + registerLbPolicy(WEIGHTED_ROUND_ROBIN_TYPE_URL, convertToLoadBalancingPolicy); + } +} diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-impl.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-impl.ts index cd552d315..1b3cd9654 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-impl.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-impl.ts @@ -173,7 +173,7 @@ class XdsClusterImplPicker implements Picker { return { pickResultType: originalPick.pickResultType, status: originalPick.status, - subchannel: pickSubchannel?.getWrappedSubchannel() ?? null, + subchannel: pickSubchannel?.getWrappedSubchannel?.() ?? null, onCallStarted: () => { originalPick.onCallStarted?.(); pickSubchannel?.getStatsObject()?.addCallStarted(); diff --git a/packages/grpc-js-xds/test/test-custom-lb-policies.ts b/packages/grpc-js-xds/test/test-custom-lb-policies.ts index 111a31b48..82903b29f 100644 --- a/packages/grpc-js-xds/test/test-custom-lb-policies.ts +++ b/packages/grpc-js-xds/test/test-custom-lb-policies.ts @@ -40,6 +40,7 @@ import parseLoadBalancingConfig = experimental.parseLoadBalancingConfig; import registerLoadBalancerType = experimental.registerLoadBalancerType; import StatusOr = experimental.StatusOr; import { PickFirst } from "../src/generated/envoy/extensions/load_balancing_policies/pick_first/v3/PickFirst"; +import { ClientSideWeightedRoundRobin } from "../src/generated/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/ClientSideWeightedRoundRobin"; const LB_POLICY_NAME = 'test.RpcBehaviorLoadBalancer'; @@ -344,5 +345,70 @@ describe('Custom LB policies', () => { const error = await client.sendOneCallAsync(); assert.strictEqual(error, null); }); - + it('Should handle weighted_round_robin', async () => { + const lbPolicy: ClientSideWeightedRoundRobin & AnyExtension = { + '@type': 'type.googleapis.com/envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin', + enable_oob_load_report: { value: true }, + oob_reporting_period: { seconds: 1 }, + blackout_period: { seconds: 1 }, + weight_expiration_period: { seconds: 1 }, + weight_update_period: { seconds: 1 }, + error_utilization_penalty: { value: 0.5 } + }; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + client?.stopCalls(); + assert.fail(`Client NACKED ${typeUrl} resource with message ${responseState.errorMessage}`); + } + }); + const [backend] = await createBackends(1); + const serverRoute = new FakeServerRoute(backend.getPort(), 'serverRoute'); + xdsServer.setRdsResource(serverRoute.getRouteConfiguration()); + xdsServer.setLdsResource(serverRoute.getListener()); + const cluster = new FakeEdsCluster('cluster1', 'endpoint1', [{backends: [backend], locality:{region: 'region1'}}], lbPolicy); + const routeGroup = new FakeRouteGroup('listener1', 'route1', [{cluster: cluster}]); + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + await routeGroup.startAllBackends(xdsServer); + client = XdsTestClient.createFromServer('listener1', xdsServer); + const error = await client.sendOneCallAsync(); + assert.strictEqual(error, null); + }); + it('Should distribute traffic among backends with weighted_round_robin', async () => { + const lbPolicy: ClientSideWeightedRoundRobin & AnyExtension = { + '@type': 'type.googleapis.com/envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin', + enable_oob_load_report: { value: true }, + oob_reporting_period: { seconds: 1 }, + blackout_period: { seconds: 1 }, + weight_expiration_period: { seconds: 1 }, + weight_update_period: { seconds: 1 }, + error_utilization_penalty: { value: 0.5 } + }; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + client?.stopCalls(); + assert.fail(`Client NACKED ${typeUrl} resource with message ${responseState.errorMessage}`); + } + }); + const [backend1, backend2] = await createBackends(2); + const serverRoute1 = new FakeServerRoute(backend1.getPort(), 'serverRoute'); + const serverRoute2 = new FakeServerRoute(backend2.getPort(), 'serverRoute2'); + xdsServer.setRdsResource(serverRoute1.getRouteConfiguration()); + xdsServer.setLdsResource(serverRoute1.getListener()); + xdsServer.setRdsResource(serverRoute2.getRouteConfiguration()); + xdsServer.setLdsResource(serverRoute2.getListener()); + const cluster = new FakeEdsCluster('cluster1', 'endpoint1', [{backends: [backend1, backend2], locality:{region: 'region1'}}], lbPolicy); + const routeGroup = new FakeRouteGroup('listener1', 'route1', [{cluster: cluster}]); + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + await routeGroup.startAllBackends(xdsServer); + client = XdsTestClient.createFromServer('listener1', xdsServer); + client.startCalls(100); + await routeGroup.waitForAllBackendsToReceiveTraffic(); + client.stopCalls(); + }); }); diff --git a/packages/grpc-js-xds/test/xds-server.ts b/packages/grpc-js-xds/test/xds-server.ts index 3dbeecd10..d6115e79a 100644 --- a/packages/grpc-js-xds/test/xds-server.ts +++ b/packages/grpc-js-xds/test/xds-server.ts @@ -53,6 +53,7 @@ const loadedProtos = loadPackageDefinition(loadSync( 'envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto', 'envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto', 'envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto', + 'envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.proto', 'envoy/extensions/transport_sockets/tls/v3/tls.proto', 'xds/type/v3/typed_struct.proto', 'envoy/extensions/filters/http/router/v3/router.proto', diff --git a/packages/grpc-js/src/duration.ts b/packages/grpc-js/src/duration.ts index 843275f25..05a43da74 100644 --- a/packages/grpc-js/src/duration.ts +++ b/packages/grpc-js/src/duration.ts @@ -47,6 +47,10 @@ export function isDuration(value: any): value is Duration { return typeof value.seconds === 'number' && typeof value.nanos === 'number'; } +export function isDurationMessage(value: any): value is DurationMessage { + return typeof value.seconds === 'string' && typeof value.nanos === 'number'; +} + const durationRegex = /^(\d+)(?:\.(\d+))?s$/; export function parseDuration(value: string): Duration | null { const match = value.match(durationRegex); diff --git a/packages/grpc-js/src/load-balancer-weighted-round-robin.ts b/packages/grpc-js/src/load-balancer-weighted-round-robin.ts index 59aa3be97..cdeabc36d 100644 --- a/packages/grpc-js/src/load-balancer-weighted-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-weighted-round-robin.ts @@ -19,13 +19,13 @@ import { StatusOr } from './call-interface'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './connectivity-state'; import { LogVerbosity } from './constants'; -import { Duration, durationToMs, durationToString, isDuration, msToDuration, parseDuration } from './duration'; +import { Duration, durationMessageToDuration, durationToMs, durationToString, isDuration, isDurationMessage, msToDuration, parseDuration } from './duration'; import { OrcaLoadReport__Output } from './generated/xds/data/orca/v3/OrcaLoadReport'; import { ChannelControlHelper, createChildChannelControlHelper, LoadBalancer, registerLoadBalancerType, TypedLoadBalancingConfig } from './load-balancer'; import { LeafLoadBalancer } from './load-balancer-pick-first'; import * as logging from './logging'; import { createMetricsReader, MetricsListener, OrcaOobMetricsSubchannelWrapper } from './orca'; -import { PickArgs, Picker, PickResult, QueuePicker, UnavailablePicker } from './picker'; +import { PickArgs, Picker, PickResult, PickResultType, QueuePicker, UnavailablePicker } from './picker'; import { PriorityQueue } from './priority-queue'; import { Endpoint, endpointToString } from './subchannel-address'; @@ -70,10 +70,12 @@ function validateFieldType( } function parseDurationField(obj: any, fieldName: string): number | null { - if (fieldName in obj && obj[fieldName] !== undefined) { + if (fieldName in obj && obj[fieldName] !== undefined && obj[fieldName] !== null) { let durationObject: Duration; if (isDuration(obj[fieldName])) { durationObject = obj[fieldName]; + } else if (isDurationMessage(obj[fieldName])) { + durationObject = durationMessageToDuration(obj[fieldName]); } else if (typeof obj[fieldName] === 'string') { const parsedDuration = parseDuration(obj[fieldName]); if (!parsedDuration) { @@ -207,11 +209,19 @@ class WeightedRoundRobinPicker implements Picker { deadline: entry.deadline + entry.period }) const childPick = entry.picker.pick(pickArgs); - if (this.metricsHandler) { - return { - ...childPick, - onCallEnded: createMetricsReader(loadReport => this.metricsHandler!(loadReport, entry.endpointName), childPick.onCallEnded) - }; + if (childPick.pickResultType === PickResultType.COMPLETE) { + if (this.metricsHandler) { + return { + ...childPick, + onCallEnded: createMetricsReader(loadReport => this.metricsHandler!(loadReport, entry.endpointName), childPick.onCallEnded) + }; + } else { + const subchannelWrapper = childPick.subchannel as OrcaOobMetricsSubchannelWrapper; + return { + ...childPick, + subchannel: subchannelWrapper.getWrappedSubchannel() + } + } } else { return childPick; } diff --git a/packages/grpc-js/src/orca.ts b/packages/grpc-js/src/orca.ts index 16372fb05..234907331 100644 --- a/packages/grpc-js/src/orca.ts +++ b/packages/grpc-js/src/orca.ts @@ -338,6 +338,10 @@ export class OrcaOobMetricsSubchannelWrapper extends BaseSubchannelWrapper { super(child); this.addDataWatcher(new OobMetricsDataWatcher(metricsListener, intervalMs)); } + + getWrappedSubchannel(): SubchannelInterface { + return this.child; + } } function createOobMetricsDataProducer(subchannel: Subchannel) {