Skip to content

Replace Endpoints with Regional Endpoints #39390

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

Merged
merged 194 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
194 commits
Select commit Hold shift + click to select a range
b0fe9fd
add new policy, add logic to use policy
simorenoh Jan 24, 2025
2444847
Merge branch 'main' into service_response_error_policy
simorenoh Jan 24, 2025
83b7a0d
added small test file I was using
simorenoh Jan 24, 2025
39d8a86
Merge branch 'service_response_error_policy' of https://github.com/si…
simorenoh Jan 24, 2025
3e5b8e5
initial regional endpoint work
tvaron3 Jan 24, 2025
41eadb4
Merge branch 'service_response_error_policy' of https://github.com/si…
tvaron3 Jan 24, 2025
6df9e49
groundwork
tvaron3 Jan 24, 2025
c0f9d5f
re-add AzureError logic, refactor, fix tests
simorenoh Jan 24, 2025
3eec9a1
Update _retry_utility.py
simorenoh Jan 24, 2025
cb7e8a8
Updated location_cache with new design
kushagraThapar Jan 24, 2025
3ae5c3f
Fixed key error with most_preferred_location
kushagraThapar Jan 24, 2025
116d8d3
Merge remote-tracking branch 'simon/service_response_error_policy' in…
kushagraThapar Jan 24, 2025
8fd9f9d
Update test_cosmos_http_logging_policy.py
simorenoh Jan 24, 2025
1305358
Update _retry_utility.py
simorenoh Jan 24, 2025
0fbc20c
Added logic to refresh cache on previous endpoint usage
kushagraThapar Jan 24, 2025
19e38c4
Added business logic update the regional endpoint based on success or…
kushagraThapar Jan 24, 2025
2342d27
implementation
simorenoh Jan 24, 2025
cd010fa
Update _retry_utility_async.py
simorenoh Jan 24, 2025
42ecabc
fix some tests
tvaron3 Jan 24, 2025
61f477b
changelog, versions, fixes
simorenoh Jan 24, 2025
794cf18
fixes
simorenoh Jan 25, 2025
1aff626
fix some tests
tvaron3 Jan 25, 2025
3ceffe0
remove fake logic, count fix
simorenoh Jan 25, 2025
112538f
fix some tests
tvaron3 Jan 25, 2025
d7e8886
Update _service_request_retry_policy.py
simorenoh Jan 25, 2025
c13d28a
Update _retry_utility_async.py
simorenoh Jan 25, 2025
7486d42
Merge with simon fix
tvaron3 Jan 25, 2025
ec3502c
retry utilities fixing
simorenoh Jan 25, 2025
2828dda
Update _retry_utility.py
simorenoh Jan 25, 2025
808d192
additional enhancements
simorenoh Jan 25, 2025
8eca519
Update setup.py
simorenoh Jan 25, 2025
d49e1a4
Update _retry_utility_async.py
simorenoh Jan 25, 2025
65bd86f
add tests, remove previous retry logic for ServiceRequestExceptions
simorenoh Jan 25, 2025
291195a
clean up with finally
simorenoh Jan 25, 2025
e97f377
tests
simorenoh Jan 25, 2025
b2d1bb3
retry utilities
simorenoh Jan 25, 2025
918785d
disable tests
simorenoh Jan 25, 2025
863edc9
add logging to policies
simorenoh Jan 25, 2025
07bc302
GetDatabaseAccount Fix
tvaron3 Jan 25, 2025
60851d6
Update _base.py
simorenoh Jan 25, 2025
e1f2ec3
retry utilities fixes
simorenoh Jan 25, 2025
10fb752
Update _retry_utility.py
simorenoh Jan 25, 2025
9f28e50
retry utulities part 34
simorenoh Jan 25, 2025
f4a7e0e
Update _service_request_retry_policy.py
simorenoh Jan 25, 2025
62ce36c
remove extra logs
simorenoh Jan 25, 2025
d47d372
policy updates
simorenoh Jan 25, 2025
0f9650a
Update _service_response_retry_policy.py
simorenoh Jan 25, 2025
50385cd
Update _service_response_retry_policy.py
simorenoh Jan 25, 2025
a084a3a
policies updates and update operation types
simorenoh Jan 25, 2025
43a229b
trying out fixes
simorenoh Jan 25, 2025
93c2774
Update sdk/cosmos/azure-cosmos/CHANGELOG.md
simorenoh Jan 25, 2025
f07b81a
Update sdk/cosmos/azure-cosmos/CHANGELOG.md
simorenoh Jan 25, 2025
db83522
Skipped proxy test for debugging
kushagraThapar Jan 26, 2025
852161b
annotation fix
simorenoh Jan 26, 2025
b95d61e
Merge branch 'service-reetries' of https://github.com/Azure/azure-sdk…
simorenoh Jan 26, 2025
4534e51
Fixed some tests cases
kushagraThapar Jan 26, 2025
8f8313a
test fixes
simorenoh Jan 26, 2025
9243abb
Update test_service_retry_policies_async.py
simorenoh Jan 26, 2025
552428a
Fixed some mocking behavior
kushagraThapar Jan 26, 2025
7af122f
fixed pylint issues
kushagraThapar Jan 26, 2025
ac3743a
Added aiohttp minimum dependency
kushagraThapar Jan 26, 2025
c79df22
Updated changelog and setup.py
kushagraThapar Jan 26, 2025
6ad9ca1
Updated changelog
kushagraThapar Jan 26, 2025
c61884f
Merge service-retries
tvaron3 Jan 27, 2025
62b9db5
Add changelog and fix tests.
tvaron3 Jan 27, 2025
1964565
Fix tests
tvaron3 Jan 27, 2025
a0c6abb
bootstrapping with global endpoint as previous for writes
tvaron3 Jan 28, 2025
887d5ef
merge with main
tvaron3 Jan 28, 2025
31482fa
Add headers and cleanup
tvaron3 Jan 28, 2025
610c399
cleanup and retry all service request headers
tvaron3 Jan 28, 2025
e7d7a97
Don't retry on a none previous
tvaron3 Jan 28, 2025
2390b0e
Updated the business logic with current and previous, fixed database …
kushagraThapar Jan 28, 2025
58abeca
fix client id
tvaron3 Jan 28, 2025
736ddcf
Reacting to comments
tvaron3 Jan 28, 2025
a209eb8
Added print statements and fixed some retry logic
kushagraThapar Jan 28, 2025
4f82f08
Revert getDatabase in mark endpoint
tvaron3 Jan 28, 2025
37f9bbb
Fixed some pylint and changelog issues
kushagraThapar Jan 28, 2025
34607c6
Fixed version
kushagraThapar Jan 28, 2025
f7fd96f
fix bug with type check, update tests
simorenoh Jan 28, 2025
b0e210d
Update test_service_retry_policies_async.py
simorenoh Jan 28, 2025
26f75d7
sync tests updates
simorenoh Jan 29, 2025
9584ad3
Reacting to comments and fixing service request retry policy
tvaron3 Jan 29, 2025
67e0bca
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 29, 2025
1c3e9a5
Code review comments and pylint issues
kushagraThapar Jan 29, 2025
b5250cc
Fixed tests and pylint
kushagraThapar Jan 29, 2025
8ea6b9f
more sync mock tests - missing async copies
simorenoh Jan 29, 2025
c3a9e99
Fixed min aiohttp requirements
kushagraThapar Jan 29, 2025
353a7ae
Merged latest commit and resolved conflicts
kushagraThapar Jan 29, 2025
41490ef
Merge branch 'main' into tvaron3/regionalEndpoints
kushagraThapar Jan 29, 2025
0120ddd
Update _retry_utility_async.py
simorenoh Jan 30, 2025
274e846
Change to check operation type in operations
tvaron3 Jan 30, 2025
f9e3a2a
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 30, 2025
8181d95
push initial GEM mock test
simorenoh Jan 30, 2025
0d8d880
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Jan 30, 2025
0758393
Update test_service_retry_policies.py
simorenoh Jan 30, 2025
258c877
Fixed extra retries
tvaron3 Jan 30, 2025
77627e8
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 30, 2025
2c30d29
sync tests
simorenoh Jan 30, 2025
319e5b2
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Jan 30, 2025
2cb82be
Update test_service_retry_policies_async.py
simorenoh Jan 30, 2025
3818885
Fixed extra retries and relevant tests
tvaron3 Jan 30, 2025
a711a3c
Only delay retry by one second
tvaron3 Jan 30, 2025
fa066ae
async tests - need to split up inheritance ones since endpoint unavai…
simorenoh Jan 30, 2025
9b97295
Change retry strategy
tvaron3 Jan 30, 2025
9df935d
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 30, 2025
c928cd1
add sub-class errors tests
simorenoh Jan 30, 2025
28b51ed
change old tests, refactoring, fix mocking bleed
simorenoh Jan 30, 2025
d4d93c0
Fix a test
tvaron3 Jan 30, 2025
f0266b2
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 30, 2025
fdfb171
clear last routed location pythonic
tvaron3 Jan 30, 2025
9b5d7a7
Removed aiohttp dependency
kushagraThapar Jan 30, 2025
d215e46
catch import errors
tvaron3 Jan 30, 2025
2cd1d4f
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 30, 2025
554d875
Skipped global endpoint manager test for debugging
kushagraThapar Jan 31, 2025
9a351f0
Fixed tests
tvaron3 Jan 31, 2025
1ce1b08
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 31, 2025
0900806
Removed skips
tvaron3 Jan 31, 2025
f391fc4
fix live tests and print statements for debugging
tvaron3 Jan 31, 2025
e19b952
cleanup of few tests
kushagraThapar Jan 31, 2025
9ec61e2
updated globaldb mock
kushagraThapar Jan 31, 2025
d4190f1
Moved some of the high offer throughput tests to live tests
kushagraThapar Jan 31, 2025
25d5ac2
Fixed global endpoint retry async test
kushagraThapar Jan 31, 2025
ec7afdf
Tried fixing global endpoint retry async test
kushagraThapar Jan 31, 2025
f50a644
no swaps on success test
tvaron3 Jan 31, 2025
0c10812
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 31, 2025
d41a1ba
fix import
tvaron3 Jan 31, 2025
e71fa83
Tried fixing global endpoint retry async test
kushagraThapar Jan 31, 2025
2313b8f
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Jan 31, 2025
105a0eb
Added separate split live tests
kushagraThapar Jan 31, 2025
bc78060
Added live platform matrix
kushagraThapar Jan 31, 2025
511167d
Merge branch 'tvaron3/regionalEndpoints' of github.com:tvaron3/azure-…
kushagraThapar Jan 31, 2025
75f9b01
some test fixes
simorenoh Jan 31, 2025
d13beae
Fixed live test pipeline
kushagraThapar Jan 31, 2025
209fd41
Moved test resource id to cosmosLong
kushagraThapar Jan 31, 2025
7e5a2c3
Updated live tests
kushagraThapar Jan 31, 2025
64cf837
Running live tests with proper flag
kushagraThapar Feb 1, 2025
9a43071
testing logging experiments
kushagraThapar Feb 1, 2025
6e92716
fix tests
simorenoh Feb 1, 2025
929d47c
honor testmark argument through a safe environment variable, versus a…
scbedd Feb 1, 2025
ed89809
more test fixes
simorenoh Feb 1, 2025
f51384b
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Feb 1, 2025
092eaf7
Merged latest commit and resolved conflicts
kushagraThapar Feb 1, 2025
db88f3b
remove accidental log files
simorenoh Feb 1, 2025
539e9cd
Fixed issues with swapping and retry policies
kushagraThapar Feb 1, 2025
a232212
Merge branch 'testing_logging_experiments' into tvaron3/regionalEndpo…
kushagraThapar Feb 1, 2025
6ee18f2
Merge changes
tvaron3 Feb 1, 2025
2a3d005
Merge branch 'testing_logging_experiments' of https://github.com/kush…
tvaron3 Feb 1, 2025
5b4159a
Fixed issues with swapping and retry policies
kushagraThapar Feb 1, 2025
58f6163
Marking endpoint as down fix
tvaron3 Feb 1, 2025
1732af4
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Feb 1, 2025
e016e86
more test fixes
simorenoh Feb 1, 2025
91c08e4
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Feb 1, 2025
4b9f276
Remove print statements
tvaron3 Feb 1, 2025
7d96364
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Feb 1, 2025
01b5801
Fixed some minor issues with emulator tests
kushagraThapar Feb 1, 2025
5df4e35
Merge branch 'tvaron3/regionalEndpoints' of github.com:tvaron3/azure-…
kushagraThapar Feb 1, 2025
b7ca3f0
split change feed tests
simorenoh Feb 1, 2025
d809d04
Fixed emulator tests
kushagraThapar Feb 1, 2025
997df71
Merge branch 'tvaron3/regionalEndpoints' of github.com:tvaron3/azure-…
kushagraThapar Feb 1, 2025
d20cb8d
updated changelog
tvaron3 Feb 1, 2025
1f548ba
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Feb 1, 2025
9c2ef11
Fixed emulator tests again
kushagraThapar Feb 1, 2025
31fdef8
Fixed emulator tests and event loop
kushagraThapar Feb 1, 2025
59f711c
vector/fts query tests
simorenoh Feb 1, 2025
4ae78c3
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Feb 1, 2025
15ebd45
Fix session token live tests
tvaron3 Feb 1, 2025
f17298b
hybrid search query fixes
simorenoh Feb 1, 2025
989276b
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Feb 1, 2025
5ca674d
Fixed live test name
kushagraThapar Feb 2, 2025
afe3102
fallback to regional
tvaron3 Feb 2, 2025
334a866
fix ci tests
tvaron3 Feb 2, 2025
a4f4714
Update conftest.py
simorenoh Feb 3, 2025
c73f699
Database accounts call will timeout in 5 seconds
tvaron3 Feb 3, 2025
1924b78
Merge with main
tvaron3 Feb 3, 2025
c0b41b8
Change timeouts and update docs
tvaron3 Feb 4, 2025
217bf4d
call updates to endpoint policy and location cache
simorenoh Feb 4, 2025
fde8d64
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
simorenoh Feb 4, 2025
504bc6c
Health check for endpoitns
tvaron3 Feb 4, 2025
d78ef9d
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Feb 4, 2025
9507321
database account retry policy
tvaron3 Feb 4, 2025
0421e91
Fix parameter error
tvaron3 Feb 4, 2025
e89bbe9
Retry on cosmos error fix
tvaron3 Feb 4, 2025
94d349b
Retry on service request error fix
tvaron3 Feb 4, 2025
c552653
None checks for request in retry utilities
tvaron3 Feb 4, 2025
f595650
lowercase constructed regional endpoint
tvaron3 Feb 5, 2025
af9a900
fix global endpoint as unhealthy
tvaron3 Feb 5, 2025
0f7fd42
fix parsing test
tvaron3 Feb 5, 2025
0579061
Added logic for swapping on health check failed
kushagraThapar Feb 5, 2025
56c585f
Fixed log statement
kushagraThapar Feb 5, 2025
7e0df0a
fix pylint, docs, and remove print statements
tvaron3 Feb 5, 2025
cc5d3da
Merge branch 'tvaron3/regionalEndpoints' of https://github.com/tvaron…
tvaron3 Feb 5, 2025
bdb491a
fix pylint
tvaron3 Feb 5, 2025
01575db
fix some tests
tvaron3 Feb 5, 2025
4582bd7
Prepared for release
kushagraThapar Feb 5, 2025
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
19 changes: 17 additions & 2 deletions eng/pipelines/templates/steps/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,18 @@ steps:
}
Write-Host (Get-Command python).Source

