Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add agent details and new runtime version header #456

Merged
merged 4 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/on-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,17 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install and configure Poetry
uses: snok/install-poetry@v1
with:
version: 1.3.1
virtualenvs-in-project: true

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: poetry

- name: Install dependencies
run: poetry install

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/on-push-to-release-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,17 @@ jobs:
steps:
- uses: actions/checkout@v3

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install and configure Poetry
uses: snok/install-poetry@v1
with:
version: 1.3.1
virtualenvs-in-project: true

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: poetry install

Expand Down
2 changes: 2 additions & 0 deletions src/momento/internal/_utilities/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ._client_type import ClientType
from ._data_validation import (
_as_bytes,
_gen_dictionary_fields_as_bytes,
Expand All @@ -14,4 +15,5 @@
_validate_ttl,
)
from ._momento_version import momento_version
from ._python_runtime_version import PYTHON_RUNTIME_VERSION
from ._time import _timedelta_to_ms
13 changes: 13 additions & 0 deletions src/momento/internal/_utilities/_client_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Enumerates the types of clients that can be used.

Used to populate the agent header in gRPC requests.
"""

from enum import Enum


class ClientType(Enum):
"""Describes the type of client that is being used."""

CACHE = "cache"
TOPIC = "topic"
10 changes: 10 additions & 0 deletions src/momento/internal/_utilities/_python_runtime_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Python runtime version information.

Used to populate the `runtime-version` header in gRPC requests.
"""
import sys

PYTHON_RUNTIME_VERSION = (
f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} "
f"({sys.version_info.releaselevel} {sys.version_info.serial})"
)
2 changes: 1 addition & 1 deletion src/momento/internal/aio/_add_header_client_interceptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@


class Header:
once_only_headers = ["agent"]
once_only_headers = ["agent", "runtime-version"]

