Skip to content

Commit dce23a4

Browse files
authored
Add Azure Managed on-demand sandbox preview APIs (#151)
1 parent 5b048fe commit dce23a4

29 files changed

Lines changed: 2786 additions & 322 deletions

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99

1010
ADDED
1111

12+
- Added overridable activity-dispatch hooks `_on_activity_execution_started`
13+
and `_on_activity_execution_completed` on `TaskHubGrpcWorker`, invoked
14+
immediately before each activity runs and in a `finally` after it completes
15+
or fails. Subclasses can override these to observe in-flight activity
16+
execution (for example, to track the number of activities currently
17+
running).
1218
- Added `durabletask.extensions.history_export` for exporting the event history of
1319
terminal orchestrations to an external destination. Includes
1420
`ExportHistoryClient`, a per-job `ExportHistoryJobClient` returned by

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ install:
99

1010
gen-proto:
1111
curl -o durabletask/internal/orchestrator_service.proto https://raw.githubusercontent.com/microsoft/durabletask-protobuf/refs/heads/main/protos/orchestrator_service.proto
12-
curl -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/microsoft/durabletask-protobuf/commits?path=protos/orchestrator_service.proto&sha=main&per_page=1" | jq -r '.[0].sha' >> durabletask/internal/PROTO_SOURCE_COMMIT_HASH
12+
curl -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/microsoft/durabletask-protobuf/commits?path=protos/orchestrator_service.proto&sha=main&per_page=1" | jq -r '.[0].sha' > durabletask/internal/PROTO_SOURCE_COMMIT_HASH
1313
python3 -m grpc_tools.protoc --proto_path=. --python_out=. --pyi_out=. --grpc_python_out=. ./durabletask/internal/orchestrator_service.proto
1414
rm durabletask/internal/*.proto
15+
SANDBOX_PROTO_SOURCE_COMMIT_HASH=$$(cat durabletask-azuremanaged/durabletask/azuremanaged/internal/SANDBOX_PROTO_SOURCE_COMMIT_HASH); \
16+
curl -o durabletask-azuremanaged/durabletask/azuremanaged/internal/sandbox_service.proto https://raw.githubusercontent.com/microsoft/durabletask-protobuf/$${SANDBOX_PROTO_SOURCE_COMMIT_HASH}/protos/durable-task-scheduler/sandbox_service.proto
17+
python3 -m grpc_tools.protoc --proto_path=durabletask-azuremanaged --python_out=durabletask-azuremanaged --pyi_out=durabletask-azuremanaged --grpc_python_out=durabletask-azuremanaged ./durabletask-azuremanaged/durabletask/azuremanaged/internal/sandbox_service.proto
18+
rm durabletask-azuremanaged/durabletask/azuremanaged/internal/*.proto
1519

1620
.PHONY: init test gen-proto install

durabletask-azuremanaged/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
66
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## Unreleased
9+
10+
- Updates base dependency to durabletask v1.6.0.
11+
- Added preview support for Durable Task Scheduler on-demand sandbox
12+
activities under `durabletask.azuremanaged.preview.sandboxes`. Applications
13+
can declare sandbox activities (with optional per-activity versions),
14+
register sandbox worker profiles, and run a sandbox activity worker that
15+
establishes a live worker session and dispatches only the activities it
16+
has registered.
17+
818
## v1.5.0
919

1020
- Updates base dependency to durabletask v1.5.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
67a2f1d3b9ea8a210eb86addb636a5d8a6484dbc

durabletask-azuremanaged/durabletask/azuremanaged/internal/sandbox_service_pb2.py

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
from google.protobuf.internal import containers as _containers
2+
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
3+
from google.protobuf import descriptor as _descriptor
4+
from google.protobuf import message as _message
5+
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
6+
7+
DESCRIPTOR: _descriptor.FileDescriptor
8+
9+
class SandboxProviderKind(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
10+
__slots__ = ()
11+
SANDBOX_PROVIDER_KIND_UNSPECIFIED: _ClassVar[SandboxProviderKind]
12+
SANDBOX_PROVIDER_KIND_ACA_SESSION_POOL: _ClassVar[SandboxProviderKind]
13+
SANDBOX_PROVIDER_KIND_SANDBOX: _ClassVar[SandboxProviderKind]
14+
SANDBOX_PROVIDER_KIND_UNSPECIFIED: SandboxProviderKind
15+
SANDBOX_PROVIDER_KIND_ACA_SESSION_POOL: SandboxProviderKind
16+
SANDBOX_PROVIDER_KIND_SANDBOX: SandboxProviderKind
17+
18+
class SandboxActivityWorkerMessage(_message.Message):
19+
__slots__ = ("start", "heartbeat")
20+
START_FIELD_NUMBER: _ClassVar[int]
21+
HEARTBEAT_FIELD_NUMBER: _ClassVar[int]
22+
start: SandboxActivityWorkerStart
23+
heartbeat: SandboxActivityWorkerHeartbeat
24+
def __init__(self, start: _Optional[_Union[SandboxActivityWorkerStart, _Mapping]] = ..., heartbeat: _Optional[_Union[SandboxActivityWorkerHeartbeat, _Mapping]] = ...) -> None: ...
25+
26+
class SandboxActivityWorkerStart(_message.Message):
27+
__slots__ = ("task_hub", "max_activities_count", "sandbox_provider", "dts_sandbox_identifier", "worker_profile_id", "activities")
28+
TASK_HUB_FIELD_NUMBER: _ClassVar[int]
29+
MAX_ACTIVITIES_COUNT_FIELD_NUMBER: _ClassVar[int]
30+
SANDBOX_PROVIDER_FIELD_NUMBER: _ClassVar[int]
31+
DTS_SANDBOX_IDENTIFIER_FIELD_NUMBER: _ClassVar[int]
32+
WORKER_PROFILE_ID_FIELD_NUMBER: _ClassVar[int]
33+
ACTIVITIES_FIELD_NUMBER: _ClassVar[int]
34+
task_hub: str
35+
max_activities_count: int
36+
sandbox_provider: SandboxProviderKind
37+
dts_sandbox_identifier: str
38+
worker_profile_id: str
39+
activities: _containers.RepeatedCompositeFieldContainer[SandboxActivity]
40+
def __init__(self, task_hub: _Optional[str] = ..., max_activities_count: _Optional[int] = ..., sandbox_provider: _Optional[_Union[SandboxProviderKind, str]] = ..., dts_sandbox_identifier: _Optional[str] = ..., worker_profile_id: _Optional[str] = ..., activities: _Optional[_Iterable[_Union[SandboxActivity, _Mapping]]] = ...) -> None: ...
41+
42+
class SandboxActivityWorkerHeartbeat(_message.Message):
43+
__slots__ = ("active_activities_count",)
44+
ACTIVE_ACTIVITIES_COUNT_FIELD_NUMBER: _ClassVar[int]
45+
active_activities_count: int
46+
def __init__(self, active_activities_count: _Optional[int] = ...) -> None: ...
47+
48+
class SandboxActivityWorkerSessionResult(_message.Message):
49+
__slots__ = ("message",)
50+
MESSAGE_FIELD_NUMBER: _ClassVar[int]
51+
message: str
52+
def __init__(self, message: _Optional[str] = ...) -> None: ...
53+
54+
class SandboxWorkerProfile(_message.Message):
55+
__slots__ = ("worker_profile_id", "activities", "image", "environment_variables", "max_concurrent_activities", "resources", "scheduler_managed_identity_client_id")
56+
class EnvironmentVariablesEntry(_message.Message):
57+
__slots__ = ("key", "value")
58+
KEY_FIELD_NUMBER: _ClassVar[int]
59+
VALUE_FIELD_NUMBER: _ClassVar[int]
60+
key: str
61+
value: str
62+
def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
63+
WORKER_PROFILE_ID_FIELD_NUMBER: _ClassVar[int]
64+
ACTIVITIES_FIELD_NUMBER: _ClassVar[int]
65+
IMAGE_FIELD_NUMBER: _ClassVar[int]
66+
ENVIRONMENT_VARIABLES_FIELD_NUMBER: _ClassVar[int]
67+
MAX_CONCURRENT_ACTIVITIES_FIELD_NUMBER: _ClassVar[int]
68+
RESOURCES_FIELD_NUMBER: _ClassVar[int]
69+
SCHEDULER_MANAGED_IDENTITY_CLIENT_ID_FIELD_NUMBER: _ClassVar[int]
70+
worker_profile_id: str
71+
activities: _containers.RepeatedCompositeFieldContainer[SandboxActivity]
72+
image: SandboxActivityImage
73+
environment_variables: _containers.ScalarMap[str, str]
74+
max_concurrent_activities: int
75+
resources: SandboxActivityResources
76+
scheduler_managed_identity_client_id: str
77+
def __init__(self, worker_profile_id: _Optional[str] = ..., activities: _Optional[_Iterable[_Union[SandboxActivity, _Mapping]]] = ..., image: _Optional[_Union[SandboxActivityImage, _Mapping]] = ..., environment_variables: _Optional[_Mapping[str, str]] = ..., max_concurrent_activities: _Optional[int] = ..., resources: _Optional[_Union[SandboxActivityResources, _Mapping]] = ..., scheduler_managed_identity_client_id: _Optional[str] = ...) -> None: ...
78+
79+
class SandboxActivity(_message.Message):
80+
__slots__ = ("name", "version")
81+
NAME_FIELD_NUMBER: _ClassVar[int]
82+
VERSION_FIELD_NUMBER: _ClassVar[int]
83+
name: str
84+
version: str
85+
def __init__(self, name: _Optional[str] = ..., version: _Optional[str] = ...) -> None: ...
86+
87+
class SandboxActivityImage(_message.Message):
88+
__slots__ = ("image_ref", "managed_identity_client_id", "entrypoint", "cmd")
89+
IMAGE_REF_FIELD_NUMBER: _ClassVar[int]
90+
MANAGED_IDENTITY_CLIENT_ID_FIELD_NUMBER: _ClassVar[int]
91+
ENTRYPOINT_FIELD_NUMBER: _ClassVar[int]
92+
CMD_FIELD_NUMBER: _ClassVar[int]
93+
image_ref: str
94+
managed_identity_client_id: str
95+
entrypoint: _containers.RepeatedScalarFieldContainer[str]
96+
cmd: _containers.RepeatedScalarFieldContainer[str]
97+
def __init__(self, image_ref: _Optional[str] = ..., managed_identity_client_id: _Optional[str] = ..., entrypoint: _Optional[_Iterable[str]] = ..., cmd: _Optional[_Iterable[str]] = ...) -> None: ...
98+
99+
class SandboxActivityResources(_message.Message):
100+
__slots__ = ("cpu", "memory")
101+
CPU_FIELD_NUMBER: _ClassVar[int]
102+
MEMORY_FIELD_NUMBER: _ClassVar[int]
103+
cpu: str
104+
memory: str
105+
def __init__(self, cpu: _Optional[str] = ..., memory: _Optional[str] = ...) -> None: ...
106+
107+
class DeclareSandboxWorkerProfileResult(_message.Message):
108+
__slots__ = ()
109+
def __init__(self) -> None: ...
110+
111+
class RemoveSandboxWorkerProfileRequest(_message.Message):
112+
__slots__ = ("worker_profile_id",)
113+
WORKER_PROFILE_ID_FIELD_NUMBER: _ClassVar[int]
114+
worker_profile_id: str
115+
def __init__(self, worker_profile_id: _Optional[str] = ...) -> None: ...
116+
117+
class RemoveSandboxWorkerProfileResult(_message.Message):
118+
__slots__ = ()
119+
def __init__(self) -> None: ...

0 commit comments

Comments
 (0)