if ($env:TESTMARKARGUMENT) {
$markArg = $env:TESTMARKARGUMENT
}
else {
$markArg = "${{ parameters.TestMarkArgument }}"
}

python scripts/devops_tasks/dispatch_tox.py
"$(TargetingString)"
${{ parameters.AdditionalTestArgs }}
${{ parameters.CoverageArg }}
--mark_arg="${{ parameters.TestMarkArgument }}"
--mark_arg="$markArg"
--service="${{ parameters.ServiceDirectory }}"
--toxenv="${{ parameters.ToxTestEnv }}"
--injected-packages="${{ parameters.InjectedPackages }}"
Expand All @@ -104,10 +111,18 @@ steps:
. $(VENV_LOCATION)/bin/activate.ps1
}
Write-Host (Get-Command python).Source

if ($env:TESTMARKARGUMENT) {
$markArg = $env:TESTMARKARGUMENT
}
else {
$markArg = "${{ parameters.TestMarkArgument }}"
}

python scripts/devops_tasks/dispatch_tox.py "$(TargetingString)" `
${{ parameters.AdditionalTestArgs }} `
${{ parameters.CoverageArg }} `
--mark_arg="${{ parameters.TestMarkArgument }}" `
--mark_arg="$markArg" `
--service="${{ parameters.ServiceDirectory }}" `
--toxenv="${{ parameters.ToxTestEnv }}" `
--injected-packages="${{ parameters.InjectedPackages }}" `
Expand Down
17 changes: 17 additions & 0 deletions sdk/cosmos/azure-cosmos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
## Release History

