Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

feat: Add attempt_direct_path argument to create_channel - #583

Merged
parthea merged 19 commits into
mainfrom
add-support-for-direct-path
Feb 4, 2024
Merged

feat: Add attempt_direct_path argument to create_channel#583
parthea merged 19 commits into
mainfrom
add-support-for-direct-path

Conversation

@parthea

@partheaparthea commented Jan 26, 2024

Copy link
Copy Markdown
Contributor

Fixes#482
b/267782870

@product-auto-labelproduct-auto-labelBot added the size: m Pull request size is medium. label Jan 26, 2024
@parthea
partheaforce-pushed the add-support-for-direct-path branch 5 times, most recently from 676ca58 to e777b53CompareJanuary 31, 2024 00:56
@product-auto-labelproduct-auto-labelBot added size: l Pull request size is large. and removed size: m Pull request size is medium. labels Jan 31, 2024
@parthea
partheaforce-pushed the add-support-for-direct-path branch from e777b53 to 0e974b6CompareJanuary 31, 2024 01:09
@parthea
partheaforce-pushed the add-support-for-direct-path branch 2 times, most recently from c4f537d to 257d4dfCompareJanuary 31, 2024 01:22
@parthea
partheaforce-pushed the add-support-for-direct-path branch from 1d40546 to 421becdCompareJanuary 31, 2024 01:28
@parthea
parthea marked this pull request as ready for review January 31, 2024 01:33
@parthea
parthea requested review from a teamJanuary 31, 2024 01:33

@vchudnov-gvchudnov-g left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is looking good. I only reviewed the sync file and not the tests yet; I'll pick this back up tomorrow, but feel free to start responding to the comments here (or wait if you prefer; all good).

Comment threadgoogle/api_core/grpc_helpers.py Outdated
else:
# Use grpc.compute_engine_channel_credentials in order to support Direct Path.
# See https://grpc.github.io/grpc/python/grpc.html#grpc.compute_engine_channel_credentials
# TODO(b/323073050): Although `grpc.compute_engine_channel_credentials`

@vchudnov-gvchudnov-gJan 31, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since this is public code, I would prefer to a public (GitHub) issue in this TODO.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e9199a0

Comment threadgoogle/api_core/grpc_helpers.py Outdated
attempt_direct_path (Optional[bool]): If set, Direct Path will be attempted when
the request is made. Direct Path provides a proxyless connection which
increases the available throughput, reduces latency, and increases
reliability. Outside of GCE, the direct path request may fallback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need to spell out what GCE stands for in public docs? Not everyone looking at this file may be using GCE.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e7e3cf7

Comment threadgoogle/api_core/grpc_helpers.py Outdated
If a `ServiceUnavailable` response is received when the request is sent, it is
recommended that the client repeat the request with `attempt_direct_path` set to `False`
as the Service may not support Direct Path. Using `ssl_credentials` with `attempt_direct_path`
set to `True` will result in `ValueError` as it is not yet supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
setto`True`willresultin`ValueError`asitisnotyetsupported.
setto`True`willresultin`ValueError`asthiscombinationisnotyetsupported.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e7e3cf7

Comment threadgoogle/api_core/grpc_helpers.py Outdated
Comment on lines +327 to +336
attempt_direct_path (Optional[bool]): If set, Direct Path will be attempted when
the request is made. Direct Path provides a proxyless connection which
increases the available throughput, reduces latency, and increases
reliability. Outside of GCE, the direct path request may fallback
to DNS if this is configured by the Service. This argument should only
be set in a GCE environment and for Services that are known to support Direct Path.
If a `ServiceUnavailable` response is received when the request is sent, it is
recommended that the client repeat the request with `attempt_direct_path` set to `False`
as the Service may not support Direct Path. Using `ssl_credentials` with `attempt_direct_path`
set to `True` will result in `ValueError` as it is not yet supported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"Should only be set in a GCE environment" is confusing in light of "Outside of GCE, the request may fall back". Clarify. I suspect you mean something like this:

