Skip to content

Commit 142dcde

Browse files
authored
Merge branch 'main' into andystaples/fix-flaky-ci
2 parents 760efbc + 60ecc95 commit 142dcde

File tree

5 files changed

+345
-156
lines changed

5 files changed

+345
-156
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
---
2+
name: update-protobuf
3+
description: >-
4+
Update the protobuf generated Python files from the latest
5+
microsoft/durabletask-protobuf definitions. Use when the proto definitions
6+
need to be refreshed or regenerated.
7+
---
8+
9+
# Update Protobuf Definitions
10+
11+
This skill regenerates the Python protobuf files in `durabletask/internal/`
12+
from the latest proto source at
13+
<https://github.com/microsoft/durabletask-protobuf>.
14+
15+
## Prerequisites
16+
17+
- Python 3.11 must be available on the system. Verify with `py -3.11 --version`
18+
(Windows) or `python3.11 --version` (Linux/macOS). If it is not installed,
19+
stop and ask the user to install it — do **not** use a different version.
20+
- On Linux/macOS, [`jq`](https://jqlang.github.io/jq/) must be installed.
21+
- Internet access is required to download the proto file and query the GitHub
22+
API.
23+
24+
## Steps
25+
26+
### 1. Set up the `.proto_venv` environment (skip if it already exists)
27+
28+
Check whether `.proto_venv/` already exists at the repo root and whether
29+
`grpcio-tools==1.65.4` is installed in it:
30+
31+
```bash
32+
# Windows
33+
.proto_venv\Scripts\pip.exe list 2>$null | Select-String grpcio-tools
34+
35+
# Bash
36+
.proto_venv/bin/pip list 2>/dev/null | grep grpcio-tools
37+
```
38+
39+
If the venv **does not exist** or `grpcio-tools` is missing, create/recreate it:
40+
41+
```bash
42+
# Windows
43+
py -3.11 -m venv .proto_venv
44+
.proto_venv\Scripts\python.exe -m pip install grpcio-tools==1.65.4
45+
46+
# Bash
47+
python3.11 -m venv .proto_venv
48+
.proto_venv/bin/python -m pip install grpcio-tools==1.65.4
49+
```
50+
51+
> [!NOTE]
52+
> Do **not** delete `.proto_venv` after use. It is reused across runs to avoid
53+
> reinstalling `grpcio-tools` each time. The directory is already in
54+
> `.gitignore`.
55+
56+
### 2. Download the latest proto file
57+
58+
Download from the `main` branch of `microsoft/durabletask-protobuf`:
59+
60+
```bash
61+
# Windows (PowerShell)
62+
Invoke-WebRequest `
63+
-Uri "https://raw.githubusercontent.com/microsoft/durabletask-protobuf/refs/heads/main/protos/orchestrator_service.proto" `
64+
-OutFile "durabletask/internal/orchestrator_service.proto"
65+
66+
# Bash
67+
curl -o durabletask/internal/orchestrator_service.proto \
68+
https://raw.githubusercontent.com/microsoft/durabletask-protobuf/refs/heads/main/protos/orchestrator_service.proto
69+
```
70+
71+
### 3. Regenerate the Python files
72+
73+
Run `grpc_tools.protoc` from the **repo root**:
74+
75+
```bash
76+
# Windows
77+
.proto_venv\Scripts\python.exe -m grpc_tools.protoc --proto_path=. --python_out=. --pyi_out=. --grpc_python_out=. ./durabletask/internal/orchestrator_service.proto
78+
79+
# Bash
80+
.proto_venv/bin/python -m grpc_tools.protoc --proto_path=. --python_out=. --pyi_out=. --grpc_python_out=. ./durabletask/internal/orchestrator_service.proto
81+
```
82+
83+
This produces three files in `durabletask/internal/`:
84+
85+
- `orchestrator_service_pb2.py`
86+
- `orchestrator_service_pb2_grpc.py`
87+
- `orchestrator_service_pb2.pyi`
88+
89+
### 4. Update `PROTO_SOURCE_COMMIT_HASH`
90+
91+
Query the GitHub API for the latest commit that touched the proto file and
92+
**overwrite** `durabletask/internal/PROTO_SOURCE_COMMIT_HASH` with that single
93+
hash:
94+
95+
```bash
96+
# Windows (PowerShell)
97+
$response = Invoke-RestMethod `
98+
-Uri "https://api.github.com/repos/microsoft/durabletask-protobuf/commits?path=protos/orchestrator_service.proto&sha=main&per_page=1"
99+
$response[0].sha | Out-File -FilePath "durabletask/internal/PROTO_SOURCE_COMMIT_HASH" -NoNewline -Encoding ascii
100+
101+
# Bash
102+
curl -s -H "Accept: application/vnd.github.v3+json" \
103+
"https://api.github.com/repos/microsoft/durabletask-protobuf/commits?path=protos/orchestrator_service.proto&sha=main&per_page=1" \
104+
| jq -jr '.[0].sha' > durabletask/internal/PROTO_SOURCE_COMMIT_HASH
105+
```
106+
107+
The file should contain exactly one commit hash with no trailing newline.
108+
109+
### 5. Clean up the downloaded proto file
110+
111+
Delete the `.proto` source file — only the generated Python files are kept in
112+
the repo:
113+
114+
```bash
115+
# Windows
116+
Remove-Item durabletask/internal/orchestrator_service.proto
117+
118+
# Bash
119+
rm durabletask/internal/orchestrator_service.proto
120+
```
121+
122+
### 6. Verify
123+
124+
Confirm the generated modules import successfully using the project's main
125+
venv:
126+
127+
```bash
128+
python -c "from durabletask.internal import orchestrator_service_pb2; print('pb2 OK'); from durabletask.internal import orchestrator_service_pb2_grpc; print('pb2_grpc OK')"
129+
```
130+
131+
## Generated files
132+
133+
| File | Description |
134+
|---|---|
135+
| `durabletask/internal/orchestrator_service_pb2.py` | Message classes |
136+
| `durabletask/internal/orchestrator_service_pb2_grpc.py` | gRPC stubs |
137+
| `durabletask/internal/orchestrator_service_pb2.pyi` | Type stubs |
138+
| `durabletask/internal/PROTO_SOURCE_COMMIT_HASH` | Source commit hash |

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ celerybeat.pid
104104
# Environments
105105
.env
106106
.venv
107+
.proto_venv
107108
env/
108109
venv/
109110
ENV/
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
443b333f4f65a438dc9eb4f090560d232afec4b7
2-
fd9369c6a03d6af4e95285e432b7c4e943c06970
3-
026329c53fe6363985655857b9ca848ec7238bd2
1+
e42905306605b7be6efb789dc489d27e27e22f71

durabletask/internal/orchestrator_service_pb2.py

Lines changed: 159 additions & 149 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

durabletask/internal/orchestrator_service_pb2.pyi

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,14 @@ class SendEntityMessageAction(_message.Message):
593593
entityUnlockSent: EntityUnlockSentEvent
594594
def __init__(self, entityOperationSignaled: _Optional[_Union[EntityOperationSignaledEvent, _Mapping]] = ..., entityOperationCalled: _Optional[_Union[EntityOperationCalledEvent, _Mapping]] = ..., entityLockRequested: _Optional[_Union[EntityLockRequestedEvent, _Mapping]] = ..., entityUnlockSent: _Optional[_Union[EntityUnlockSentEvent, _Mapping]] = ...) -> None: ...
595595

596+
class RewindOrchestrationAction(_message.Message):
597+
__slots__ = ("newHistory",)
598+
NEWHISTORY_FIELD_NUMBER: _ClassVar[int]
599+
newHistory: _containers.RepeatedCompositeFieldContainer[HistoryEvent]
600+
def __init__(self, newHistory: _Optional[_Iterable[_Union[HistoryEvent, _Mapping]]] = ...) -> None: ...
601+
596602
class OrchestratorAction(_message.Message):
597-
__slots__ = ("id", "scheduleTask", "createSubOrchestration", "createTimer", "sendEvent", "completeOrchestration", "terminateOrchestration", "sendEntityMessage")
603+
__slots__ = ("id", "scheduleTask", "createSubOrchestration", "createTimer", "sendEvent", "completeOrchestration", "terminateOrchestration", "sendEntityMessage", "rewindOrchestration")
598604
ID_FIELD_NUMBER: _ClassVar[int]
599605
SCHEDULETASK_FIELD_NUMBER: _ClassVar[int]
600606
CREATESUBORCHESTRATION_FIELD_NUMBER: _ClassVar[int]
@@ -603,6 +609,7 @@ class OrchestratorAction(_message.Message):
603609
COMPLETEORCHESTRATION_FIELD_NUMBER: _ClassVar[int]
604610
TERMINATEORCHESTRATION_FIELD_NUMBER: _ClassVar[int]
605611
SENDENTITYMESSAGE_FIELD_NUMBER: _ClassVar[int]
612+
REWINDORCHESTRATION_FIELD_NUMBER: _ClassVar[int]
606613
id: int
607614
scheduleTask: ScheduleTaskAction
608615
createSubOrchestration: CreateSubOrchestrationAction
@@ -611,7 +618,8 @@ class OrchestratorAction(_message.Message):
611618
completeOrchestration: CompleteOrchestrationAction
612619
terminateOrchestration: TerminateOrchestrationAction
613620
sendEntityMessage: SendEntityMessageAction
614-
def __init__(self, id: _Optional[int] = ..., scheduleTask: _Optional[_Union[ScheduleTaskAction, _Mapping]] = ..., createSubOrchestration: _Optional[_Union[CreateSubOrchestrationAction, _Mapping]] = ..., createTimer: _Optional[_Union[CreateTimerAction, _Mapping]] = ..., sendEvent: _Optional[_Union[SendEventAction, _Mapping]] = ..., completeOrchestration: _Optional[_Union[CompleteOrchestrationAction, _Mapping]] = ..., terminateOrchestration: _Optional[_Union[TerminateOrchestrationAction, _Mapping]] = ..., sendEntityMessage: _Optional[_Union[SendEntityMessageAction, _Mapping]] = ...) -> None: ...
621+
rewindOrchestration: RewindOrchestrationAction
622+
def __init__(self, id: _Optional[int] = ..., scheduleTask: _Optional[_Union[ScheduleTaskAction, _Mapping]] = ..., createSubOrchestration: _Optional[_Union[CreateSubOrchestrationAction, _Mapping]] = ..., createTimer: _Optional[_Union[CreateTimerAction, _Mapping]] = ..., sendEvent: _Optional[_Union[SendEventAction, _Mapping]] = ..., completeOrchestration: _Optional[_Union[CompleteOrchestrationAction, _Mapping]] = ..., terminateOrchestration: _Optional[_Union[TerminateOrchestrationAction, _Mapping]] = ..., sendEntityMessage: _Optional[_Union[SendEntityMessageAction, _Mapping]] = ..., rewindOrchestration: _Optional[_Union[RewindOrchestrationAction, _Mapping]] = ...) -> None: ...
615623

616624
class OrchestrationTraceContext(_message.Message):
617625
__slots__ = ("spanID", "spanStartTime")
@@ -1250,16 +1258,50 @@ class SkipGracefulOrchestrationTerminationsResponse(_message.Message):
12501258
def __init__(self, unterminatedInstanceIds: _Optional[_Iterable[str]] = ...) -> None: ...
12511259

12521260
class GetWorkItemsRequest(_message.Message):
1253-
__slots__ = ("maxConcurrentOrchestrationWorkItems", "maxConcurrentActivityWorkItems", "maxConcurrentEntityWorkItems", "capabilities")
1261+
__slots__ = ("maxConcurrentOrchestrationWorkItems", "maxConcurrentActivityWorkItems", "maxConcurrentEntityWorkItems", "capabilities", "workItemFilters")
12541262
MAXCONCURRENTORCHESTRATIONWORKITEMS_FIELD_NUMBER: _ClassVar[int]
12551263
MAXCONCURRENTACTIVITYWORKITEMS_FIELD_NUMBER: _ClassVar[int]
12561264
MAXCONCURRENTENTITYWORKITEMS_FIELD_NUMBER: _ClassVar[int]
12571265
CAPABILITIES_FIELD_NUMBER: _ClassVar[int]
1266+
WORKITEMFILTERS_FIELD_NUMBER: _ClassVar[int]
12581267
maxConcurrentOrchestrationWorkItems: int
12591268
maxConcurrentActivityWorkItems: int
12601269
maxConcurrentEntityWorkItems: int
12611270
capabilities: _containers.RepeatedScalarFieldContainer[WorkerCapability]
1262-
def __init__(self, maxConcurrentOrchestrationWorkItems: _Optional[int] = ..., maxConcurrentActivityWorkItems: _Optional[int] = ..., maxConcurrentEntityWorkItems: _Optional[int] = ..., capabilities: _Optional[_Iterable[_Union[WorkerCapability, str]]] = ...) -> None: ...
1271+
workItemFilters: WorkItemFilters
1272+
def __init__(self, maxConcurrentOrchestrationWorkItems: _Optional[int] = ..., maxConcurrentActivityWorkItems: _Optional[int] = ..., maxConcurrentEntityWorkItems: _Optional[int] = ..., capabilities: _Optional[_Iterable[_Union[WorkerCapability, str]]] = ..., workItemFilters: _Optional[_Union[WorkItemFilters, _Mapping]] = ...) -> None: ...
1273+
1274+
class WorkItemFilters(_message.Message):
1275+
__slots__ = ("orchestrations", "activities", "entities")
1276+
ORCHESTRATIONS_FIELD_NUMBER: _ClassVar[int]
1277+
ACTIVITIES_FIELD_NUMBER: _ClassVar[int]
1278+
ENTITIES_FIELD_NUMBER: _ClassVar[int]
1279+
orchestrations: _containers.RepeatedCompositeFieldContainer[OrchestrationFilter]
1280+
activities: _containers.RepeatedCompositeFieldContainer[ActivityFilter]
1281+
entities: _containers.RepeatedCompositeFieldContainer[EntityFilter]
1282+
def __init__(self, orchestrations: _Optional[_Iterable[_Union[OrchestrationFilter, _Mapping]]] = ..., activities: _Optional[_Iterable[_Union[ActivityFilter, _Mapping]]] = ..., entities: _Optional[_Iterable[_Union[EntityFilter, _Mapping]]] = ...) -> None: ...
1283+
1284+
class OrchestrationFilter(_message.Message):
1285+
__slots__ = ("name", "versions")
1286+
NAME_FIELD_NUMBER: _ClassVar[int]
1287+
VERSIONS_FIELD_NUMBER: _ClassVar[int]
1288+
name: str
1289+
versions: _containers.RepeatedScalarFieldContainer[str]
1290+
def __init__(self, name: _Optional[str] = ..., versions: _Optional[_Iterable[str]] = ...) -> None: ...
1291+
1292+
class ActivityFilter(_message.Message):
1293+
__slots__ = ("name", "versions")
1294+
NAME_FIELD_NUMBER: _ClassVar[int]
1295+
VERSIONS_FIELD_NUMBER: _ClassVar[int]
1296+
name: str
1297+
versions: _containers.RepeatedScalarFieldContainer[str]
1298+
def __init__(self, name: _Optional[str] = ..., versions: _Optional[_Iterable[str]] = ...) -> None: ...
1299+
1300+
class EntityFilter(_message.Message):
1301+
__slots__ = ("name",)
1302+
NAME_FIELD_NUMBER: _ClassVar[int]
1303+
name: str
1304+
def __init__(self, name: _Optional[str] = ...) -> None: ...
12631305

12641306
class WorkItem(_message.Message):
12651307
__slots__ = ("orchestratorRequest", "activityRequest", "entityRequest", "healthPing", "entityRequestV2", "completionToken")

0 commit comments

Comments
 (0)