CBI-436 Add GetGlobalQuote for anonymous batch pricing - #501
Conversation
The public pricing calculator implements pricing arithmetic in the browser, so the rules live in two places and drift. This is the endpoint that lets it stop: one anonymous call prices N configurations server-side. Batch rather than single-config because the calculator ranks candidates. A one-at-a-time endpoint would leave the loop, and therefore the arithmetic, in the browser — which is the thing being removed. Responses are index-aligned with the request and capped at 50. No account_id anywhere: this is a public shop window, always standard tier and no discount. A customer with a negotiated rate sees list price here and their real price on GetQuote. Reusing GetQuoteResponse carries the per-component breakdowns across unchanged. GlobalQuoteConfiguration duplicates GetQuoteRequest's pricing fields rather than reusing it: account_id sits inline there, with no nested configuration message to lift out.
|
PR Packages Published Python Package:
NPM Package:
|
|
The latest Buf updates on your PR. Results from workflow Pull Request / linting (pull_request).
|
Generated bindings were added in c6d8add; the uncommitted-changes check now passes.
lomidzemikheili
left a comment
There was a problem hiding this comment.
Left one question
| message GetGlobalQuoteResponse { | ||
| // The quotes for each requested configuration. | ||
| // Index-aligned with `GetGlobalQuoteRequest.configurations`. | ||
| repeated GetQuoteResponse quotes = 1; |
There was a problem hiding this comment.
Do you think it is good idea to introduce new message GetGlobalQuoteResponse instead of reusing existing one. It already have discount field which does not make sense for public unauthenticated endpoint.
The response reused GetQuoteResponse, which carries original/discounted price and a discount percentage at the top level and again inside every component breakdown. GetGlobalQuote is unauthenticated and always quotes standard-tier list price, so those fields could only ever report zero — dead surface on a public contract, and a breaking change to remove once anything reads it. GlobalQuote and GlobalPriceBreakdown replace them with a single price_per_hour each, keeping the three per-component slots the calculator needs. This also stops a message named ...Response from being nested inside another response, which is what the neighbouring Global endpoints already avoid: ListGlobal* wrap plain payload types like Package and CloudProvider. GlobalQuote needs a QDRANT_CLOUD_REQUIRED_ENTITY_FIELDS ignore. The lint plugin infers entity names by stripping CRUD prefixes from RPCs, so GetGlobalQuote makes it look like an account-scoped resource owing id/name/account_id/ created_at. It is a value, not an entity, and the endpoint has no account.
|
This adds a new RPC to BookingService, but the service api_version is still 1.0.0. CONTRIBUTING.md says MINOR should be incremented when new backward-compatible functionality is added: Should this become 1.1.0? cc @Robert-Stam |
| // Gets price quotes for a batch of cluster configurations. | ||
| // Always prices at standard tier with no discount, since there is no account to discount against. | ||
| // Authentication not required | ||
| rpc GetGlobalQuote(GetGlobalQuoteRequest) returns (GetGlobalQuoteResponse) { |
There was a problem hiding this comment.
This RPC is batch-oriented: the request has repeated configurations and the response has repeated quotes. Before this is released, should we name it GetGlobalQuotes or BatchGetGlobalQuotes? Renaming it later would be an breaking change.
What
Adds
GetGlobalQuote, an unauthenticated RPC that prices a batch of cluster configurations in onecall and returns quotes index-aligned with the request. Always standard tier, always zero discount.
Why
The public pricing calculator computes prices in the browser. That means the pricing rules exist in
two implementations, and they drift: the calculator's optimiser currently excludes extra-disk cost
when ranking candidates while the total it displays includes it, so the configuration it recommends
is not necessarily the cheapest one it shows. Fixing that in the browser would just re-enter the
same rules a third time. This endpoint lets the calculator stop knowing them at all.
How
Batch rather than single-config, because the calculator ranks candidates. A one-at-a-time endpoint
would leave the loop — and therefore the arithmetic — in the browser, which is the thing being
removed. Capped at 50 per request; one invalid configuration fails the batch, matching
GetQuote.No
account_idanywhere in the request or response. This is a public shop window, so a customerwith a negotiated rate sees list price here and their real price on
GetQuote. Making itaccount-aware later would be a behaviour change, not a field addition.
GetGlobalQuoteResponsereusesGetQuoteResponse, so the per-componentPriceBreakdownfieldscome across unchanged.
GlobalQuoteConfigurationis a new message rather than a reuse ofGetQuoteRequest:account_idsits inline in that message with no nested configuration to liftout, so reusing it would mean carrying an account field on an endpoint that must not have one.
Hourly only — the monthly conversion stays in the caller rather than freezing an "average month"
into the contract. Inference and backup pricing are deliberately out: the calculator has no model,
token-volume or backup-size input, and this is not the place to add surface for features that do
not exist yet.