Suggested change
attempt_direct_path (Optional[bool]): Ifset, DirectPathwillbeattemptedwhen
therequestismade. DirectPathprovidesaproxylessconnectionwhich
increasestheavailablethroughput, reduceslatency, andincreases
reliability. OutsideofGCE, thedirectpathrequestmayfallback
toDNSifthisisconfiguredbytheService. Thisargumentshouldonly
besetinaGCEenvironmentandforServicesthatareknowntosupportDirectPath.
Ifa`ServiceUnavailable`responseisreceivedwhentherequestissent, itis
recommendedthattheclientrepeattherequestwith`attempt_direct_path`setto`False`
astheServicemaynotsupportDirectPath. Using`ssl_credentials`with`attempt_direct_path`
setto`True`willresultin`ValueError`asitisnotyetsupported.
attempt_direct_path (Optional[bool]): Ifset, DirectPathwillbeattemptedwhen
therequestismade. DirectPathisonlyavailablewithinaGoogleCompute
Engineenvironmentandprovidesaproxylessconnectionwhichincreasesthe
availablethroughput, reduceslatency, andincreasesreliability.
-Thisargumentshouldonly
besetinaGCEenvironmentandforServicesthatareknowntosupportDirect
Path.
-IfthisargumentissetoutsideofGCE, thenthisrequestwillfail
unlesstheback-endservicehappenstohaveconfiguredfall-backtoDNS.
-Iftherequestcausesa`ServiceUnavailable`response, we
recommendthattheclientrepeattherequestwith`attempt_direct_path`setto
`False`astheServicemaynotsupportDirectPath.
-Using`ssl_credentials`with`attempt_direct_path`
setto`True`willresultin`ValueError`asthiscombinationisnotyet
supported.

(And similarly for the async version)

WDYT?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e7e3cf7

Comment threadgoogle/api_core/grpc_helpers.py Outdated
attempt_direct_path (Optional[bool]): If set, Direct Path will be attempted when
the request is made. Direct Path provides a proxyless connection which
increases the available throughput, reduces latency, and increases
reliability. Outside of GCE, the direct path request may fallback

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
reliability. OutsideofGCE, thedirectpathrequestmayfallback
reliability. OutsideofGCE, thedirectpathrequestmayfallback

but see comment below

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e7e3cf7

Comment threadgoogle/api_core/grpc_helpers.py Outdated
Comment on lines +395 to +397
target (str): The target service address which is converted into a format compatible with Direct Path.
If the target contains `dns:///` or does not have contain `:///`, the target will be converted in
a format compatible with Direct Path, otherwise the original target will be returned.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
target (str): ThetargetserviceaddresswhichisconvertedintoaformatcompatiblewithDirectPath.
Ifthetargetcontains`dns:///`ordoesnothavecontain`:///`, thetargetwillbeconvertedin
aformatcompatiblewithDirectPath,otherwisetheoriginaltargetwillbereturned.
target (str): ThetargetserviceaddresswhichisconvertedintoaformatcompatiblewithDirectPath.
Ifthetargetcontains`dns:///`ordoesnotcontain`:///`, thetargetwillbeconvertedin
aformatcompatiblewithDirectPath;otherwisetheoriginaltargetwillbereturned.

So the idea is that a :/// (except for dns:///) already denotes Direct Path, so no action is needed, correct? It might be good to be explicit about this assumption.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done in 44d5845

