Skip to content

Commit ca44c94

Browse files
committed
fix: address copilot feedback
Signed-off-by: Samantha Coyle <sam@diagrid.io>
1 parent fd0ac06 commit ca44c94

10 files changed

Lines changed: 41 additions & 34 deletions

File tree

.github/workflows/build.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ jobs:
7070
# Install and run the durabletask-go sidecar for running e2e tests
7171
- name: Pytest e2e tests for DurableTask Python
7272
run: |
73-
# TODO: use dapr run instead of durabletask-go as it provides a more reliable sidecar behaviorfor e2e tests
74-
go install github.com/dapr/durabletask-go@main
75-
durabletask-go --port 4001 & cd durabletask && \
76-
tox -e py${{ matrix.python-version }}-e2e
73+
# TODO: use dapr run instead of durabletask-go as it provides a more reliable sidecar behavior for e2e tests
74+
go install github.com/dapr/durabletask-go@main
75+
durabletask-go --port 4001 &
76+
pip install -e durabletask[dev]
77+
pytest -m e2e durabletask_tests/
7778
- name: Run examples
7879
run: |
7980
pip install mechanical-markdown

.github/workflows/durabletask-validation.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ jobs:
2828
- name: Install dependencies
2929
run: |
3030
python -m pip install --upgrade pip
31-
pip install .[dev]
31+
pip install -e durabletask[dev]
3232
- name: Lint with ruff
3333
run: |
34-
ruff check
34+
ruff check durabletask/ durabletask_tests/
3535
- name: Pytest unit tests
3636
run: |
37-
tox -e py${{ matrix.python-version }}
37+
pytest -m "not e2e" durabletask_tests/
3838
# Sidecar for running e2e tests requires Go SDK
3939
- name: Install Go SDK
4040
uses: actions/setup-go@v5
@@ -43,11 +43,10 @@ jobs:
4343
# Install and run the durabletask-go sidecar for running e2e tests
4444
- name: Pytest e2e tests
4545
run: |
46-
# TODO: use dapr run instead of durabletask-go as it provides a more reliable sidecar behaviorfor e2e tests
47-
go install github.com/dapr/durabletask-go@main
46+
# TODO: use dapr run instead of durabletask-go as it provides a more reliable sidecar behavior for e2e tests
47+
go install github.com/dapr/durabletask-go@main
4848
durabletask-go --port 4001 &
49-
cd durabletask
50-
tox -e py${{ matrix.python-version }}-e2e
49+
pytest -m e2e durabletask_tests/
5150
- name: Run examples
5251
run: |
5352
pip install mechanical-markdown

durabletask/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def sequence(ctx: task.OrchestrationContext, _):
6565
return [result1, result2, result3]
6666
```
6767

68-
You can find the full sample [here](./examples/activity_sequence.py).
68+
You can find the full sample [here](../durabletask_examples/activity_sequence.py).
6969

7070
### Fan-out/fan-in
7171

@@ -93,11 +93,11 @@ def orchestrator(ctx: task.OrchestrationContext, _):
9393
return {'work_items': work_items, 'results': results, 'total': sum(results)}
9494
```
9595

96-
You can find the full sample [here](./examples/fanout_fanin.py).
96+
You can find the full sample [here](../durabletask_examples/fanout_fanin.py).
9797

9898
### Human interaction and durable timers
9999

100-
An orchestration can wait for a user-defined event, such as a human approval event, before proceding to the next step. In addition, the orchestration can create a timer with an arbitrary duration that triggers some alternate action if the external event hasn't been received:
100+
An orchestration can wait for a user-defined event, such as a human approval event, before proceeding to the next step. In addition, the orchestration can create a timer with an arbitrary duration that triggers some alternate action if the external event hasn't been received:
101101

