Skip to content

Commit c9f2464

Browse files
Added read_entity_state to DurableOrchestrationClient (#285)
1 parent 0dbccf1 commit c9f2464

File tree

5 files changed

+137
-1
lines changed

5 files changed

+137
-1
lines changed

azure/durable_functions/models/DurableOrchestrationClient.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from .PurgeHistoryResult import PurgeHistoryResult
1111
from .DurableOrchestrationStatus import DurableOrchestrationStatus
12+
from .EntityStateResponse import EntityStateResponse
1213
from .RpcManagementOptions import RpcManagementOptions
1314
from .OrchestrationRuntimeStatus import OrchestrationRuntimeStatus
1415
from ..models.DurableOrchestrationBindings import DurableOrchestrationBindings
@@ -132,6 +133,56 @@ def create_http_management_payload(self, instance_id: str) -> Dict[str, str]:
132133
"""
133134
return self.get_client_response_links(None, instance_id)
134135

136+
async def read_entity_state(
137+
self,
138+
entityId: EntityId,
139+
task_hub_name: Optional[str] = None,
140+
connection_name: Optional[str] = None,
141+
) -> EntityStateResponse:
142+
"""Read the state of the entity.
143+
144+
Parameters
145+
----------
146+
entityId : EntityId
147+
The EntityId of the targeted entity.
148+
task_hub_name : Optional[str]
149+
The task hub name of the target entity.
150+
connection_name : Optional[str]
151+
The name of the connection string associated with [task_hub_name].
152+
153+
Raises
154+
------
155+
Exception:
156+
When an unexpected status code is returned
157+
158+
Returns
159+
-------
160+
EntityStateResponse
161+
container object representing the state of the entity
162+
"""
163+
options = RpcManagementOptions(
164+
connection_name=connection_name,
165+
task_hub_name=task_hub_name,
166+
entity_Id=entityId,
167+
)
168+
169+
request_url = options.to_url(self._orchestration_bindings.rpc_base_url)
170+
response = await self._get_async_request(request_url)
171+
172+
switch_statement = {
173+
200: lambda: EntityStateResponse(True, response[1]),
174+
404: lambda: EntityStateResponse(False),
175+
}
176+
177+
result = switch_statement.get(response[0])
178+
179+
if not result:
180+
raise Exception(
181+
f"The operation failed with an unexpected status code {response[0]}"
182+
)
183+
184+
return result()
185+
135186
def get_client_response_links(
136187
self,
137188
request: Optional[func.HttpRequest], instance_id: str) -> Dict[str, str]:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import Any
2+
3+
4+
class EntityStateResponse:
5+
"""Entity state response object for [read_entity_state]."""
6+
7+
def __init__(self, entity_exists: bool, entity_state: Any = None) -> None:
8+
self._entity_exists = entity_exists
9+
self._entity_state = entity_state
10+
11+
@property
12+
def entity_exists(self) -> bool:
13+
"""Get the bool representing whether entity exists."""
14+
return self._entity_exists
15+
16+
@property
17+
def entity_state(self) -> Any:
18+
"""Get the state of the entity.
19+
20+
When [entity_exists] is False, this value will be None.
21+
Optional.
22+
"""
23+
return self._entity_state

samples/counter_entity/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,15 @@ Http Functions:
3232

3333
This indicates that your `DurableTrigger` function can be reached via a `GET` or `POST` request to that URL. `DurableTrigger` starts the function-chaning orchestrator whose name is passed as a parameter to the URL. So, to start the orchestrator, which is named `DurableOrchestration`, make a GET request to `http://127.0.0.1:7071/api/orchestrators/DurableOrchestration`.
3434

35-
And that's it! You should see a JSON response with five URLs to monitor the status of the orchestration.
35+
And that's it! You should see a JSON response with five URLs to monitor the status of the orchestration.
36+
37+
### Retrieving the state via the DurableOrchestrationClient
38+
It is possible to retrieve the state of an entity using the `read_entity_state` function. As an example we have the `RetrieveEntity` endpoint which will return the current state of the entity:
39+
40+
```bash
41+
Http Functions:
42+
43+
RetrieveEntity: [GET] http://localhost:7071/api/entity/{entityName}/{entityKey}
44+
```
45+
46+
For our example a call to `http://localhost:7071/api/entity/Counter/myCounter` will return the current state of our counter.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import json
2+
import logging
3+
from typing import Any, Dict, Union, cast
4+
5+
import azure.functions as func
6+
from azure.durable_functions import DurableOrchestrationClient
7+
from azure.durable_functions.models.utils.entity_utils import EntityId
8+
9+
10+
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
11+
client = DurableOrchestrationClient(starter)
12+
entity_name, entity_key = req.route_params["entityName"], req.route_params["entityKey"]
13+
14+
entity_identifier = EntityId(entity_name, entity_key)
15+
16+
entity_state_response = await client.read_entity_state(entity_identifier)
17+
18+
if not entity_state_response.entity_exists:
19+
return func.HttpResponse("Entity not found", status_code=404)
20+
21+
return func.HttpResponse(json.dumps({
22+
"entity": entity_name,
23+
"key": entity_key,
24+
"state": entity_state_response.entity_state
25+
}))
26+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"scriptFile": "__init__.py",
3+
"bindings": [
4+
{
5+
"authLevel": "function",
6+
"name": "req",
7+
"type": "httpTrigger",
8+
"direction": "in",
9+
"route": "entity/{entityName}/{entityKey}",
10+
"methods": [
11+
"get"
12+
]
13+
},
14+
{
15+
"name": "$return",
16+
"type": "http",
17+
"direction": "out"
18+
},
19+
{
20+
"name": "starter",
21+
"type": "durableClient",
22+
"direction": "in"
23+
}
24+
]
25+
}

0 commit comments

Comments
 (0)