a format compatible with Direct Path, otherwise the original target will be returned.
"""

dns_prefix = "dns:///"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It might be helpful to clarify in a comment what the dns_prefix means, which I take it is to be explicit about an endpoint living in the Internet (ie outside GCP).

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in e6ea7ec

Comment threadgoogle/api_core/grpc_helpers.py Outdated
default_scopes=None,
default_host=None,
compression=None,
attempt_direct_path: Optional[bool] = None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
attempt_direct_path: Optional[bool] =None,
attempt_direct_path: Optional[bool] =False,

Since it's meant to be a Boolean, might as well.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in 0f3a0e4

@vchudnov-gvchudnov-g left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! Nothing blocking, but I think some of my suggestions can make things tighter/clearer.

Comment threadgoogle/api_core/grpc_helpers.py Outdated
# If `ssl_credentials` is set and `attempt_direct_path` is set to `True`,
# raise ValueError as this is not yet supported.
# See https://github.com/googleapis/python-api-core/issues/590
if ssl_credentials is not None and attempt_direct_path:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we simplify to just this?:

Suggested change
ifssl_credentialsisnotNoneandattempt_direct_path:
ifssl_credentialsandattempt_direct_path:

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in 60b8acb

"Compression argument is being ignored for grpc_gcp.secure_channel creation."
)
if attempt_direct_path:
warnings.warn(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For consistency, the _LOGGER.debug in the previous lines should probably also become a warnings.warn

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in 1a7578d and d96499f

Comment threadgoogle/api_core/grpc_helpers.py Outdated
Given a target, return a modified version which is compatible with Direct Path.

Args:
target (str): The target service address in the format 'hostname:port', 'dns://hostname' or other

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
target (str): Thetargetserviceaddressintheformat'hostname:port', 'dns://hostname'orother
target (str): Thetargetserviceaddressintheformat'hostname[:port]', 'dns://hostname[:port]'orother

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in af3a21b

Comment threadgoogle/api_core/grpc_helpers.py Outdated

Args:
target (str): The target service address in the format 'hostname:port', 'dns://hostname' or other
compatible format.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

"other compatible format": link to a place that lists compatible formats, or remove this phrase which I think is puzzling by itself.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Removed in af3a21b

Comment threadgoogle/api_core/grpc_helpers.py Outdated
Comment on lines +405 to +406
direct_path_prefix = ":///"
if direct_path_prefix not in target:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
direct_path_prefix=":///"
ifdirect_path_prefixnotintarget:
direct_path_separator=":///"
ifdirect_path_separatornotintarget:

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in c0052e6

)


def _modify_target_for_direct_path(target: str) -> str:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Q: In general, an API endpoint could depend on the URL path and not just the host+port. Is this true of Google APIs? If so, where do we deal with the path part of the URI? (I realize these functions specify only host+port as inputs, so it's clear what they expect and they're doing the right thing, but I was wondering about this more general question.)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

If so, where do we deal with the path part of the URI?

I believe this is part of the transcode method

Transcodes a grpc request pattern into a proper HTTP request following the rules outlined here,

deftranscode(http_options, message=None, **request_kwargs):
"""Transcodes a grpc request pattern into a proper HTTP request following the rules outlined here,
https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L44-L312
Args:
http_options (list(dict)): A list of dicts which consist of these keys,
'method' (str): The http method
'uri' (str): The path template
'body' (str): The body field name (optional)
(This is a simplified representation of the proto option `google.api.http`)

https://github.com/googleapis/gapic-generator-python/blob/b4e6cfc0be8594e2575910699389600f5e92e552/gapic/templates/%25namespace/%25name_%25version/%25sub/services/%25service/transports/rest.py.j2#L372

import functools

from typing import Generic, Iterator, AsyncGenerator, TypeVar
from typing import AsyncGenerator, Generic, Iterator, Optional, TypeVar

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

General notes:

  1. The comments from the sycn version apply here too
  2. Just a note for the future (not blocking this PR): a lot of the code seems identical or very similar to the sync code. We should consolidate sensibly to eliminate duplication. (I just filed #593 to track more such instances)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks for opening that issue! I also made changes to the async code based on the sync code feedback.

Comment threadtests/unit/test_grpc_helpers.py Outdated
def test_create_channel_implicit(grpc_secure_channel, default, composite_creds_call):
def test_create_channel_implicit(
grpc_secure_channel,
default,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

default is too generic a name. I assume this is meant to take the google.auth.default you have patched in the decorators. Is there any way this parameter name could be made more descriptive (like auth-default, say), or does @mock preclude that?

(I realize this was pre-existing, so no need to spend too much time on this. But if it's easy...)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in d63402e



@mock.patch("grpc.composite_channel_credentials")
@pytest.mark.parametrize(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it be worth making this test function take a target parameter, and then parametrizing it as we do for test_create_channel_implicit_with_default_host below? target seems to be used the same way in both places, and this would allow us to check here the dns:/// and another-c2p:/// cases you parametrize below.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done in 396d8fa



@mock.patch("grpc.composite_channel_credentials")
@pytest.mark.parametrize(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same comments as in sync version apply here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Done in 396d8fa

@parthea
partheaforce-pushed the add-support-for-direct-path branch from b4a6edf to 396d8faCompareFebruary 4, 2024 17:48
@parthea
parthea merged commit 94726e7 into mainFeb 4, 2024
@parthea
parthea deleted the add-support-for-direct-path branch February 4, 2024 20:00
@release-pleaserelease-pleaseBot mentioned this pull request Feb 4, 2024
This was referenced May 30, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

size: lPull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable DirectPath support for gRPC workflows

2 participants

@parthea@vchudnov-g