102102
```python
103103
def purchase_order_workflow(ctx: task.OrchestrationContext, order: Order):
@@ -124,7 +124,7 @@ def purchase_order_workflow(ctx: task.OrchestrationContext, order: Order):
124124

125125
As an aside, you'll also notice that the example orchestration above works with custom business objects. Support for custom business objects includes support for custom classes, custom data classes, and named tuples. Serialization and deserialization of these objects is handled automatically by the SDK.
126126

127-
You can find the full sample [here](./examples/human_interaction.py).
127+
You can find the full sample [here](../durabletask_examples/human_interaction.py).
128128

129129
## Feature overview
130130

durabletask/internal/shared.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,16 @@ def get_logger(
113113
) -> logging.Logger:
114114
logger = logging.getLogger(f"durabletask-{name_suffix}")
115115

116-
# Add a default log handler if none is provided
116+
# Add a log handler only if one is not already present, to avoid duplicate log lines
117+
# when get_logger is called multiple times for the same logger name.
117118
if log_handler is None:
118-
log_handler = logging.StreamHandler()
119-
logger.handlers.append(log_handler)
119+
if not logger.handlers:
120+
log_handler = logging.StreamHandler()
121+
logger.addHandler(log_handler)
122+
else:
123+
log_handler = logger.handlers[0]
124+
elif log_handler not in logger.handlers:
125+
logger.addHandler(log_handler)
120126

121127
# Set a default log formatter to our handler if none is provided
122128
if log_formatter is None:

durabletask/pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ readme = "README.md"
2727
dependencies = [
2828
"grpcio",
2929
"protobuf>=6.31.1,<7.0.0", # follows grpcio generation version https://github.com/grpc/grpc/blob/v1.75.1/tools/distrib/python/grpcio_tools/setup.py
30-
"asyncio"
3130
]
3231

3332
[project.urls]

durabletask/task.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def call_sub_orchestrator(
158158
"""
159159
pass
160160

161-
# TOOD: Add a timeout parameter, which allows the task to be canceled if the event is
161+
# TODO: Add a timeout parameter, which allows the task to be canceled if the event is
162162
# not received within the specified timeout. This requires support for task cancellation.
163163
@abstractmethod
164164
def wait_for_external_event(self, name: str) -> Task:
@@ -352,7 +352,9 @@ def pending_tasks(self) -> int:
352352

353353
def on_child_completed(self, task: Task[T]):
354354
if self.is_complete:
355-
raise ValueError("The task has already completed.")
355+
# A prior child failure may have already completed this composite task.
356+
# Ignore late child completions rather than crashing the orchestration runner.
357+
return
356358
self._completed_tasks += 1
357359
if task.is_failed and self._exception is None:
358360
self._exception = task.get_exception()

durabletask_examples/fanout_fanin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""End-to-end sample that demonstrates how to configure an orchestrator
2-
that a dynamic number activity functions in parallel, waits for them all
2+
that runs a dynamic number of activity functions in parallel, waits for them all
33
to complete, and prints an aggregate summary of the outputs."""
44

55
import random

durabletask_examples/human_interaction.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""End-to-end sample that demonstrates how to configure an orchestrator
2-
that waits for an "approval" event before proceding to the next step. If
2+
that waits for an "approval" event before proceeding to the next step. If
33
the approval isn't received within a specified timeout, the order that is
44
represented by the orchestration is automatically cancelled."""
55

durabletask_tests/durabletask/test_orchestration_e2e.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ def parent_orchestrator(ctx: task.OrchestrationContext, count: int):
351351

352352
time.sleep(1) # Brief delay to let orchestrations start
353353

354-
output = "Recursive termination = {recurse}"
354+
output = f"Recursive termination = {recurse}"
355355
task_hub_client.terminate_orchestration(
356356
instance_id, output=output, recursive=recurse
357357
)

durabletask_tests/durabletask/test_registry.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -185,24 +185,24 @@ def orchestrator3(ctx, input):
185185
)
186186
registry.add_named_orchestrator(name="orchestrator", fn=orchestrator3, version_name="v3")
187187

188-
orquestrator, version = registry.get_orchestrator(name="orchestrator")
189-
assert orquestrator is orchestrator2
188+
orchestrator, version = registry.get_orchestrator(name="orchestrator")
189+
assert orchestrator is orchestrator2
190190
assert version == "v2"
191191

192-
orquestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v1")
193-
assert orquestrator is orchestrator1
192+
orchestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v1")
193+
assert orchestrator is orchestrator1
194194
assert version == "v1"
195195

196-
orquestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v2")
197-
assert orquestrator is orchestrator2
196+
orchestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v2")
197+
assert orchestrator is orchestrator2
198198
assert version == "v2"
199199

200-
orquestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v3")
201-
assert orquestrator is orchestrator3
200+
orchestrator, version = registry.get_orchestrator(name="orchestrator", version_name="v3")
201+
assert orchestrator is orchestrator3
202202
assert version == "v3"
203203

204204
with pytest.raises(worker.VersionNotRegisteredException):
205205
registry.get_orchestrator(name="orchestrator", version_name="v4")
206206

207-
orquestrator, _ = registry.get_orchestrator(name="non-existent")
208-
assert orquestrator is None
207+
orchestrator, _ = registry.get_orchestrator(name="non-existent")
208+
assert orchestrator is None

0 commit comments

Comments
 (0)