Skip to content

Implement/service config#2731

Open
nathanielford wants to merge 2 commits into
grpc:masterfrom
nathanielford:implement/ServiceConfig
Open

Implement/service config#2731
nathanielford wants to merge 2 commits into
grpc:masterfrom
nathanielford:implement/ServiceConfig

Conversation

@nathanielford

Copy link
Copy Markdown
Contributor

Motivation

ServiceConfig requires an internal representation that we can de/serialize.

Solution

This CL implements the ServiceConfig struct and necessary plumbing for de/serialization. In a follow-on CL(s) we will be adding the plumbing to fully utilize the ServiceConfig, including adding the option to the Channel builde, passing it to the load balancer tree for utilization, and interactions with the Name Resolver.

@nathanielford
nathanielford force-pushed the implement/ServiceConfig branch from 29c707f to 52589c3 Compare July 13, 2026 21:32
@nathanielford
nathanielford requested a review from dfawley July 13, 2026 21:43
@nathanielford
nathanielford marked this pull request as ready for review July 13, 2026 21:43
Comment on lines +25 to +26
use serde::Deserialize;
use std::time::Duration;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: please try to follow import groupings: std, external, internal.

use serde::Deserialize;
use std::time::Duration;

// See [service config format notes](https://protobuf.dev/reference/protobuf/google.protobuf/#duration)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link text here may be misleading. The link itself is to the proto duration parsing page, not service config notes.

Also, without triple slashes, I don't think this ever renders as a link anyway? (Probably should triple-slash this?)


assert!(parse_duration("").is_err());
assert!(parse_duration("1").is_err());
assert!(parse_duration("1.s").is_err());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ".5s" valid or an error? Please add a test for it.

.transpose()
}

// This included to allow deserializing both u32 and string (or "stringified")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This included to allow deserializing both u32 and string (or "stringified")
// This is included to allow deserializing both u32 and string (or "stringified")

?

Comment on lines +86 to +87
// representations of u32, as well as null values. This is used for the
// `max_concurrent_streams` field in the service config.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a max_concurrent_streams in service config, do we?

.transpose()
}

// This included to allow deserializing both u32 and string (or "stringified")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we supporting stringified numbers? Is that a requirement?


impl ServiceConfig {
/// Parses a service configuration from a JSON string.
pub fn parse(config_json: &str) -> Result<Self, String> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we might want a service_config::ParseResult type here that is Result<ServiceConfig, String>, for newtype reasons. The name resolve will be passing the full ParseResult to the channel.

(Go reference: https://pkg.go.dev/google.golang.org/grpc@v1.82.1/serviceconfig#ParseResult + passed to channel with https://pkg.go.dev/google.golang.org/grpc/resolver#State)

Comment on lines +468 to 470
.is_some_and(|lbc| lbc.iter().any(|c| c.name == "round_robin"))
{
json!([{round_robin::POLICY_NAME: {}}])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can delete the first part of this if and just use pick_first if there isn't an LB policy in the config at all. Unless you're saving that for the next PR because it cases even more changes?

json!([{pick_first::POLICY_NAME: {"shuffleAddressList": true, "unknown_field": false}}])
};

// TODO: config should come from ServiceConfig.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be deleted if you do the above?

Comment thread grpc/src/inmemory/mod.rs
},
]),
method_config: None,
retry_throttling: None,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use the channel_controller.parse_service_config on a string instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants