|
38 | 38 | from dapr.proto import api_v1, api_service_v1, common_v1
|
39 | 39 | from dapr.proto.runtime.v1.dapr_pb2 import UnsubscribeConfigurationResponse
|
40 | 40 |
|
41 |
| -from dapr.clients.grpc._helpers import MetadataTuple, DaprClientInterceptor, to_bytes |
| 41 | +from dapr.clients.grpc._helpers import ( |
| 42 | + DaprClientInterceptor, |
| 43 | + MetadataTuple, |
| 44 | + to_bytes, |
| 45 | + validateNotBlankString, |
| 46 | +) |
42 | 47 | from dapr.clients.grpc._request import (
|
43 | 48 | InvokeMethodRequest,
|
44 | 49 | BindingRequest,
|
|
50 | 55 | GetSecretResponse,
|
51 | 56 | GetBulkSecretResponse,
|
52 | 57 | InvokeMethodResponse,
|
| 58 | + UnlockResponseStatus, |
53 | 59 | StateResponse,
|
54 | 60 | BulkStatesResponse,
|
55 | 61 | BulkStateItem,
|
56 | 62 | ConfigurationResponse,
|
57 | 63 | ConfigurationItem,
|
58 | 64 | QueryResponse,
|
59 | 65 | QueryResponseItem,
|
60 |
| - ConfigurationWatcher |
| 66 | + ConfigurationWatcher, |
| 67 | + TryLockResponse, |
| 68 | + UnlockResponse, |
61 | 69 | )
|
62 | 70 |
|
63 | 71 |
|
@@ -984,6 +992,102 @@ def unsubscribe_configuration(
|
984 | 992 | response: UnsubscribeConfigurationResponse = self._stub.UnsubscribeConfigurationAlpha1(req)
|
985 | 993 | return response.ok
|
986 | 994 |
|
| 995 | + def try_lock( |
| 996 | + self, |
| 997 | + store_name: str, |
| 998 | + resource_id: str, |
| 999 | + lock_owner: str, |
| 1000 | + expiry_in_seconds: int) -> TryLockResponse: |
| 1001 | + """Tries to get a lock with an expiry. |
| 1002 | +
|
| 1003 | + You can use the result of this operation directly on an `if` statement: |
| 1004 | +
|
| 1005 | + if client.try_lock(store_name, resource_id, first_client_id, expiry_s): |
| 1006 | + # lock acquired successfully... |
| 1007 | +
|
| 1008 | + You can also inspect the response's `success` attribute: |
| 1009 | +
|
| 1010 | + response = client.try_lock(store_name, resource_id, first_client_id, expiry_s) |
| 1011 | + if response.success: |
| 1012 | + # lock acquired successfully... |
| 1013 | +
|
| 1014 | + Finally, you can use this response with a `with` statement, and have the lock |
| 1015 | + be automatically unlocked after the with-statement scope ends |
| 1016 | +
|
| 1017 | + with client.try_lock(store_name, resource_id, first_client_id, expiry_s) as lock: |
| 1018 | + if lock: |
| 1019 | + # lock acquired successfully... |
| 1020 | + # Lock automatically unlocked at this point, no need to call client->unlock(...) |
| 1021 | +
|
| 1022 | + Args: |
| 1023 | + store_name (str): the lock store name, e.g. `redis`. |
| 1024 | + resource_id (str): the lock key. e.g. `order_id_111`. |
| 1025 | + It stands for "which resource I want to protect". |
| 1026 | + lock_owner (str): indicates the identifier of lock owner. |
| 1027 | + expiry_in_seconds (int): The length of time (in seconds) for which this lock |
| 1028 | + will be held and after which it expires. |
| 1029 | +
|
| 1030 | + Returns: |
| 1031 | + :class:`TryLockResponse`: With the result of the try-lock operation. |
| 1032 | + """ |
| 1033 | + # Warnings and input validation |
| 1034 | + warn('The Distributed Lock API is an Alpha version and is subject to change.', |
| 1035 | + UserWarning, stacklevel=2) |
| 1036 | + validateNotBlankString(store_name=store_name, |
| 1037 | + resource_id=resource_id, |
| 1038 | + lock_owner=lock_owner) |
| 1039 | + if not expiry_in_seconds or expiry_in_seconds < 1: |
| 1040 | + raise ValueError("expiry_in_seconds must be a positive number") |
| 1041 | + # Actual tryLock invocation |
| 1042 | + req = api_v1.TryLockRequest( |
| 1043 | + store_name=store_name, |
| 1044 | + resource_id=resource_id, |
| 1045 | + lock_owner=lock_owner, |
| 1046 | + expiryInSeconds=expiry_in_seconds) |
| 1047 | + response, call = self._stub.TryLockAlpha1.with_call(req) |
| 1048 | + return TryLockResponse( |
| 1049 | + success=response.success, |
| 1050 | + client=self, |
| 1051 | + store_name=store_name, |
| 1052 | + resource_id=resource_id, |
| 1053 | + lock_owner=lock_owner, |
| 1054 | + headers=call.initial_metadata()) |
| 1055 | + |
| 1056 | + def unlock( |
| 1057 | + self, |
| 1058 | + store_name: str, |
| 1059 | + resource_id: str, |
| 1060 | + lock_owner: str) -> UnlockResponse: |
| 1061 | + """Unlocks a lock. |
| 1062 | +
|
| 1063 | + Args: |
| 1064 | + store_name (str): the lock store name, e.g. `redis`. |
| 1065 | + resource_id (str): the lock key. e.g. `order_id_111`. |
| 1066 | + It stands for "which resource I want to protect". |
| 1067 | + lock_owner (str): indicates the identifier of lock owner. |
| 1068 | + metadata (tuple, optional, DEPRECATED): gRPC custom metadata |
| 1069 | +
|
| 1070 | + Returns: |
| 1071 | + :class:`UnlockResponseStatus`: Status of the request, |
| 1072 | + `UnlockResponseStatus.success` if it was successful of some other |
| 1073 | + status otherwise. |
| 1074 | + """ |
| 1075 | + # Warnings and input validation |
| 1076 | + warn('The Distributed Lock API is an Alpha version and is subject to change.', |
| 1077 | + UserWarning, stacklevel=2) |
| 1078 | + validateNotBlankString(store_name=store_name, |
| 1079 | + resource_id=resource_id, |
| 1080 | + lock_owner=lock_owner) |
| 1081 | + # Actual unlocking invocation |
| 1082 | + req = api_v1.UnlockRequest( |
| 1083 | + store_name=store_name, |
| 1084 | + resource_id=resource_id, |
| 1085 | + lock_owner=lock_owner) |
| 1086 | + response, call = self._stub.UnlockAlpha1.with_call(req) |
| 1087 | + |
| 1088 | + return UnlockResponse(status=UnlockResponseStatus(response.status), |
| 1089 | + headers=call.initial_metadata()) |
| 1090 | + |
987 | 1091 | def wait(self, timeout_s: float):
|
988 | 1092 | """Waits for sidecar to be available within the timeout.
|
989 | 1093 |
|
|
0 commit comments