Skip to content

Commit 4fb70cc

Browse files
JericHunterannatischsimorenohtjprescott
authored
[Cosmos] Add AutoScale Header Support 1/2 (Azure#24976)
* Update offer.py * Update http_constants.py * Update database.py * Update _base.py * Update container_management.py * Update container_management_async.py * Create test_auto_scale.py * Create test_auto_scale_async.py * Update database.py * Update _database.py * Update _base.py * update readme and changelog * Update _base.py * Update offer.py * Update _base.py * Update container_management.py * Update container_management_async.py * Update test_auto_scale.py * Update test_auto_scale_async.py * Update offer.py * Update test_auto_scale.py * Update sdk/cosmos/azure-cosmos/samples/container_management_async.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/samples/container_management.py Co-authored-by: Anna Tisch <[email protected]> * Update _base.py * Update database.py * Update offer.py * Update test_auto_scale.py * Update __init__.py * Update test_auto_scale.py * Update CHANGELOG.md * Update __init__.py * Update database.py * Update test_auto_scale.py * Update _database.py * Update database.py * Update test_auto_scale.py * Update test_auto_scale_async.py * Update database.py * Update container.py * Update _database.py * Update _container.py * Update container.py * Update database.py * Update _container.py * Update _database.py * Update database.py * Update offer.py * Update cosmos_client.py * Update _cosmos_client.py * Update offer.py * Update test_auto_scale.py * Update test_auto_scale_async.py * code refactor * Update _base.py adding deserialize method * Update _base.py * Update _cosmos_client.py * Update _database.py * Update cosmos_client.py * Update database.py * renaming method * database samples * merge conflicts * Update database.py * Update _base.py * Update _base.py * Update _base.py * Update __init__.py * Update _base.py * docstring changes * Update CHANGELOG.md * Update test_auto_scale_async.py * Update test_auto_scale.py * Update _base.py * Update _base.py * Update _base.py * tests updates * Update _base.py * Update CHANGELOG.md * Update _base.py * Update sdk/cosmos/azure-cosmos/azure/cosmos/_base.py Co-authored-by: Travis Prescott <[email protected]> * Update CHANGELOG.md * Update CHANGELOG.md * Update sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/database.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/aio/_cosmos_client.py Co-authored-by: Anna Tisch <[email protected]> * Update _base.py * Update _database.py * Update _cosmos_client.py * Update cosmos_client.py * Update database.py * Update sdk/cosmos/azure-cosmos/azure/cosmos/aio/_cosmos_client.py Co-authored-by: Simon Moreno <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py Co-authored-by: Anna Tisch <[email protected]> * Update _database.py * Update _base.py * Update sdk/cosmos/azure-cosmos/azure/cosmos/_base.py Co-authored-by: Anna Tisch <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/_base.py Co-authored-by: Anna Tisch <[email protected]> * Update offer.py * Update database.py * Update cosmos_client.py * Update _database.py * Update _base.py * Update sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py Co-authored-by: Simon Moreno <[email protected]> * Update sdk/cosmos/azure-cosmos/azure/cosmos/database.py Co-authored-by: Simon Moreno <[email protected]> Co-authored-by: Anna Tisch <[email protected]> Co-authored-by: Simon Moreno <[email protected]> Co-authored-by: Travis Prescott <[email protected]>
1 parent 1c97ca7 commit 4fb70cc

18 files changed

+413
-43
lines changed

sdk/cosmos/azure-cosmos/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
## Release History
22

3-
### 4.3.1 (2022-08-12)
3+
### 4.3.1 (Unreleased)
44

55
#### Features Added
66
- GA release of integrated cache functionality. For more information on integrated cache please see [Azure Cosmos DB integrated cache](https://docs.microsoft.com/azure/cosmos-db/integrated-cache).
77
- Added ability to replace analytical ttl on containers. For more information on analytical ttl please see [Azure Cosmos DB analytical store](https://docs.microsoft.com/azure/cosmos-db/analytical-store-introduction).
8+
- Added the ability to create containers and databases with autoscale properties for the sync and async clients.
89

910
#### Bugs Fixed
1011
- Fixed parsing of args for overloaded `container.read()` method.

sdk/cosmos/azure-cosmos/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ Currently the features below are **not supported**. For alternatives options, ch
162162

163163
* Get CollectionSizeUsage, DatabaseUsage, and DocumentUsage metrics
164164
* Create Geospatial Index
165-
* Provision Autoscale DBs or containers
166165
* Update Autoscale throughput
167166
* Get the connection string
168167
* Get the minimum RU/s of a container

sdk/cosmos/azure-cosmos/azure/cosmos/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .user import UserProxy
2828
from .scripts import ScriptsProxy
2929
from .offer import Offer
30+
from .offer import ThroughputProperties
3031
from .documents import (
3132
ConsistencyLevel,
3233
DataType,
@@ -62,5 +63,6 @@
6263
"TriggerOperation",
6364
"TriggerType",
6465
"ConnectionRetryPolicy",
66+
"ThroughputProperties",
6567
)
6668
__version__ = VERSION

sdk/cosmos/azure-cosmos/azure/cosmos/_base.py

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,17 @@
2727
import json
2828
import uuid
2929
import binascii
30-
from typing import Dict, Any
30+
from typing import Dict, Any, Union
3131

3232
from urllib.parse import quote as urllib_quote
3333
from urllib.parse import urlsplit
34-
3534
from azure.core import MatchConditions
36-
3735
from . import auth
3836
from . import documents
3937
from . import partition_key
4038
from . import http_constants
4139
from . import _runtime_constants
40+
from .offer import ThroughputProperties
4241

4342
# pylint: disable=protected-access
4443

@@ -297,6 +296,9 @@ def GetHeaders( # pylint: disable=too-many-statements,too-many-branches
297296
if options.get("maxIntegratedCacheStaleness"):
298297
headers[http_constants.HttpHeaders.DedicatedGatewayCacheStaleness] = options["maxIntegratedCacheStaleness"]
299298

299+
if options.get("autoUpgradePolicy"):
300+
headers[http_constants.HttpHeaders.AutoscaleSettings] = options["autoUpgradePolicy"]
301+
300302
return headers
301303

302304

@@ -674,3 +676,60 @@ def validate_cache_staleness_value(max_integrated_cache_staleness):
674676
if max_integrated_cache_staleness < 0:
675677
raise ValueError("Parameter 'max_integrated_cache_staleness_in_ms' can only be an "
676678
"integer greater than or equal to zero")
679+
680+
681+
def _stringify_auto_scale(offer: Dict[str, Any]) -> Any:
682+
auto_scale_params = None
683+
max_throughput = offer.auto_scale_max_throughput
684+
increment_percent = offer.auto_scale_increment_percent
685+
auto_scale_params = {"maxThroughput": max_throughput}
686+
if increment_percent is not None:
687+
auto_scale_params["autoUpgradePolicy"] = {"throughputPolicy": {"incrementPercent": increment_percent}}
688+
auto_scale_settings = json.dumps(auto_scale_params)
689+
690+
return auto_scale_settings
691+
692+
693+
def _set_throughput_options(offer: Union[int, ThroughputProperties], request_options: Dict[str, Any]) -> Any:
694+
if offer is not None:
695+
try:
696+
max_throughput = offer.auto_scale_max_throughput
697+
increment_percent = offer.auto_scale_increment_percent
698+
699+
if max_throughput is not None:
700+
request_options['autoUpgradePolicy'] = _stringify_auto_scale(offer=offer)
701+
elif increment_percent:
702+
raise ValueError("auto_scale_max_throughput must be supplied in "
703+
"conjunction with auto_scale_increment_percent")
704+
if offer.offer_throughput:
705+
request_options["offerThroughput"] = offer.offer_throughput
706+
707+
except AttributeError:
708+
if isinstance(offer, int):
709+
request_options["offerThroughput"] = offer
710+
else:
711+
raise TypeError("offer_throughput must be int or an instance of ThroughputProperties")
712+
713+
714+
def _deserialize_throughput(throughput: list) -> Any:
715+
throughput_properties = throughput
716+
try:
717+
max_throughput = throughput_properties[0]['content']['offerAutopilotSettings']['maxThroughput']
718+
except (KeyError, TypeError): # Adding TypeError just in case one of these dicts is None
719+
max_throughput = None
720+
try:
721+
increment_percent = \
722+
throughput_properties[0]['content']['offerAutopilotSettings']['autoUpgradePolicy']['throughputPolicy'][
723+
'incrementPercent']
724+
except (KeyError, TypeError):
725+
increment_percent = None
726+
try:
727+
throughput = throughput_properties[0]["content"]["offerThroughput"]
728+
except (KeyError, TypeError):
729+
throughput = None
730+
return ThroughputProperties(
731+
auto_scale_max_throughput=max_throughput,
732+
auto_scale_increment_percent=increment_percent,
733+
offer_throughput=throughput,
734+
properties=throughput_properties[0]
735+
)

sdk/cosmos/azure-cosmos/azure/cosmos/aio/_container.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from azure.core.tracing.decorator_async import distributed_trace_async # type: ignore
3030

3131
from ._cosmos_client_connection_async import CosmosClientConnection
32-
from .._base import build_options as _build_options, validate_cache_staleness_value
32+
from .._base import build_options as _build_options, validate_cache_staleness_value, _deserialize_throughput
3333
from ..exceptions import CosmosResourceNotFoundError
3434
from ..http_constants import StatusCodes
3535
from ..offer import ThroughputProperties
@@ -594,8 +594,7 @@ async def get_throughput(self, **kwargs: Any) -> ThroughputProperties:
594594
if response_hook:
595595
response_hook(self.client_connection.last_response_headers, throughput_properties)
596596

597-
return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"],
598-
properties=throughput_properties[0])
597+
return _deserialize_throughput(throughput=throughput_properties)
599598

600599
@distributed_trace_async
601600
async def replace_throughput(self, throughput: int, **kwargs: Any) -> ThroughputProperties:

sdk/cosmos/azure-cosmos/azure/cosmos/aio/_cosmos_client.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232
from ..cosmos_client import _parse_connection_str, _build_auth
3333
from ._cosmos_client_connection_async import CosmosClientConnection
34-
from .._base import build_options as _build_options
34+
from .._base import build_options as _build_options, _set_throughput_options
35+
from ..offer import ThroughputProperties
3536
from ._retry_utility_async import _ConnectionRetryPolicy
3637
from ._database import DatabaseProxy
3738
from ..documents import ConnectionPolicy, DatabaseAccount
@@ -196,7 +197,8 @@ async def create_database( # pylint: disable=redefined-builtin
196197
Create a new database with the given ID (name).
197198
198199
:param str id: ID (name) of the database to create.
199-
:keyword int offer_throughput: The provisioned throughput for this offer.
200+
:keyword offer_throughput: The provisioned throughput for this offer.
201+
:paramtype offer_throughput: int or ~azure.cosmos.ThroughputProperties.
200202
:keyword str session_token: Token for use with Session consistency.
201203
:keyword dict[str, str] initial_headers: Initial headers to be sent as part of the request.
202204
:keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource
@@ -223,8 +225,7 @@ async def create_database( # pylint: disable=redefined-builtin
223225
request_options = _build_options(kwargs)
224226
response_hook = kwargs.pop('response_hook', None)
225227
offer_throughput = kwargs.pop('offer_throughput', None)
226-
if offer_throughput is not None:
227-
request_options["offerThroughput"] = offer_throughput
228+
_set_throughput_options(offer=offer_throughput, request_options=request_options)
228229

229230
result = await self.client_connection.CreateDatabase(database=dict(id=id), options=request_options, **kwargs)
230231
if response_hook:

sdk/cosmos/azure-cosmos/azure/cosmos/aio/_database.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from azure.core.tracing.decorator import distributed_trace
3131

3232
from ._cosmos_client_connection_async import CosmosClientConnection
33-
from .._base import build_options as _build_options
33+
from .._base import build_options as _build_options, _set_throughput_options, _deserialize_throughput
3434
from ._container import ContainerProxy
3535
from ..offer import ThroughputProperties
3636
from ..http_constants import StatusCodes
@@ -164,7 +164,8 @@ async def create_container(
164164
:keyword dict[str, str] indexing_policy: The indexing policy to apply to the container.
165165
:keyword int default_ttl: Default time to live (TTL) for items in the container.
166166
If unspecified, items do not expire.
167-
:keyword int offer_throughput: The provisioned throughput for this offer.
167+
:keyword offer_throughput: The provisioned throughput for this offer.
168+
:paramtype offer_throughput: int or ~azure.cosmos.ThroughputProperties.
168169
:keyword dict[str, str] unique_key_policy: The unique key policy to apply to the container.
169170
:keyword dict[str, str] conflict_resolution_policy: The conflict resolution policy to apply to the container.
170171
:keyword str session_token: Token for use with Session consistency.
@@ -227,8 +228,7 @@ async def create_container(
227228
request_options = _build_options(kwargs)
228229
response_hook = kwargs.pop('response_hook', None)
229230
offer_throughput = kwargs.pop('offer_throughput', None)
230-
if offer_throughput is not None:
231-
request_options["offerThroughput"] = offer_throughput
231+
_set_throughput_options(offer=offer_throughput, request_options=request_options)
232232

233233
data = await self.client_connection.CreateContainer(
234234
database_link=self.database_link, collection=definition, options=request_options, **kwargs
@@ -258,7 +258,8 @@ async def create_container_if_not_exists(
258258
:keyword dict[str, str] indexing_policy: The indexing policy to apply to the container.
259259
:keyword int default_ttl: Default time to live (TTL) for items in the container.
260260
If unspecified, items do not expire.
261-
:keyword int offer_throughput: The provisioned throughput for this offer.
261+
:keyword offer_throughput: The provisioned throughput for this offer.
262+
:paramtype offer_throughput: int or ~azure.cosmos.ThroughputProperties.
262263
:keyword dict[str, str] unique_key_policy: The unique key policy to apply to the container.
263264
:keyword dict[str, str] conflict_resolution_policy: The conflict resolution policy to apply to the container.
264265
:keyword str session_token: Token for use with Session consistency.
@@ -749,9 +750,7 @@ async def get_throughput(self, **kwargs: Any) -> ThroughputProperties:
749750
if response_hook:
750751
response_hook(self.client_connection.last_response_headers, throughput_properties)
751752

752-
return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"],
753-
properties=throughput_properties[0])
754-
753+
return _deserialize_throughput(throughput=throughput_properties)
755754

756755
@distributed_trace_async
757756
async def replace_throughput(self, throughput: int, **kwargs: Any) -> ThroughputProperties:

sdk/cosmos/azure-cosmos/azure/cosmos/container.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from azure.core.tracing.decorator import distributed_trace # type: ignore
3030

3131
from ._cosmos_client_connection import CosmosClientConnection
32-
from ._base import build_options, validate_cache_staleness_value
32+
from ._base import build_options, validate_cache_staleness_value, _deserialize_throughput
3333
from .exceptions import CosmosResourceNotFoundError
3434
from .http_constants import StatusCodes
3535
from .offer import ThroughputProperties
@@ -665,8 +665,7 @@ def get_throughput(self, **kwargs):
665665
if response_hook:
666666
response_hook(self.client_connection.last_response_headers, throughput_properties)
667667

668-
return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"],
669-
properties=throughput_properties[0])
668+
return _deserialize_throughput(throughput=throughput_properties)
670669

671670
@distributed_trace
672671
def replace_throughput(self, throughput, **kwargs):

sdk/cosmos/azure-cosmos/azure/cosmos/cosmos_client.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
from azure.core.tracing.decorator import distributed_trace # type: ignore
2828

2929
from ._cosmos_client_connection import CosmosClientConnection
30-
from ._base import build_options
30+
from ._base import build_options, _set_throughput_options
31+
from .offer import ThroughputProperties
3132
from ._retry_utility import ConnectionRetryPolicy
3233
from .database import DatabaseProxy
3334
from .documents import ConnectionPolicy, DatabaseAccount
@@ -230,15 +231,16 @@ def create_database( # pylint: disable=redefined-builtin
230231
self,
231232
id, # type: str
232233
populate_query_metrics=None, # type: Optional[bool]
233-
offer_throughput=None, # type: Optional[int]
234+
offer_throughput=None, # type: Optional[Union[int, ThroughputProperties]]
234235
**kwargs # type: Any
235236
):
236237
# type: (...) -> DatabaseProxy
237238
"""
238239
Create a new database with the given ID (name).
239240
240241
:param id: ID (name) of the database to create.
241-
:param int offer_throughput: The provisioned throughput for this offer.
242+
:param offer_throughput: The provisioned throughput for this offer.
243+
:paramtype offer_throughput: int or ~azure.cosmos.ThroughputProperties.
242244
:keyword str session_token: Token for use with Session consistency.
243245
:keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request.
244246
:keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource
@@ -268,8 +270,7 @@ def create_database( # pylint: disable=redefined-builtin
268270
UserWarning,
269271
)
270272
request_options["populateQueryMetrics"] = populate_query_metrics
271-
if offer_throughput is not None:
272-
request_options["offerThroughput"] = offer_throughput
273+
_set_throughput_options(offer=offer_throughput, request_options=request_options)
273274

274275
result = self.client_connection.CreateDatabase(database=dict(id=id), options=request_options, **kwargs)
275276
if response_hook:
@@ -281,7 +282,7 @@ def create_database_if_not_exists( # pylint: disable=redefined-builtin
281282
self,
282283
id, # type: str
283284
populate_query_metrics=None, # type: Optional[bool]
284-
offer_throughput=None, # type: Optional[int]
285+
offer_throughput=None, # type: Optional[Union[int, ThroughputProperties]]
285286
**kwargs # type: Any
286287
):
287288
# type: (...) -> DatabaseProxy
@@ -296,7 +297,8 @@ def create_database_if_not_exists( # pylint: disable=redefined-builtin
296297
297298
:param id: ID (name) of the database to read or create.
298299
:param bool populate_query_metrics: Enable returning query metrics in response headers.
299-
:param int offer_throughput: The provisioned throughput for this offer.
300+
:param offer_throughput: The provisioned throughput for this offer.
301+
:type offer_throughput: int or ~azure.cosmos.ThroughputProperties.
300302
:keyword str session_token: Token for use with Session consistency.
301303
:keyword dict[str,str] initial_headers: Initial headers to be sent as part of the request.
302304
:keyword str etag: An ETag value, or the wildcard character (*). Used to check if the resource

sdk/cosmos/azure-cosmos/azure/cosmos/database.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from azure.core.tracing.decorator import distributed_trace # type: ignore
2929

3030
from ._cosmos_client_connection import CosmosClientConnection
31-
from ._base import build_options
31+
from ._base import build_options, _set_throughput_options, _deserialize_throughput
3232
from .container import ContainerProxy
3333
from .offer import ThroughputProperties
3434
from .http_constants import StatusCodes
@@ -155,7 +155,7 @@ def create_container(
155155
indexing_policy=None, # type: Optional[Dict[str, Any]]
156156
default_ttl=None, # type: Optional[int]
157157
populate_query_metrics=None, # type: Optional[bool]
158-
offer_throughput=None, # type: Optional[int]
158+
offer_throughput=None, # type: Optional[Union[int, ThroughputProperties]]
159159
unique_key_policy=None, # type: Optional[Dict[str, Any]]
160160
conflict_resolution_policy=None, # type: Optional[Dict[str, Any]]
161161
**kwargs # type: Any
@@ -170,6 +170,7 @@ def create_container(
170170
:param indexing_policy: The indexing policy to apply to the container.
171171
:param default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire.
172172
:param offer_throughput: The provisioned throughput for this offer.
173+
:type offer_throughput: int or ~azure.cosmos.ThroughputProperties.
173174
:param unique_key_policy: The unique key policy to apply to the container.
174175
:param conflict_resolution_policy: The conflict resolution policy to apply to the container.
175176
:keyword str session_token: Token for use with Session consistency.
@@ -232,9 +233,7 @@ def create_container(
232233
UserWarning,
233234
)
234235
request_options["populateQueryMetrics"] = populate_query_metrics
235-
if offer_throughput is not None:
236-
request_options["offerThroughput"] = offer_throughput
237-
236+
_set_throughput_options(offer=offer_throughput, request_options=request_options)
238237
data = self.client_connection.CreateContainer(
239238
database_link=self.database_link, collection=definition, options=request_options, **kwargs
240239
)
@@ -252,7 +251,7 @@ def create_container_if_not_exists(
252251
indexing_policy=None, # type: Optional[Dict[str, Any]]
253252
default_ttl=None, # type: Optional[int]
254253
populate_query_metrics=None, # type: Optional[bool]
255-
offer_throughput=None, # type: Optional[int]
254+
offer_throughput=None, # type: Optional[Union[int, ThroughputProperties]]
256255
unique_key_policy=None, # type: Optional[Dict[str, Any]]
257256
conflict_resolution_policy=None, # type: Optional[Dict[str, Any]]
258257
**kwargs # type: Any
@@ -270,6 +269,7 @@ def create_container_if_not_exists(
270269
:param default_ttl: Default time to live (TTL) for items in the container. If unspecified, items do not expire.
271270
:param populate_query_metrics: Enable returning query metrics in response headers.
272271
:param offer_throughput: The provisioned throughput for this offer.
272+
:paramtype offer_throughput: int or ~azure.cosmos.ThroughputProperties.
273273
:param unique_key_policy: The unique key policy to apply to the container.
274274
:param conflict_resolution_policy: The conflict resolution policy to apply to the container.
275275
:keyword str session_token: Token for use with Session consistency.
@@ -774,8 +774,7 @@ def get_throughput(self, **kwargs):
774774
if response_hook:
775775
response_hook(self.client_connection.last_response_headers, throughput_properties)
776776

777-
return ThroughputProperties(offer_throughput=throughput_properties[0]["content"]["offerThroughput"],
778-
properties=throughput_properties[0])
777+
return _deserialize_throughput(throughput=throughput_properties)
779778

780779
@distributed_trace
781780
def replace_throughput(self, throughput, **kwargs):

0 commit comments

Comments
 (0)