def __init__(self, name: str, value: str):
self.name = name
Expand Down
26 changes: 17 additions & 9 deletions src/momento/internal/aio/_scs_grpc_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from momento.config import Configuration, TopicConfiguration
from momento.config.transport.transport_strategy import StaticGrpcConfiguration
from momento.errors.exceptions import ConnectionException
from momento.internal._utilities import momento_version
from momento.internal._utilities import PYTHON_RUNTIME_VERSION, ClientType, momento_version
from momento.internal._utilities._channel_credentials import (
channel_credentials_from_root_certs_or_default,
)
Expand Down Expand Up @@ -42,7 +42,9 @@ def __init__(self, configuration: Configuration, credential_provider: Credential
self._secure_channel = grpc.aio.secure_channel(
target=credential_provider.control_endpoint,
credentials=channel_credentials_from_root_certs_or_default(configuration),
interceptors=_interceptors(credential_provider.auth_token, configuration.get_retry_strategy()),
interceptors=_interceptors(
credential_provider.auth_token, ClientType.CACHE, configuration.get_retry_strategy()
),
options=grpc_control_channel_options_from_grpc_config(
grpc_config=configuration.get_transport_strategy().get_grpc_configuration(),
),
Expand All @@ -65,7 +67,9 @@ def __init__(self, configuration: Configuration, credential_provider: Credential
self._secure_channel = grpc.aio.secure_channel(
target=credential_provider.cache_endpoint,
credentials=channel_credentials_from_root_certs_or_default(configuration),
interceptors=_interceptors(credential_provider.auth_token, configuration.get_retry_strategy()),
interceptors=_interceptors(
credential_provider.auth_token, ClientType.CACHE, configuration.get_retry_strategy()
),
# Here is where you would pass override configuration to the underlying C gRPC layer.
# However, I have tried several different tuning options here and did not see any
# performance improvements, so sticking with the defaults for now.
Expand Down Expand Up @@ -142,7 +146,7 @@ def __init__(self, configuration: TopicConfiguration, credential_provider: Crede
self._secure_channel = grpc.aio.secure_channel(
target=credential_provider.cache_endpoint,
credentials=grpc.ssl_channel_credentials(),
interceptors=_interceptors(credential_provider.auth_token, None),
interceptors=_interceptors(credential_provider.auth_token, ClientType.TOPIC, None),
options=grpc_data_channel_options_from_grpc_config(grpc_config),
)

Expand All @@ -165,7 +169,7 @@ def __init__(self, configuration: TopicConfiguration, credential_provider: Crede
self._secure_channel = grpc.aio.secure_channel(
target=credential_provider.cache_endpoint,
credentials=grpc.ssl_channel_credentials(),
interceptors=_stream_interceptors(credential_provider.auth_token),
interceptors=_stream_interceptors(credential_provider.auth_token, ClientType.TOPIC),
options=grpc_data_channel_options_from_grpc_config(grpc_config),
)

Expand All @@ -176,10 +180,13 @@ def async_stub(self) -> pubsub_client.PubsubStub:
return pubsub_client.PubsubStub(self._secure_channel) # type: ignore[no-untyped-call]


def _interceptors(auth_token: str, retry_strategy: Optional[RetryStrategy] = None) -> list[grpc.aio.ClientInterceptor]:
def _interceptors(
auth_token: str, client_type: ClientType, retry_strategy: Optional[RetryStrategy] = None
) -> list[grpc.aio.ClientInterceptor]:
headers = [
Header("authorization", auth_token),
Header("agent", f"python:{_ControlGrpcManager.version}"),
Header("agent", f"python:{client_type.value}:{_ControlGrpcManager.version}"),
Header("runtime-version", f"python {PYTHON_RUNTIME_VERSION}"),
]
return list(
filter(
Expand All @@ -192,9 +199,10 @@ def _interceptors(auth_token: str, retry_strategy: Optional[RetryStrategy] = Non
)


def _stream_interceptors(auth_token: str) -> list[grpc.aio.UnaryStreamClientInterceptor]:
def _stream_interceptors(auth_token: str, client_type: ClientType) -> list[grpc.aio.UnaryStreamClientInterceptor]:
headers = [
Header("authorization", auth_token),
Header("agent", f"python:{_PubsubGrpcStreamManager.version}"),
Header("agent", f"python:{client_type.value}:{_PubsubGrpcStreamManager.version}"),
Header("runtime-version", f"python {PYTHON_RUNTIME_VERSION}"),
]
return [AddHeaderStreamingClientInterceptor(headers)]
25 changes: 16 additions & 9 deletions src/momento/internal/synchronous/_scs_grpc_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from momento.config import Configuration, TopicConfiguration
from momento.config.transport.transport_strategy import StaticGrpcConfiguration
from momento.errors.exceptions import ConnectionException
from momento.internal._utilities import momento_version
from momento.internal._utilities import PYTHON_RUNTIME_VERSION, ClientType, momento_version
from momento.internal._utilities._channel_credentials import (
channel_credentials_from_root_certs_or_default,
)
Expand Down Expand Up @@ -46,7 +46,8 @@ def __init__(self, configuration: Configuration, credential_provider: Credential
),
)
intercept_channel = grpc.intercept_channel(
self._secure_channel, *_interceptors(credential_provider.auth_token, configuration.get_retry_strategy())
self._secure_channel,
*_interceptors(credential_provider.auth_token, ClientType.CACHE, configuration.get_retry_strategy()),
)
self._stub = control_client.ScsControlStub(intercept_channel) # type: ignore[no-untyped-call]

Expand All @@ -73,7 +74,8 @@ def __init__(self, configuration: Configuration, credential_provider: Credential
)

intercept_channel = grpc.intercept_channel(
self._secure_channel, *_interceptors(credential_provider.auth_token, configuration.get_retry_strategy())
self._secure_channel,
*_interceptors(credential_provider.auth_token, ClientType.CACHE, configuration.get_retry_strategy()),
)
self._stub = cache_client.ScsStub(intercept_channel) # type: ignore[no-untyped-call]

Expand Down Expand Up @@ -164,7 +166,7 @@ def __init__(self, configuration: TopicConfiguration, credential_provider: Crede
options=grpc_data_channel_options_from_grpc_config(grpc_config),
)
intercept_channel = grpc.intercept_channel(
self._secure_channel, *_interceptors(credential_provider.auth_token, None)
self._secure_channel, *_interceptors(credential_provider.auth_token, ClientType.TOPIC, None)
)
self._stub = pubsub_client.PubsubStub(intercept_channel) # type: ignore[no-untyped-call]

Expand All @@ -190,7 +192,7 @@ def __init__(self, configuration: TopicConfiguration, credential_provider: Crede
options=grpc_data_channel_options_from_grpc_config(grpc_config),
)
intercept_channel = grpc.intercept_channel(
self._secure_channel, *_stream_interceptors(credential_provider.auth_token)
self._secure_channel, *_stream_interceptors(credential_provider.auth_token, ClientType.TOPIC)
)
self._stub = pubsub_client.PubsubStub(intercept_channel) # type: ignore[no-untyped-call]

Expand All @@ -202,19 +204,24 @@ def stub(self) -> pubsub_client.PubsubStub:


def _interceptors(
auth_token: str, retry_strategy: Optional[RetryStrategy] = None
auth_token: str, client_type: ClientType, retry_strategy: Optional[RetryStrategy] = None
) -> list[grpc.UnaryUnaryClientInterceptor]:
headers = [Header("authorization", auth_token), Header("agent", f"python:{_ControlGrpcManager.version}")]
headers = [
Header("authorization", auth_token),
Header("agent", f"python:{client_type.value}:{_ControlGrpcManager.version}"),
Header("runtime-version", f"python {PYTHON_RUNTIME_VERSION}"),
]
return list(
filter(
None, [AddHeaderClientInterceptor(headers), RetryInterceptor(retry_strategy) if retry_strategy else None]
)
)


def _stream_interceptors(auth_token: str) -> list[grpc.UnaryStreamClientInterceptor]:
def _stream_interceptors(auth_token: str, client_type: ClientType) -> list[grpc.UnaryStreamClientInterceptor]:
headers = [
Header("authorization", auth_token),
Header("agent", f"python:{_PubsubGrpcStreamManager.version}"),
Header("agent", f"python:{client_type.value}:{_PubsubGrpcStreamManager.version}"),
Header("runtime-version", f"python {PYTHON_RUNTIME_VERSION}"),
]
return [AddHeaderStreamingClientInterceptor(headers)]
Loading