Visitar URL original
feat!: unify the durable task client into dapr-sdk-workflows (#1800) · dapr/java-sdk@6e846a6 · GitHub
Skip to content

Commit 6e846a6

Browse files
feat!: unify the durable task client into dapr-sdk-workflows (#1800)
* feat!: unify the durable task client into dapr-sdk-workflows The durabletask-client module duplicated much of the workflows API across a module boundary, which forced an adapter layer and a second copy of a dozen types. Fold it into dapr-sdk-workflows and remove it. The absorbed types move from io.dapr.durabletask.* to io.dapr.workflows.task.*, split into client, worker, history, exception, serialization and internal subpackages. Twelve duplicate type-pairs collapse to one each. Most significantly TaskOrchestrationContext becomes WorkflowContext and is implemented directly by the replay executor, so the DefaultWorkflowContext adapter and the converter and wrapper classes it required are gone. Two behaviour changes come with the merge: - The runtime's default executor is a virtual-thread-per-task executor on Java 21+, resolved reflectively so the module still compiles at release 17 and never names a Java 21 API. WorkflowRuntime now tracks whether it created the executor and no longer shuts down one supplied by the caller, so handing it a framework-managed executor is safe. - WorkflowRuntimeStatus absorbs the protobuf mapping and gains STALLED, which the deleted converter rejected with an exception. isCausedBy maps the exception names that shipped under io.dapr.durabletask onto their current types, so a workflow started before the upgrade still resolves its failure type after it. The CI job that built durabletask-client now installs its reactor dependencies first: unlike the old module, the merged one depends on the sibling dapr-sdk and cannot be built standalone. BREAKING CHANGE: io.dapr:durabletask-client is removed and its classes ship in io.dapr:dapr-sdk-workflows. Types move from io.dapr.durabletask.* to io.dapr.workflows.task.*, seven types are renamed, and the four @deprecated(forRemoval) DaprWorkflowClient methods together with WorkflowInstanceStatus are removed. See MIGRATION.md for the full type mapping and for what it means for workflows that are already running. Signed-off-by: Javier Aliaga <javier@diagrid.io> * docs: add a migration guide for the unified workflows module Folding durabletask-client into dapr-sdk-workflows is a breaking change, so document it where an upgrader will look: MIGRATION.md carries the full old-to-new type mapping, the renames, the removed API, the behaviour changes that are invisible to the compiler, and a tested rewrite script for the mechanical import changes. The section on workflows that are already running is the important one. The error type is persisted into workflow history, so a workflow started before the upgrade carries the old exception names; the guide explains what the SDK maps for you and what it does not. Link the guide from README.md and SUPPORT.md, drop durabletask-client from the module lists in both, and record that Java 21 is recommended for workflows now that the default executor uses virtual threads there. Signed-off-by: Javier Aliaga <javier@diagrid.io> * refactor: narrow the workflow exception constructors back to package-private Splitting the folded durable task types into subpackages moved the executor away from the exceptions it constructs, and the visibility was widened to compensate. It was widened further than the split required: every constructor on both classes became public where only the two the executor actually calls needed to be. Restore the rest to package-private, matching what they were before the merge. The two that stay public are the ones the executor constructs from io.dapr.workflows.task.internal, and their javadoc now says so accurately — the previous note claimed a sibling-package caller for members that have none. No test used any of these constructors, and no behaviour changes. Signed-off-by: Javier Aliaga <javier@diagrid.io> * docs: name the SDK line that carries the workflows module unification State in SUPPORT.md that durabletask-client is folded into dapr-sdk-workflows in 1.19.x, so a user reading the version table knows which upgrade requires the source changes described in MIGRATION.md. Signed-off-by: Javier Aliaga <javier@diagrid.io> * test: cover the durable task sources folded into dapr-sdk-workflows The durabletask-client module had no jacoco configuration, so none of its sources were measured. Folding them into dapr-sdk-workflows brings them into the report, where the untested ones stood out: the activity and orchestration runners had no tests at all. Adds unit tests for the runners, the orchestration context operations that fan tasks in and out, the gRPC client management operations, the client convenience overloads and their cross-app guard, and the argument checks on the helpers, converters, factories and builders. Line coverage for the module goes from 70% to 86%, so the temporary 60% jacoco threshold this branch introduced is removed and the module is back on the repo-wide 80% default. Signed-off-by: Javier Aliaga <javier@diagrid.io> * fix: reject a null workflow status and cover the executor ownership decision WorkflowRuntimeStatus.fromProtobuf threw NullPointerException on a null status, where the converter it replaced threw IllegalArgumentException with a message and had a test for it. Restores that behaviour. WorkflowRuntimeBuilder decides whether the runtime owns the executor it was built with, but the lifecycle tests passed that flag straight to the WorkflowRuntime constructor, so nothing pinned the decision itself. Adds two tests that go through build(), one per outcome; inverting the decision fails both. Signed-off-by: Javier Aliaga <javier@diagrid.io> * fix: exclude generated durabletask protobuf classes from SpotBugs Signed-off-by: Javier Aliaga <javier@diagrid.io> * docs: note that the unified workflows module ships in 1.20.x Signed-off-by: Javier Aliaga <javier@diagrid.io> * fix: wait for in-flight work on a caller-supplied executor before close returns close() does not shut down an executor the caller supplied, so it also did not wait for the orchestrations and activities submitted to it. The runtime could then close the sidecar channel while they still needed it. The worker now counts the runners it submits and close() waits up to 60 seconds for them, without shutting the executor down. Signed-off-by: Javier Aliaga <javier@diagrid.io> * fix: reject a non-finite retry backoff coefficient NaN passed the 'less than 1.0' check because every comparison with NaN is false, and the executor then turned it into a zero retry delay. The constructor and the builder setter now reject NaN and infinity. Signed-off-by: Javier Aliaga <javier@diagrid.io> * fix: drop a work item that arrives after close starts draining The worker thread can already hold a work item from the stream when close() runs. It then submitted that item after the drain had returned, so the item ran against a channel that was about to close. The submit now checks for shutdown under the same lock as the in-flight count and drops the item; the sidecar redelivers it because it was never completed. Signed-off-by: Javier Aliaga <javier@diagrid.io> * test: cover DurableTaskGrpcClient option mapping, sidecar errors and TLS failures Covers the empty orchestrator name check, version and start time mapping, terminate output, the DEADLINE_EXCEEDED to TimeoutException mapping and rethrow of other errors for waitForInstanceStart, waitForInstanceCompletion and purgeInstances, and the errors raised when TLS certificate files cannot be read. Signed-off-by: Javier Aliaga <javier@diagrid.io> --------- Signed-off-by: Javier Aliaga <javier@diagrid.io>
1 parent 3bf68c9 commit 6e846a6

161 files changed

Lines changed: 5633 additions & 4408 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/build.yml‎

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ jobs:
4646
name: report-dapr-java-sdk-actors-jdk${{ env.JDK_VER }}
4747
path: sdk-actors/target/jacoco-report/
4848

49-
build-durabletask:
50-
name: "Durable Task build & tests"
49+
build-workflows:
50+
name: "Workflows build & tests"
5151
runs-on: ubuntu-latest
5252
# The job timeout covers every retry attempt, so it must fit setup plus max_attempts x timeout_minutes.
5353
timeout-minutes: 15
@@ -61,6 +61,13 @@ jobs:
6161
with:
6262
distribution: 'temurin'
6363
java-version: ${{ env.JDK_VER }}
64+
65+
# sdk-workflows depends on the sibling `dapr-sdk` module, so `-pl sdk-workflows` cannot
66+
# resolve it from a repository on a clean runner. Install the module and its upstream
67+
# reactor dependencies first, as the `build` job does.
68+
- name: Install sdk-workflows and its reactor dependencies
69+
run: ./mvnw clean install -B -q -DskipTests -pl sdk-workflows -am
70+
6471
- name: Checkout Durable Task Sidecar
6572
uses: actions/checkout@v7
6673
with:
@@ -78,13 +85,15 @@ jobs:
7885
- name: Wait for 10 seconds
7986
run: sleep 10
8087

81-
- name: Integration Tests For Durable Tasks
88+
- name: Integration Tests For Workflows
8289
uses: nick-fields/retry@v4
8390
with:
8491
max_attempts: 2
8592
timeout_minutes: 5
8693
retry_wait_seconds: 15
87-
command: ./mvnw -B -pl durabletask-client -Pintegration-tests clean dependency:copy-dependencies verify
94+
# jacoco.skip: this profile skips surefire, so there is no unit-test coverage to
95+
# measure here. The gate is enforced in the "Unit tests" job, which runs surefire.
96+
command: ./mvnw -B -pl sdk-workflows -Pintegration-tests -Djacoco.skip=true clean dependency:copy-dependencies verify
8897

8998
- name: Kill Durable Task Sidecar
9099
run: docker rm -f durabletask-sidecar || true
@@ -129,7 +138,7 @@ jobs:
129138
max_attempts: 2
130139
timeout_minutes: 25
131140
retry_wait_seconds: 15
132-
command: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -pl !durabletask-client -Pintegration-tests clean dependency:copy-dependencies verify
141+
command: PRODUCT_SPRING_BOOT_VERSION=${{ matrix.spring-boot-version }} ./mvnw -B -pl !sdk-workflows -Pintegration-tests clean dependency:copy-dependencies verify
133142
- name: Upload failsafe test report for sdk-tests on failure
134143
if: ${{ failure() && steps.integration_tests.conclusion == 'failure' }}
135144
uses: actions/upload-artifact@v7
@@ -194,7 +203,7 @@ jobs:
194203

195204
publish:
196205
runs-on: ubuntu-latest
197-
needs: [ build, test, build-durabletask ]
206+
needs: [ build, test, build-workflows ]
198207
timeout-minutes: 10
199208
env:
200209
JDK_VER: 17

‎MIGRATION.md‎

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# Migrating workflows to the unified `dapr-sdk-workflows`
2+
3+
The durable task client has been folded into the workflows SDK. `io.dapr:durabletask-client` no
4+
longer exists as a separate artifact, and everything it contained now ships inside
5+
`io.dapr:dapr-sdk-workflows` under `io.dapr.workflows.*`.
6+
7+
This is a **breaking change**. Most of it is mechanical: change a dependency, change some imports.
8+
A smaller part needs real attention, and one item affects workflows that are already running when
9+
you upgrade. Read [Behaviour changes](#4-behaviour-changes) and [Workflows already
10+
running](#5-workflows-already-running) even if the rest applies cleanly.
11+
12+
---
13+
14+
## 1. Dependencies
15+
16+
Remove `durabletask-client`. It is gone, and its classes are in `dapr-sdk-workflows`.
17+
18+
```xml
19+
<!-- before -->
20+
<dependency>
21+
<groupId>io.dapr</groupId>
22+
<artifactId>dapr-sdk-workflows</artifactId>
23+
</dependency>
24+
<dependency>
25+
<groupId>io.dapr</groupId>
26+
<artifactId>durabletask-client</artifactId>
27+
</dependency>
28+
29+
<!-- after -->
30+
<dependency>
31+
<groupId>io.dapr</groupId>
32+
<artifactId>dapr-sdk-workflows</artifactId>
33+
</dependency>
34+
```
35+
36+
If you import `dapr-sdk-bom`, nothing changes beyond removing any explicit `durabletask-client`
37+
dependency: the BOM no longer manages that artifact.
38+
39+
> **Do not keep the old `durabletask-client` on the classpath alongside the new
40+
> `dapr-sdk-workflows`.** Both jars contain the generated protobuf classes under
41+
> `io.dapr.durabletask.implementation.protobuf`, so the two will collide. Which copy wins is
42+
> whichever the classloader reaches first.
43+
44+
---
45+
46+
## 2. What most codebases actually have to change
47+
48+
These are the types application code normally names. If you only use these, the migration is an
49+
import rewrite.
50+
51+
| Was | Now |
52+
|---|---|
53+
| `io.dapr.durabletask.Task` | `io.dapr.workflows.task.Task` |
54+
| `io.dapr.durabletask.TaskFailedException` | `io.dapr.workflows.task.exception.TaskFailedException` |
55+
| `io.dapr.durabletask.TaskCanceledException` | `io.dapr.workflows.task.exception.TaskCanceledException` |
56+
| `io.dapr.durabletask.CompositeTaskFailedException` | `io.dapr.workflows.task.exception.CompositeTaskFailedException` |
57+
| `io.dapr.durabletask.interruption.OrchestratorBlockedException` | `io.dapr.workflows.task.interruption.OrchestratorBlockedException` |
58+
| `io.dapr.durabletask.interruption.ContinueAsNewInterruption` | `io.dapr.workflows.task.interruption.ContinueAsNewInterruption` |
59+
| `io.dapr.durabletask.PropagatedHistory` | `io.dapr.workflows.task.history.PropagatedHistory` |
60+
| `io.dapr.durabletask.HistoryPropagationScope` | `io.dapr.workflows.task.history.HistoryPropagationScope` |
61+
| `io.dapr.durabletask.WorkflowResult` | `io.dapr.workflows.task.history.WorkflowResult` |
62+
| `io.dapr.durabletask.ActivityResult` | `io.dapr.workflows.task.history.ActivityResult` |
63+
| `io.dapr.durabletask.ChildWorkflowResult` | `io.dapr.workflows.task.history.ChildWorkflowResult` |
64+
65+
**Unchanged.** `Workflow`, `WorkflowActivity`, `WorkflowActivityContext`, `WorkflowState`,
66+
`WorkflowRuntime`, `WorkflowRuntimeBuilder` and `DaprWorkflowClient` keep their names and packages.
67+
If your workflow code only touches those plus `WorkflowContext`, it compiles untouched apart from
68+
the imports above.
69+
70+
---
71+
72+
## 3. Renamed types
73+
74+
Seven types were renamed. Each had a near-duplicate twin on the workflows side, and unifying the two
75+
artifacts removed the duplication — that was the point of the merge, and it is not something an
76+
alias can paper over.
77+
78+
| Was | Now | Note |
79+
|---|---|---|
80+
| `io.dapr.durabletask.TaskOrchestrationContext` | `io.dapr.workflows.WorkflowContext` | `callSubOrchestrator` → `callChildWorkflow`; `getIsReplaying` → `isReplaying` |
81+
| `io.dapr.durabletask.TaskOptions` | `io.dapr.workflows.WorkflowTaskOptions` | keeps both the builder and the constructors |
82+
| `io.dapr.durabletask.RetryPolicy` | `io.dapr.workflows.WorkflowTaskRetryPolicy` | see [Behaviour changes](#4-behaviour-changes) |
83+
| `io.dapr.durabletask.RetryHandler` | `io.dapr.workflows.WorkflowTaskRetryHandler` | |
84+
| `io.dapr.durabletask.RetryContext` | `io.dapr.workflows.WorkflowTaskRetryContext` | `getOrchestrationContext()` → `getWorkflowContext()` |
85+
| `io.dapr.durabletask.FailureDetails` | `io.dapr.workflows.task.exception.WorkflowFailureDetails` | was an interface on the workflows side, is now a final class |
86+
| `io.dapr.durabletask.OrchestrationRuntimeStatus` | `io.dapr.workflows.client.WorkflowRuntimeStatus` | gains `STALLED` |
87+
88+
### Removed
89+
90+
| Removed | Use instead |
91+
|---|---|
92+
| `DaprWorkflowClient.getInstanceState(…)` | `getWorkflowState(…)` |
93+
| `DaprWorkflowClient.waitForInstanceStart(…)` | `waitForWorkflowStart(…)` |
94+
| `DaprWorkflowClient.waitForInstanceCompletion(…)` | `waitForWorkflowCompletion(…)` |
95+
| `DaprWorkflowClient.purgeInstance(…)` | `purgeWorkflow(…)` |
96+
| `io.dapr.workflows.client.WorkflowInstanceStatus` | `io.dapr.workflows.client.WorkflowState` |
97+
| `WorkflowRuntimeStatusConverter` | folded into `WorkflowRuntimeStatus` |
98+
| `DefaultWorkflowContext`, `DefaultWorkflowFailureDetails`, `DefaultWorkflowInstanceStatus` | internal adapters, no longer needed |
99+
100+
All four client methods were already `@Deprecated(forRemoval = true)`.
101+
102+
`WorkflowState` is the same shape as `WorkflowInstanceStatus` with one difference: the id accessor
103+
is **`getWorkflowId()`**, not `getInstanceId()`.
104+
105+
### Types that became internal
106+
107+
These were public but are implementation detail. They now live under `io.dapr.workflows.task.internal`
108+
and are not supported API: `Helpers`, `TaskOrchestrationExecutor`, `TaskActivityExecutor`,
109+
`TaskOrchestratorResult`, `UuidGenerator`, and the runners (`DurableRunner`, `ActivityRunner`,
110+
`OrchestratorRunner`, `OrchestrationRunner`). If you depend on any of these, open an issue describing
111+
what you needed them for.
112+
113+
---
114+
115+
## 4. Behaviour changes
116+
117+
Three changes are not visible to the compiler.
118+
119+
**Retry policy defaults are now explicit.** `WorkflowTaskRetryPolicy.getMaxRetryInterval()` and
120+
`getRetryTimeout()` return `Duration.ZERO` when unset, where the workflows-side builder previously
121+
returned `null`. Code doing `if (policy.getMaxRetryInterval() != null)` will now always take the
122+
non-null branch. The value the runtime sees is unchanged — an adapter used to perform this
123+
`null` → `ZERO` conversion, and it now happens in the constructor.
124+
125+
**`WorkflowContext` gained methods.** `getAppId()`, `sendEvent(...)`, `clearCustomStatus()` and two
126+
`createTimer(String, …)` overloads are now on the interface. Calling code is unaffected. **Anything
127+
that *implements* `WorkflowContext` must implement them** — mocks and test doubles included.
128+
129+
**Error type strings changed.** `WorkflowFailureDetails.getErrorType()` returns the exception's fully
130+
qualified name, so the strings moved with the classes. If you compare error types as strings, update
131+
the literals — or better, compare against `SomeException.class.getName()`.
132+
133+
---
134+
135+
## 5. Workflows already running
136+
137+
This is the one that bites silently.
138+
139+
The error type is **persisted into workflow history**. A workflow that started before the upgrade and
140+
resumes afterwards carries `io.dapr.durabletask.TaskFailedException` in its history, while the class
141+
is now `io.dapr.workflows.task.exception.TaskFailedException`.
142+
143+
`WorkflowFailureDetails.isCausedBy(...)` resolves the persisted name reflectively. To keep those
144+
instances working, the SDK maps the exception names that shipped under `io.dapr.durabletask` onto
145+
their current types, so `isCausedBy` answers correctly across the upgrade:
146+
147+
```
148+
TaskFailedException TaskCanceledException
149+
CompositeTaskFailedException NonDeterministicOrchestratorException
150+
PropagatedHistoryException orchestration.exception.VersionNotRegisteredException
151+
interruption.OrchestratorBlockedException
152+
interruption.ContinueAsNewInterruption
153+
DataConverter$DataConverterException
154+
```
155+
156+
**What this covers:** `isCausedBy` on in-flight workflows, including compensation logic that branches
157+
on the failure type. If your workflows only ever see SDK exception types, no action is needed.
158+
159+
Note that an error type the SDK cannot resolve answers `false` to *every* query — including broad
160+
ones like `isCausedBy(RuntimeException.class)` — not just to an exact-type check. If you have
161+
persisted history whose error type is neither an SDK exception nor a class on your own classpath,
162+
expect `false` and a `WARN` line rather than a match.
163+
164+
**What it does not cover:** your own comparisons. If you do
165+
`"io.dapr.durabletask.TaskFailedException".equals(details.getErrorType())`, that is now false for new
166+
failures and true for old ones. Replace such comparisons with `isCausedBy(...)`.
167+
168+
An error type that cannot be resolved at all now logs at `WARN` and returns `false`, rather than
169+
returning `false` silently.
170+
171+
Replay determinism is unaffected: the rethrown exception type is chosen by code, not by the persisted
172+
string, so history written before the upgrade replays normally.
173+
174+
---
175+
176+
## 6. Executor lifecycle
177+
178+
`dapr-sdk-workflows` is still compiled for **Java 17** and runs on Java 17 or later, and the runtime
179+
still defaults to a cached thread pool.
180+
181+
One behaviour changed: an executor you supply with `WorkflowRuntimeBuilder.withExecutorService(...)`
182+
is no longer shut down when the runtime closes. The runtime now shuts down only an executor it
183+
created for itself. If you relied on the runtime to shut down an executor you passed in, shut it
184+
down yourself.
185+
186+
---
187+
188+
## 7. Mechanical rewrite
189+
190+
Most of section 2 can be applied with a script. Review the diff afterwards; this only rewrites
191+
imports and fully qualified references, and it does not handle the renames in section 3.
192+
193+
```bash
194+
#!/usr/bin/env bash
195+
# Rewrites v1 durable task imports to their unified homes.
196+
# Usage: ./rewrite.sh [source-dir] (defaults to src). Works on bash 3.2+.
197+
set -eu
198+
199+
ROOT="${1:-src}"
200+
201+
# "<SimpleName> <new subpackage>", one per line.
202+
MAP='
203+
Task task
204+
TaskActivity task
205+
TaskActivityContext task
206+
TaskActivityFactory task
207+
TaskOrchestration task
208+
OrchestratorFunction task
209+
TaskFailedException task.exception
210+
TaskCanceledException task.exception
211+
CompositeTaskFailedException task.exception
212+
NonDeterministicOrchestratorException task.exception
213+
PropagatedHistory task.history
214+
PropagatedHistoryException task.history
215+
HistoryPropagationScope task.history
216+
WorkflowResult task.history
217+
ActivityResult task.history
218+
ChildWorkflowResult task.history
219+
DurableTaskClient task.client
220+
DurableTaskGrpcClient task.client
221+
DurableTaskGrpcClientBuilder task.client
222+
OrchestrationMetadata task.client
223+
NewOrchestrationInstanceOptions task.client
224+
PurgeInstanceCriteria task.client
225+
PurgeResult task.client
226+
DurableTaskGrpcWorker task.worker
227+
DurableTaskGrpcWorkerBuilder task.worker
228+
DataConverter task.serialization
229+
JacksonDataConverter task.serialization
230+
'
231+
232+
count=0
233+
while IFS= read -r file; do
234+
[ -n "$file" ] || continue
235+
count=$((count + 1))
236+
237+
# Subpackages that keep their leaf name. Do these first: the type loop below
238+
# would otherwise rewrite the leaf and leave a stale parent package behind.
239+
perl -0pi -e '
240+
s/\bio\.dapr\.durabletask\.orchestration\.exception\.VersionNotRegisteredException\b/io.dapr.workflows.task.exception.VersionNotRegisteredException/g;
241+
s/\bio\.dapr\.durabletask\.interruption\./io.dapr.workflows.task.interruption./g;
242+
s/\bio\.dapr\.durabletask\.orchestration\./io.dapr.workflows.task.orchestration./g;
243+
' "$file"
244+
245+
# Longest names first, so PropagatedHistory does not clip PropagatedHistoryException.
246+
echo "$MAP" | grep -v '^$' | awk '{ print length($1), $1, $2 }' | sort -rn |
247+
while read -r _len type pkg; do
248+
perl -0pi -e "s/\\bio\\.dapr\\.durabletask\\.${type}\\b/io.dapr.workflows.${pkg}.${type}/g" "$file"
249+
done
250+
done <<EOF
251+
$(grep -rl 'io\.dapr\.durabletask' --include='*.java' "$ROOT" || true)
252+
EOF
253+
254+
echo "Rewrote $count file(s). Remaining references to review by hand:"
255+
grep -rn 'io\.dapr\.durabletask' --include='*.java' "$ROOT" || echo " none"
256+
```
257+
258+
Anything the script leaves behind is either a renamed type from section 3 or a reference to something
259+
that is now internal.
260+
261+
---
262+
263+
## 8. Checklist
264+
265+
- [ ] Drop `io.dapr:durabletask-client` from every pom and build file
266+
- [ ] Confirm no stale `durabletask-client` jar remains on the classpath (`mvn dependency:tree`)
267+
- [ ] Rewrite `io.dapr.durabletask.*` imports (section 2 / section 7)
268+
- [ ] Apply the renames in section 3
269+
- [ ] Replace the four removed `DaprWorkflowClient` methods
270+
- [ ] Swap `WorkflowInstanceStatus` for `WorkflowState`, and `getInstanceId()` for `getWorkflowId()`
271+
- [ ] Implement the new `WorkflowContext` methods in any hand-written implementation or mock
272+
- [ ] Replace string comparisons on `getErrorType()` with `isCausedBy(...)`
273+
- [ ] Review `null` checks on `getMaxRetryInterval()` / `getRetryTimeout()`
274+
- [ ] Shut down any executor you pass to `withExecutorService(...)` yourself

‎README.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ IDE setup and the tools needed to work on the SDK itself are under [Development]
5252

5353
Two BOMs are published:
5454

55-
- **`io.dapr:dapr-sdk-bom`** — core SDK modules (`dapr-sdk`, `dapr-sdk-actors`, `dapr-sdk-workflows`, `dapr-sdk-autogen`, `durabletask-client`, `testcontainers-dapr`) plus security-patched transitive dependencies (Netty, Jackson, commons-compress, commons-codec).
55+
> Upgrading workflow code from a release that still had `durabletask-client`? See
56+
> [MIGRATION.md](MIGRATION.md).
57+
58+
- **`io.dapr:dapr-sdk-bom`** — core SDK modules (`dapr-sdk`, `dapr-sdk-actors`, `dapr-sdk-workflows`, `dapr-sdk-autogen`, `testcontainers-dapr`) plus security-patched transitive dependencies (Netty, Jackson, commons-compress, commons-codec).
5659
- **`io.dapr.spring:dapr-spring-bom`** — Spring-specific modules (`dapr-sdk-springboot`, `dapr-spring-*`). Imports `dapr-sdk-bom` transitively, so Spring users only need this single BOM.
5760

5861
`durabletask-client` is the gRPC client and worker for the Durable Task engine that runs Dapr workflows; `dapr-sdk-workflows` pulls it in, so you do not add it yourself.

‎SUPPORT.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ at a given version pins the whole stack, core and Spring, to that single version
1212
| **1.19.x+** | v1.18 | 4.0.x | 17+ | Active — new features and fixes |
1313
| **1.18.x** | v1.18 | 3.5.x | 17+ | Maintenance — best-effort security/critical fixes |
1414

15-
The **core** SDK modules (`dapr-sdk`, `dapr-sdk-actors`, `dapr-sdk-workflows`, `durabletask-client`)
15+
### Migrating to the unified workflows module
16+
17+
In **1.20.x**, `durabletask-client` has been folded into `dapr-sdk-workflows`, which is a breaking
18+
change for workflow code — so upgrading from 1.19.x or earlier requires source changes. See
19+
[MIGRATION.md](MIGRATION.md) for the type mapping, the removed API, and what it means for workflows
20+
that are already running when you upgrade.
21+
22+
The **core** SDK modules (`dapr-sdk`, `dapr-sdk-actors`, `dapr-sdk-workflows`)
1623
are framework-agnostic and do not depend on Spring Boot — the Spring Boot column applies only to the
1724
Spring integration modules (`dapr-sdk-springboot`, `dapr-spring-*`). Core and Spring modules always
1825
share the same SDK version (the Spring BOM imports `dapr-sdk-bom` at its own version), so they never

‎dapr-spring/dapr-spring-boot-observation/src/main/java/io/dapr/spring/observation/client/ObservationDaprWorkflowClient.java‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,10 @@
3939

4040
/**
4141
* A {@link DaprWorkflowClient} subclass that creates Micrometer Observation spans (bridged to
42-
* OpenTelemetry) for each non-deprecated method call.
42+
* OpenTelemetry) for each method call.
4343
*
4444
* <p>Because this class extends {@link DaprWorkflowClient}, consumers can keep injecting
45-
* {@code DaprWorkflowClient} without any code changes. Deprecated methods fall through to the
46-
* parent implementation without any observation.
45+
* {@code DaprWorkflowClient} without any code changes.
4746
*
4847
* <p><b>Trace propagation:</b> an {@link OtelTracingClientInterceptor} is registered on the gRPC
4948
* channel. For each synchronous workflow RPC, the observation opens an OTel scope (via
@@ -334,10 +333,6 @@ public boolean purgeWorkflow(String workflowInstanceId) {
334333
}
335334
}
336335

337-
// Deprecated methods (getInstanceState, waitForInstanceStart, waitForInstanceCompletion,
338-
// purgeInstance) are intentionally not overridden — they fall through to the parent
339-
// implementation without any observation.
340-
341336
// -------------------------------------------------------------------------
342337
// gRPC interceptor: injects the current OTel span's traceparent into headers
343338
// -------------------------------------------------------------------------

0 commit comments

Comments
 (0)