durabletask.azuremanaged 1.4.0.dev31__tar.gz → 1.4.0.dev32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/PKG-INFO +1 -1
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/client.py +25 -5
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/internal/access_token_manager.py +5 -1
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/internal/durabletask_grpc_interceptor.py +31 -23
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/worker.py +20 -3
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask.azuremanaged.egg-info/PKG-INFO +1 -1
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/pyproject.toml +1 -1
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/__init__.py +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/internal/py.typed +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask/azuremanaged/py.typed +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask.azuremanaged.egg-info/SOURCES.txt +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask.azuremanaged.egg-info/dependency_links.txt +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask.azuremanaged.egg-info/requires.txt +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/durabletask.azuremanaged.egg-info/top_level.txt +0 -0
- {durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: durabletask.azuremanaged
|
|
3
|
-
Version: 1.4.0.
|
|
3
|
+
Version: 1.4.0.dev32
|
|
4
4
|
Summary: Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler
|
|
5
5
|
Project-URL: repository, https://github.com/microsoft/durabletask-python
|
|
6
6
|
Project-URL: changelog, https://github.com/microsoft/durabletask-python/blob/main/CHANGELOG.md
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
5
|
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Optional, Sequence
|
|
7
7
|
|
|
8
|
+
import grpc
|
|
9
|
+
import grpc.aio
|
|
8
10
|
from azure.core.credentials import TokenCredential
|
|
9
11
|
from azure.core.credentials_async import AsyncTokenCredential
|
|
10
12
|
|
|
@@ -13,6 +15,8 @@ from durabletask.azuremanaged.internal.durabletask_grpc_interceptor import (
|
|
|
13
15
|
DTSDefaultClientInterceptorImpl,
|
|
14
16
|
)
|
|
15
17
|
from durabletask.client import AsyncTaskHubGrpcClient, TaskHubGrpcClient
|
|
18
|
+
from durabletask.grpc_options import GrpcChannelOptions
|
|
19
|
+
import durabletask.internal.shared as shared
|
|
16
20
|
from durabletask.payload.store import PayloadStore
|
|
17
21
|
|
|
18
22
|
|
|
@@ -22,7 +26,10 @@ class DurableTaskSchedulerClient(TaskHubGrpcClient):
|
|
|
22
26
|
host_address: str,
|
|
23
27
|
taskhub: str,
|
|
24
28
|
token_credential: Optional[TokenCredential],
|
|
29
|
+
channel: Optional[grpc.Channel] = None,
|
|
25
30
|
secure_channel: bool = True,
|
|
31
|
+
interceptors: Optional[Sequence[shared.ClientInterceptor]] = None,
|
|
32
|
+
channel_options: Optional[GrpcChannelOptions] = None,
|
|
26
33
|
default_version: Optional[str] = None,
|
|
27
34
|
payload_store: Optional[PayloadStore] = None,
|
|
28
35
|
log_handler: Optional[logging.Handler] = None,
|
|
@@ -31,17 +38,22 @@ class DurableTaskSchedulerClient(TaskHubGrpcClient):
|
|
|
31
38
|
if not taskhub:
|
|
32
39
|
raise ValueError("Taskhub value cannot be empty. Please provide a value for your taskhub")
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
resolved_interceptors: list[shared.ClientInterceptor] = (
|
|
42
|
+
list(interceptors) if interceptors is not None else []
|
|
43
|
+
)
|
|
44
|
+
resolved_interceptors.append(DTSDefaultClientInterceptorImpl(token_credential, taskhub))
|
|
35
45
|
|
|
36
46
|
# We pass in None for the metadata so we don't construct an additional interceptor in the parent class
|
|
37
47
|
# Since the parent class doesn't use anything metadata for anything else, we can set it as None
|
|
38
48
|
super().__init__(
|
|
39
49
|
host_address=host_address,
|
|
50
|
+
channel=channel,
|
|
40
51
|
secure_channel=secure_channel,
|
|
41
52
|
metadata=None,
|
|
42
53
|
log_handler=log_handler,
|
|
43
54
|
log_formatter=log_formatter,
|
|
44
|
-
interceptors=
|
|
55
|
+
interceptors=resolved_interceptors,
|
|
56
|
+
channel_options=channel_options,
|
|
45
57
|
default_version=default_version,
|
|
46
58
|
payload_store=payload_store)
|
|
47
59
|
|
|
@@ -88,7 +100,10 @@ class AsyncDurableTaskSchedulerClient(AsyncTaskHubGrpcClient):
|
|
|
88
100
|
host_address: str,
|
|
89
101
|
taskhub: str,
|
|
90
102
|
token_credential: Optional[AsyncTokenCredential],
|
|
103
|
+
channel: Optional[grpc.aio.Channel] = None,
|
|
91
104
|
secure_channel: bool = True,
|
|
105
|
+
interceptors: Optional[Sequence[shared.AsyncClientInterceptor]] = None,
|
|
106
|
+
channel_options: Optional[GrpcChannelOptions] = None,
|
|
92
107
|
default_version: Optional[str] = None,
|
|
93
108
|
payload_store: Optional[PayloadStore] = None,
|
|
94
109
|
log_handler: Optional[logging.Handler] = None,
|
|
@@ -97,16 +112,21 @@ class AsyncDurableTaskSchedulerClient(AsyncTaskHubGrpcClient):
|
|
|
97
112
|
if not taskhub:
|
|
98
113
|
raise ValueError("Taskhub value cannot be empty. Please provide a value for your taskhub")
|
|
99
114
|
|
|
100
|
-
|
|
115
|
+
resolved_interceptors: list[shared.AsyncClientInterceptor] = (
|
|
116
|
+
list(interceptors) if interceptors is not None else []
|
|
117
|
+
)
|
|
118
|
+
resolved_interceptors.append(DTSAsyncDefaultClientInterceptorImpl(token_credential, taskhub))
|
|
101
119
|
|
|
102
120
|
# We pass in None for the metadata so we don't construct an additional interceptor in the parent class
|
|
103
121
|
# Since the parent class doesn't use anything metadata for anything else, we can set it as None
|
|
104
122
|
super().__init__(
|
|
105
123
|
host_address=host_address,
|
|
124
|
+
channel=channel,
|
|
106
125
|
secure_channel=secure_channel,
|
|
107
126
|
metadata=None,
|
|
108
127
|
log_handler=log_handler,
|
|
109
128
|
log_formatter=log_formatter,
|
|
110
|
-
interceptors=
|
|
129
|
+
interceptors=resolved_interceptors,
|
|
130
|
+
channel_options=channel_options,
|
|
111
131
|
default_version=default_version,
|
|
112
132
|
payload_store=payload_store)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Copyright (c) Microsoft Corporation.
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
from datetime import datetime, timedelta, timezone
|
|
4
|
+
from threading import Lock
|
|
4
5
|
from typing import Optional
|
|
5
6
|
|
|
6
7
|
from azure.core.credentials import AccessToken, TokenCredential
|
|
@@ -20,6 +21,7 @@ class AccessTokenManager:
|
|
|
20
21
|
self._logger = shared.get_logger("token_manager")
|
|
21
22
|
|
|
22
23
|
self._credential = token_credential
|
|
24
|
+
self._refresh_lock = Lock()
|
|
23
25
|
|
|
24
26
|
if self._credential is not None:
|
|
25
27
|
self._token = self._credential.get_token(self._scope)
|
|
@@ -30,7 +32,9 @@ class AccessTokenManager:
|
|
|
30
32
|
|
|
31
33
|
def get_access_token(self) -> Optional[AccessToken]:
|
|
32
34
|
if self._token is None or self.is_token_expired():
|
|
33
|
-
self.
|
|
35
|
+
with self._refresh_lock:
|
|
36
|
+
if self._token is None or self.is_token_expired():
|
|
37
|
+
self.refresh_token()
|
|
34
38
|
return self._token
|
|
35
39
|
|
|
36
40
|
# Checks if the token is expired, or if it will expire in the next "refresh_interval_seconds" seconds.
|
|
@@ -25,7 +25,11 @@ class DTSDefaultClientInterceptorImpl (DefaultClientInterceptorImpl):
|
|
|
25
25
|
StreamUnaryClientInterceptor and StreamStreamClientInterceptor from grpc to add an
|
|
26
26
|
interceptor to add additional headers to all calls as needed."""
|
|
27
27
|
|
|
28
|
-
def __init__(
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
token_credential: Optional[TokenCredential],
|
|
31
|
+
taskhub_name: str,
|
|
32
|
+
worker_id: Optional[str] = None):
|
|
29
33
|
try:
|
|
30
34
|
# Get the version of the azuremanaged package
|
|
31
35
|
sdk_version = version('durabletask-azuremanaged')
|
|
@@ -35,7 +39,9 @@ class DTSDefaultClientInterceptorImpl (DefaultClientInterceptorImpl):
|
|
|
35
39
|
user_agent = f"durabletask-python/{sdk_version}"
|
|
36
40
|
self._metadata = [
|
|
37
41
|
("taskhub", taskhub_name),
|
|
38
|
-
("x-user-agent", user_agent)] # 'user-agent' is a reserved header
|
|
42
|
+
("x-user-agent", user_agent)] # 'user-agent' is a reserved header; use 'x-user-agent'
|
|
43
|
+
if worker_id is not None:
|
|
44
|
+
self._metadata.append(("workerid", worker_id))
|
|
39
45
|
super().__init__(self._metadata)
|
|
40
46
|
|
|
41
47
|
self._token_manager = None
|
|
@@ -44,7 +50,17 @@ class DTSDefaultClientInterceptorImpl (DefaultClientInterceptorImpl):
|
|
|
44
50
|
self._token_manager = AccessTokenManager(token_credential=self._token_credential)
|
|
45
51
|
access_token = self._token_manager.get_access_token()
|
|
46
52
|
if access_token is not None:
|
|
47
|
-
self.
|
|
53
|
+
self._upsert_authorization_header(access_token.token)
|
|
54
|
+
|
|
55
|
+
def _upsert_authorization_header(self, token: str) -> None:
|
|
56
|
+
found = False
|
|
57
|
+
for i, (key, _) in enumerate(self._metadata):
|
|
58
|
+
if key.lower() == "authorization":
|
|
59
|
+
self._metadata[i] = ("authorization", f"Bearer {token}")
|
|
60
|
+
found = True
|
|
61
|
+
break
|
|
62
|
+
if not found:
|
|
63
|
+
self._metadata.append(("authorization", f"Bearer {token}"))
|
|
48
64
|
|
|
49
65
|
def _intercept_call(
|
|
50
66
|
self, client_call_details: _ClientCallDetails) -> grpc.ClientCallDetails:
|
|
@@ -56,15 +72,7 @@ class DTSDefaultClientInterceptorImpl (DefaultClientInterceptorImpl):
|
|
|
56
72
|
if self._token_manager is not None:
|
|
57
73
|
access_token = self._token_manager.get_access_token()
|
|
58
74
|
if access_token is not None:
|
|
59
|
-
|
|
60
|
-
found = False
|
|
61
|
-
for i, (key, _) in enumerate(self._metadata):
|
|
62
|
-
if key.lower() == "authorization":
|
|
63
|
-
self._metadata[i] = ("authorization", f"Bearer {access_token.token}")
|
|
64
|
-
found = True
|
|
65
|
-
break
|
|
66
|
-
if not found:
|
|
67
|
-
self._metadata.append(("authorization", f"Bearer {access_token.token}"))
|
|
75
|
+
self._upsert_authorization_header(access_token.token)
|
|
68
76
|
|
|
69
77
|
return super()._intercept_call(client_call_details)
|
|
70
78
|
|
|
@@ -96,6 +104,16 @@ class DTSAsyncDefaultClientInterceptorImpl(DefaultAsyncClientInterceptorImpl):
|
|
|
96
104
|
self._token_credential = token_credential
|
|
97
105
|
self._token_manager = AsyncAccessTokenManager(token_credential=self._token_credential)
|
|
98
106
|
|
|
107
|
+
def _upsert_authorization_header(self, token: str) -> None:
|
|
108
|
+
found = False
|
|
109
|
+
for i, (key, _) in enumerate(self._metadata):
|
|
110
|
+
if key.lower() == "authorization":
|
|
111
|
+
self._metadata[i] = ("authorization", f"Bearer {token}")
|
|
112
|
+
found = True
|
|
113
|
+
break
|
|
114
|
+
if not found:
|
|
115
|
+
self._metadata.append(("authorization", f"Bearer {token}"))
|
|
116
|
+
|
|
99
117
|
async def _intercept_call(
|
|
100
118
|
self, client_call_details: _AsyncClientCallDetails) -> grpc.aio.ClientCallDetails:
|
|
101
119
|
"""Internal intercept_call implementation which adds metadata to grpc metadata in the RPC
|
|
@@ -106,16 +124,6 @@ class DTSAsyncDefaultClientInterceptorImpl(DefaultAsyncClientInterceptorImpl):
|
|
|
106
124
|
if self._token_manager is not None:
|
|
107
125
|
access_token = await self._token_manager.get_access_token()
|
|
108
126
|
if access_token is not None:
|
|
109
|
-
|
|
110
|
-
# is the first successful token acquisition (token is lazily
|
|
111
|
-
# fetched on the first call since async constructors aren't possible).
|
|
112
|
-
found = False
|
|
113
|
-
for i, (key, _) in enumerate(self._metadata):
|
|
114
|
-
if key.lower() == "authorization":
|
|
115
|
-
self._metadata[i] = ("authorization", f"Bearer {access_token.token}")
|
|
116
|
-
found = True
|
|
117
|
-
break
|
|
118
|
-
if not found:
|
|
119
|
-
self._metadata.append(("authorization", f"Bearer {access_token.token}"))
|
|
127
|
+
self._upsert_authorization_header(access_token.token)
|
|
120
128
|
|
|
121
129
|
return await super()._intercept_call(client_call_details)
|
|
@@ -2,13 +2,19 @@
|
|
|
2
2
|
# Licensed under the MIT License.
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
+
import os
|
|
6
|
+
import socket
|
|
7
|
+
import uuid
|
|
5
8
|
|
|
6
|
-
from typing import Optional
|
|
9
|
+
from typing import Optional, Sequence
|
|
7
10
|
|
|
11
|
+
import grpc
|
|
8
12
|
from azure.core.credentials import TokenCredential
|
|
9
13
|
|
|
10
14
|
from durabletask.azuremanaged.internal.durabletask_grpc_interceptor import \
|
|
11
15
|
DTSDefaultClientInterceptorImpl
|
|
16
|
+
from durabletask.grpc_options import GrpcChannelOptions
|
|
17
|
+
import durabletask.internal.shared as shared
|
|
12
18
|
from durabletask.payload.store import PayloadStore
|
|
13
19
|
from durabletask.worker import ConcurrencyOptions, TaskHubGrpcWorker
|
|
14
20
|
|
|
@@ -64,7 +70,10 @@ class DurableTaskSchedulerWorker(TaskHubGrpcWorker):
|
|
|
64
70
|
host_address: str,
|
|
65
71
|
taskhub: str,
|
|
66
72
|
token_credential: Optional[TokenCredential],
|
|
73
|
+
channel: Optional[grpc.Channel] = None,
|
|
67
74
|
secure_channel: bool = True,
|
|
75
|
+
interceptors: Optional[Sequence[shared.ClientInterceptor]] = None,
|
|
76
|
+
channel_options: Optional[GrpcChannelOptions] = None,
|
|
68
77
|
concurrency_options: Optional[ConcurrencyOptions] = None,
|
|
69
78
|
payload_store: Optional[PayloadStore] = None,
|
|
70
79
|
log_handler: Optional[logging.Handler] = None,
|
|
@@ -73,17 +82,25 @@ class DurableTaskSchedulerWorker(TaskHubGrpcWorker):
|
|
|
73
82
|
if not taskhub:
|
|
74
83
|
raise ValueError("The taskhub value cannot be empty.")
|
|
75
84
|
|
|
76
|
-
|
|
85
|
+
worker_id = f"{socket.gethostname()}:{os.getpid()}:{uuid.uuid4()}"
|
|
86
|
+
resolved_interceptors: list[shared.ClientInterceptor] = (
|
|
87
|
+
list(interceptors) if interceptors is not None else []
|
|
88
|
+
)
|
|
89
|
+
resolved_interceptors.append(
|
|
90
|
+
DTSDefaultClientInterceptorImpl(token_credential, taskhub, worker_id=worker_id)
|
|
91
|
+
)
|
|
77
92
|
|
|
78
93
|
# We pass in None for the metadata so we don't construct an additional interceptor in the parent class
|
|
79
94
|
# Since the parent class doesn't use anything metadata for anything else, we can set it as None
|
|
80
95
|
super().__init__(
|
|
81
96
|
host_address=host_address,
|
|
97
|
+
channel=channel,
|
|
82
98
|
secure_channel=secure_channel,
|
|
83
99
|
metadata=None,
|
|
84
100
|
log_handler=log_handler,
|
|
85
101
|
log_formatter=log_formatter,
|
|
86
|
-
interceptors=
|
|
102
|
+
interceptors=resolved_interceptors,
|
|
103
|
+
channel_options=channel_options,
|
|
87
104
|
concurrency_options=concurrency_options,
|
|
88
105
|
# DTS natively supports long timers so chunking is unnecessary
|
|
89
106
|
maximum_timer_interval=None,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: durabletask.azuremanaged
|
|
3
|
-
Version: 1.4.0.
|
|
3
|
+
Version: 1.4.0.dev32
|
|
4
4
|
Summary: Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler
|
|
5
5
|
Project-URL: repository, https://github.com/microsoft/durabletask-python
|
|
6
6
|
Project-URL: changelog, https://github.com/microsoft/durabletask-python/blob/main/CHANGELOG.md
|
{durabletask_azuremanaged-1.4.0.dev31 → durabletask_azuremanaged-1.4.0.dev32}/pyproject.toml
RENAMED
|
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "durabletask.azuremanaged"
|
|
12
|
-
version = "1.4.0.
|
|
12
|
+
version = "1.4.0.dev32"
|
|
13
13
|
description = "Durable Task Python SDK provider implementation for the Azure Durable Task Scheduler"
|
|
14
14
|
keywords = [
|
|
15
15
|
"durable",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|