### 4.9.1b3 (2025-02-04)

#### Features Added
* Improved retry logic by retrying alternative endpoint for writes within a region before performing a cross region retry. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* Added endpoint health check logic during database account calls. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)

#### Bugs Fixed
* Fixed unnecessary retries on the wrong region for timout retry policy. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* All client connection errors from aiohttp will be retried. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)

#### Other Changes
* Changed defaults for retry delays. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* Changed default connection timeout to be 5 seconds. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* Changed default read timeout to be 65 seconds. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* On database account calls send a client id header for load balancing. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)
* Removed aiohttp dependency. See [PR 39390](https://github.com/Azure/azure-sdk-for-python/pull/39390)

### 4.9.1b2 (2025-01-24)

#### Features Added
Expand Down
5 changes: 5 additions & 0 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def GetHeaders( # pylint: disable=too-many-statements,too-many-branches
operation_type: str,
options: Mapping[str, Any],
partition_key_range_id: Optional[str] = None,
client_id: Optional[str] = None,
) -> Dict[str, Any]:
"""Gets HTTP request headers.

Expand All @@ -131,6 +132,7 @@ def GetHeaders( # pylint: disable=too-many-statements,too-many-branches
:param str operation_type:
:param dict options:
:param str partition_key_range_id:
:param str client_id:
:return: The HTTP request headers.
:rtype: dict
"""
Expand Down Expand Up @@ -280,6 +282,9 @@ def GetHeaders( # pylint: disable=too-many-statements,too-many-branches
if partition_key_range_id is not None:
headers[http_constants.HttpHeaders.PartitionKeyRangeID] = partition_key_range_id

if client_id is not None:
headers[http_constants.HttpHeaders.ClientId] = client_id

if options.get("enableScriptLogging"):
headers[http_constants.HttpHeaders.EnableScriptLogging] = options["enableScriptLogging"]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"""
import os
import urllib.parse
import uuid
from typing import Callable, Dict, Any, Iterable, List, Mapping, Optional, Sequence, Tuple, Union, cast, Type
from typing_extensions import TypedDict
from urllib3.util.retry import Retry
Expand Down Expand Up @@ -109,7 +110,7 @@ class _QueryCompatibilityMode:
_DefaultStringHashPrecision = 3
_DefaultStringRangePrecision = -1

def __init__(
def __init__( # pylint: disable=too-many-statements
self,
url_connection: str,
auth: CredentialDict,
Expand All @@ -131,6 +132,7 @@ def __init__(
The default consistency policy for client operations.

"""
self.client_id = str(uuid.uuid4())
self.url_connection = url_connection
self.master_key: Optional[str] = None
self.resource_tokens: Optional[Mapping[str, Any]] = None
Expand Down Expand Up @@ -2555,7 +2557,7 @@ def GetDatabaseAccount(
url_connection = self.url_connection

headers = base.GetHeaders(self, self.default_headers, "get", "", "", "",
documents._OperationType.Read,{})
documents._OperationType.Read,{}, client_id=self.client_id)
request_params = RequestObject("databaseaccount", documents._OperationType.Read, url_connection)
result, last_response_headers = self.__Get("", request_params, headers, **kwargs)
self.last_response_headers = last_response_headers
Expand Down Expand Up @@ -2589,6 +2591,26 @@ def GetDatabaseAccount(
response_hook(last_response_headers, result)
return database_account

def _GetDatabaseAccountCheck(
self,
url_connection: Optional[str] = None,
**kwargs: Any
):
"""Gets database account info.

:param str url_connection: the endpoint used to get the database account
:return: The Database Account.
:rtype: documents.DatabaseAccount
"""
if url_connection is None:
url_connection = self.url_connection

headers = base.GetHeaders(self, self.default_headers, "get", "", "", "",
documents._OperationType.Read,{}, client_id=self.client_id)
request_params = RequestObject("databaseaccount", documents._OperationType.Read, url_connection)
self.__Get("", request_params, headers, **kwargs)


def Create(
self,
body: Dict[str, Any],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# The MIT License (MIT)
# Copyright (c) 2014 Microsoft Corporation

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

"""Internal class for database account retry policy implementation in the
Azure Cosmos database service.
"""

class DatabaseAccountRetryPolicy(object):
"""The database account retry policy which should only retry once regardless of errors.
"""

def __init__(self, connection_policy):
self.retry_count = 0
self.retry_after_in_milliseconds = 0
self.max_retry_attempt_count = 1
self.connection_policy = connection_policy

def ShouldRetry(self, exception): # pylint: disable=unused-argument
"""Returns true if the request should retry based on the passed-in exception.

:param exceptions.CosmosHttpResponseError exception:
:returns: a boolean stating whether the request should be retried
:rtype: bool
"""

if self.retry_count >= self.max_retry_attempt_count:
return False

self.retry_count += 1

return True
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Cosmos database service.
"""
from . import http_constants
from .documents import _OperationType

# pylint: disable=protected-access

Expand Down Expand Up @@ -36,12 +37,12 @@ def __init__(self, *args):
self.current_retry_attempt_count = 0
self.retry_after_in_milliseconds = 1000
self.args = args
self.request = args[0] if args else None

def needsRetry(self, error_code):
if error_code in DefaultRetryPolicy.CONNECTION_ERROR_CODES:
if self.args:
if (self.args[3].method == "GET") or (http_constants.HttpHeaders.IsQuery in self.args[3].headers) \
or (http_constants.HttpHeaders.IsQueryPlanRequest in self.args[3].headers):
if _OperationType.IsReadOnlyOperation(self.request.operation_type):
return True
return False
return True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,7 @@ def __init__(self, connection_policy, global_endpoint_manager, *args):
self.retry_after_in_milliseconds = EndpointDiscoveryRetryPolicy.Retry_after_in_milliseconds
self.connection_policy = connection_policy
self.request = args[0] if args else None
# clear previous location-based routing directive
if self.request:
self.request.clear_route_to_location()

# Resolve the endpoint for the request and pin the resolution to the resolved endpoint
# This enables marking the endpoint unavailability on endpoint failover/unreachability
self.location_endpoint = self.global_endpoint_manager.resolve_service_endpoint(self.request)
self.request.route_to_location(self.location_endpoint)

def ShouldRetry(self, exception): # pylint: disable=unused-argument
"""Returns true if the request should retry based on the passed-in exception.
Expand All @@ -77,12 +70,16 @@ def ShouldRetry(self, exception): # pylint: disable=unused-argument

self.failover_retry_count += 1

if self.location_endpoint:
if self.request.location_endpoint_to_route:
if _OperationType.IsReadOnlyOperation(self.request.operation_type):
# Mark current read endpoint as unavailable
self.global_endpoint_manager.mark_endpoint_unavailable_for_read(self.location_endpoint)
self.global_endpoint_manager.mark_endpoint_unavailable_for_read(
self.request.location_endpoint_to_route,
True)
else:
self.global_endpoint_manager.mark_endpoint_unavailable_for_write(self.location_endpoint)
self.global_endpoint_manager.mark_endpoint_unavailable_for_write(
self.request.location_endpoint_to_route,
True)

# set the refresh_needed flag to ensure that endpoint list is
# refreshed with new writable and readable locations
Expand Down
79 changes: 41 additions & 38 deletions sdk/cosmos/azure-cosmos/azure/cosmos/_global_endpoint_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"""

import threading
from urllib.parse import urlparse

from azure.core.exceptions import AzureError

Expand Down Expand Up @@ -64,25 +63,28 @@ def get_refresh_time_interval_in_ms_stub(self):
return constants._Constants.DefaultUnavailableLocationExpirationTime

def get_write_endpoint(self):
return self.location_cache.get_write_endpoint()
return self.location_cache.get_write_regional_endpoint()

def get_read_endpoint(self):
return self.location_cache.get_read_endpoint()
return self.location_cache.get_read_regional_endpoint()

def swap_regional_endpoint_values(self, request):
return self.location_cache.swap_regional_endpoint_values(request)

def resolve_service_endpoint(self, request):
return self.location_cache.resolve_service_endpoint(request)

def mark_endpoint_unavailable_for_read(self, endpoint):
self.location_cache.mark_endpoint_unavailable_for_read(endpoint)
def mark_endpoint_unavailable_for_read(self, endpoint, refresh_cache):
self.location_cache.mark_endpoint_unavailable_for_read(endpoint, refresh_cache)

def mark_endpoint_unavailable_for_write(self, endpoint):
self.location_cache.mark_endpoint_unavailable_for_write(endpoint)
def mark_endpoint_unavailable_for_write(self, endpoint, refresh_cache):
self.location_cache.mark_endpoint_unavailable_for_write(endpoint, refresh_cache)

def get_ordered_write_endpoints(self):
return self.location_cache.get_ordered_write_endpoints()
def get_ordered_write_locations(self):
return self.location_cache.get_ordered_write_locations()

def get_ordered_read_endpoints(self):
return self.location_cache.get_ordered_read_endpoints()
def get_ordered_read_locations(self):
return self.location_cache.get_ordered_read_locations()

def can_use_multiple_write_locations(self, request):
return self.location_cache.can_use_multiple_write_locations_for_request(request)
Expand All @@ -91,6 +93,9 @@ def force_refresh(self, database_account):
self.refresh_needed = True
self.refresh_endpoint_list(database_account)

def update_location_cache(self):
self.location_cache.update_location_cache()

def refresh_endpoint_list(self, database_account, **kwargs):
if self.location_cache.current_time_millis() - self.last_refresh_time > self.refresh_time_interval_in_ms:
self.refresh_needed = True
Expand All @@ -115,6 +120,8 @@ def _refresh_endpoint_list_private(self, database_account=None, **kwargs):
self.last_refresh_time = self.location_cache.current_time_millis()
database_account = self._GetDatabaseAccount(**kwargs)
self.location_cache.perform_on_database_account_read(database_account)
# this will perform getDatabaseAccount calls to check endpoint health
self._endpoints_health_check(**kwargs)

def _GetDatabaseAccount(self, **kwargs):
"""Gets the database account.
Expand All @@ -137,7 +144,7 @@ def _GetDatabaseAccount(self, **kwargs):
# to get that info from any endpoints
except (exceptions.CosmosHttpResponseError, AzureError):
for location_name in self.PreferredLocations:
locational_endpoint = _GlobalEndpointManager.GetLocationalEndpoint(self.DefaultEndpoint, location_name)
locational_endpoint = LocationCache.GetLocationalEndpoint(self.DefaultEndpoint, location_name)
try:
database_account = self._GetDatabaseAccountStub(locational_endpoint, **kwargs)
self._database_account_cache = database_account
Expand All @@ -146,6 +153,28 @@ def _GetDatabaseAccount(self, **kwargs):
pass
raise

def _endpoints_health_check(self, **kwargs):
"""Gets the database account for each endpoint.

Validating if the endpoint is healthy else marking it as unavailable.
"""
all_endpoints = [self.location_cache.read_regional_endpoints[0]]
all_endpoints.extend(self.location_cache.write_regional_endpoints)
count = 0
for endpoint in all_endpoints:
count += 1
if count > 3:
break
try:
self.Client._GetDatabaseAccountCheck(endpoint.get_current(), **kwargs)
except (exceptions.CosmosHttpResponseError, AzureError):
if endpoint in self.location_cache.read_regional_endpoints:
self.mark_endpoint_unavailable_for_read(endpoint.get_current(), False)
if endpoint in self.location_cache.write_regional_endpoints:
self.mark_endpoint_unavailable_for_write(endpoint.get_current(), False)
endpoint.swap()
self.location_cache.update_location_cache()

def _GetDatabaseAccountStub(self, endpoint, **kwargs):
"""Stub for getting database account from the client.
This can be used for mocking purposes as well.
Expand All @@ -155,29 +184,3 @@ def _GetDatabaseAccountStub(self, endpoint, **kwargs):
:rtype: ~azure.cosmos.DatabaseAccount
"""
return self.Client.GetDatabaseAccount(endpoint, **kwargs)

@staticmethod
def GetLocationalEndpoint(default_endpoint, location_name):
# For default_endpoint like 'https://contoso.documents.azure.com:443/' parse it to
# generate URL format. This default_endpoint should be global endpoint(and cannot
# be a locational endpoint) and we agreed to document that
endpoint_url = urlparse(default_endpoint)

# hostname attribute in endpoint_url will return 'contoso.documents.azure.com'
if endpoint_url.hostname is not None:
hostname_parts = str(endpoint_url.hostname).lower().split(".")
if hostname_parts is not None:
# global_database_account_name will return 'contoso'
global_database_account_name = hostname_parts[0]

# Prepare the locational_database_account_name as contoso-EastUS for location_name 'East US'
locational_database_account_name = global_database_account_name + "-" + location_name.replace(" ", "")

# Replace 'contoso' with 'contoso-EastUS' and return locational_endpoint
# as https://contoso-EastUS.documents.azure.com:443/
locational_endpoint = default_endpoint.lower().replace(
global_database_account_name, locational_database_account_name, 1
)
return locational_endpoint

return None
Loading
Loading