Skip to content

Commit b4b5461

Browse files
authored
fix: consolidate milestone badge publishing into Pages build (#483)
1 parent b0d0fd7 commit b4b5461

4 files changed

Lines changed: 264 additions & 56 deletions

File tree

.github/workflows/build.yml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# Triggers:
77
# - pull_request: when a PR targets main
88
# - push: when code is pushed to main
9+
# - milestone: when milestone metadata changes
910
#
1011
# Notes:
1112
# Builds against Java 17, 21, and 25.
@@ -15,6 +16,8 @@ run-name: Build - ${{ github.event_name }}
1516

1617
on:
1718
workflow_dispatch:
19+
milestone:
20+
types: [created, edited, closed, deleted]
1821
pull_request:
1922
branches:
2023
- main
@@ -38,6 +41,7 @@ on:
3841

3942
permissions:
4043
contents: read
44+
issues: read
4145
pages: write
4246
id-token: write
4347

@@ -54,6 +58,8 @@ jobs:
5458
steps:
5559
- name: Checkout repository
5660
uses: actions/checkout@v7
61+
with:
62+
ref: ${{ github.event_name == 'milestone' && github.event.repository.default_branch || github.ref }}
5763

5864
- name: Setup Java ${{ matrix.java }}
5965
uses: actions/setup-java@v5
@@ -76,16 +82,38 @@ jobs:
7682
if: ${{ matrix.java == 17 }}
7783
run: mvn -B -pl sdk -am javadoc:javadoc
7884

85+
- name: Generate milestone badge
86+
if: ${{ matrix.java == 17 }}
87+
env:
88+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89+
run: |
90+
set -euo pipefail
91+
92+
TITLE=$(gh api repos/${{ github.repository }}/milestones \
93+
--jq '[.[] | select(.state == "open" and .due_on != null)] | sort_by(.due_on) | .[0].title // empty')
94+
95+
if [ -z "$TITLE" ]; then
96+
URL="https://img.shields.io/badge/Next%20Milestone-No%20milestone-lightgrey"
97+
else
98+
ENCODED=$(echo -n "$TITLE" | jq -sRr @uri | sed 's/-/--/g')
99+
URL="https://img.shields.io/badge/Next%20Milestone-${ENCODED}-blue"
100+
fi
101+
102+
mkdir -p milestone
103+
curl -sfL "$URL" -o milestone/badge.svg
104+
echo "Badge generated for: ${TITLE:-No milestone}"
105+
79106
- name: Configure GitHub Pages
80107
if: ${{ matrix.java == 17 }}
81108
uses: actions/configure-pages@v6
82109

83110
- name: Prepare GitHub Pages artifact
84111
if: ${{ matrix.java == 17 }}
85112
run: |
86-
mkdir -p github-pages/coverage github-pages/javadoc
113+
mkdir -p github-pages/coverage github-pages/javadoc github-pages/milestone
87114
cp -R coverage-report/target/site/jacoco-aggregate/. github-pages/coverage
88115
cp -R sdk/target/reports/apidocs/. github-pages/javadoc
116+
cp -R milestone/. github-pages/milestone
89117
touch github-pages/.nojekyll
90118
91119
- name: Upload GitHub Pages artifact
@@ -95,7 +123,7 @@ jobs:
95123
path: github-pages
96124

97125
deploy-pages:
98-
if: ${{ github.ref == 'refs/heads/main' }}
126+
if: ${{ github.event_name == 'milestone' || github.ref == 'refs/heads/main' }}
99127
needs: build
100128
runs-on: ubuntu-latest
101129
environment:

.github/workflows/update-milestone-badge.yml

Lines changed: 0 additions & 52 deletions
This file was deleted.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
[![Build](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/build.yml/badge.svg)](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/build.yml)
66
[![Javadoc](https://img.shields.io/badge/JavaDoc-Online-green)](https://aws.github.io/aws-durable-execution-sdk-java/javadoc/)
77
[![Maven](https://badges.mvnrepository.com/badge/software.amazon.lambda.durable/aws-durable-execution-sdk-java/badge.svg?label=Maven)](https://mvnrepository.com/artifact/software.amazon.lambda.durable/aws-durable-execution-sdk-java)
8-
[![Coverage](https://raw.githubusercontent.com/aws/aws-durable-execution-sdk-java/refs/heads/docs/coverage/jacoco.svg)](https://aws.github.io/aws-durable-execution-sdk-java/coverage/)
8+
[![Coverage](https://aws.github.io/aws-durable-execution-sdk-java/coverage/jacoco.svg)](https://aws.github.io/aws-durable-execution-sdk-java/coverage/)
99
[![E2E Tests](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/e2e-tests.yml/badge.svg)](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/e2e-tests.yml)
1010
[![CodeQL](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/github-code-scanning/codeql)
1111
[![Spotless](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/check-spotless.yml/badge.svg)](https://github.com/aws/aws-durable-execution-sdk-java/actions/workflows/check-spotless.yml)
12-
[![Roadmap](https://raw.githubusercontent.com/aws/aws-durable-execution-sdk-java/refs/heads/docs/milestone/badge.svg)](https://github.com/orgs/aws/projects/346/views/6)
12+
[![Roadmap](https://aws.github.io/aws-durable-execution-sdk-java/milestone/badge.svg)](https://github.com/orgs/aws/projects/346/views/6)
1313

1414
Build resilient, long-running AWS Lambda functions that automatically checkpoint progress and resume after failures. Durable functions can run for up to one year while you pay only for active compute time.
1515

@@ -110,6 +110,7 @@ See [Deploy Lambda durable functions with Infrastructure as Code](https://docs.a
110110
- [<u>Configuration</u>](docs/advanced/configuration.md) - Customize SDK behaviour
111111
- [<u>Error Handling</u>](docs/advanced/error-handling.md) - SDK exceptions for handling failures
112112
- [<u>Logging</u>](docs/advanced/logging.md) - How to use DurableLogger
113+
- [<u>Migrating from 1.x to 2.x</u>](docs/migration-1.x-to-2.x.md) - Upgrade guide for breaking changes since `v1.2.1`
113114
- [<u>Testing</u>](docs/advanced/testing.md) - Utilities for local development and cloud-based integration testing
114115

115116
## Related SDKs

docs/migration-1.x-to-2.x.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# Migrating from 1.x to 2.x
2+
3+
This guide helps teams upgrade from the `1.x` line to `2.x`.
4+
5+
It focuses on the breaking changes introduced since `v1.2.1`, the most recent `1.x` release at the time of writing. If you are already on a newer `1.x` patch, the same migration steps still apply.
6+
7+
## Upgrade Checklist
8+
9+
- Replace `StepConfig.builder().semantics(...)` with the correct `2.x` equivalent for your intended behavior.
10+
- Update log queries, parsers, and dashboards to use `executionArn`, `operationId`, and `operationName`.
11+
- Rebaseline replay-sensitive logging and plugin behavior for child contexts, especially in `parallel()`, `map()`, and nested `runInChildContext(...)` workflows.
12+
- Update any code that expected validation failures to throw `IllegalDurableOperationException`.
13+
- Verify that custom `SerDes` implementations can deserialize SDK-managed values immediately after serialization, or explicitly opt out of the extra validation pass.
14+
15+
Useful searches before upgrading:
16+
17+
```bash
18+
rg -n "\.semantics\(" .
19+
rg -n "durableExecutionArn|contextId|contextName" .
20+
rg -n "replay|isReplayingChildren|onOperationStart|onOperationEnd" sdk examples
21+
```
22+
23+
## 1. Rename `StepConfig.semantics(...)` to `semanticsPerRetry(...)`
24+
25+
The deprecated `semantics(...)` builder method is removed in `2.x`.
26+
27+
This is not always a one-line rename. In `1.x`, `semantics(StepSemantics.AT_MOST_ONCE_PER_RETRY)` behaved like `2.x` `semanticsPerRetry(StepSemantics.AT_MOST_ONCE_PER_RETRY)` plus a `NO_RETRY` policy.
28+
29+
Before:
30+
31+
```java
32+
var config = StepConfig.builder()
33+
.semantics(StepSemantics.AT_MOST_ONCE_PER_RETRY)
34+
.build();
35+
```
36+
37+
Naive rename:
38+
39+
```java
40+
var config = StepConfig.builder()
41+
.semanticsPerRetry(StepSemantics.AT_MOST_ONCE_PER_RETRY)
42+
.build();
43+
```
44+
45+
Behavior-preserving migration for old `1.x` `AT_MOST_ONCE_PER_RETRY` usage:
46+
47+
```java
48+
var config = StepConfig.builder()
49+
.semanticsPerRetry(StepSemantics.AT_MOST_ONCE_PER_RETRY)
50+
.retryStrategy(RetryStrategies.Presets.NO_RETRY)
51+
.build();
52+
```
53+
54+
Migration rules:
55+
56+
- Old `semantics(AT_LEAST_ONCE_PER_RETRY)` maps directly to `semanticsPerRetry(AT_LEAST_ONCE_PER_RETRY)`.
57+
- Old `semantics(AT_MOST_ONCE_PER_RETRY)` should usually become `semanticsPerRetry(AT_MOST_ONCE_PER_RETRY)` plus `retryStrategy(RetryStrategies.Presets.NO_RETRY)` if you want to preserve the old `1.x` behavior.
58+
- If you intentionally want the corrected `2.x` per-retry semantics, use `semanticsPerRetry(AT_MOST_ONCE_PER_RETRY)` without forcing `NO_RETRY`.
59+
60+
What to update:
61+
62+
- Step configuration builders
63+
- Shared helper methods and wrapper APIs
64+
- Tests that asserted on `config.semantics()`
65+
66+
If you expose your own configuration layer on top of the SDK, rename it now so downstream users do not inherit the removed `semantics` name.
67+
68+
## 2. Update logger MDC field names
69+
70+
The main user-visible breaking change in `2.x` is the logger metadata rename so Java matches the other durable execution SDKs.
71+
72+
Before:
73+
74+
```json
75+
{
76+
"durableExecutionArn": "arn:aws:lambda:...",
77+
"contextId": "child-context-id",
78+
"contextName": "inventory-check"
79+
}
80+
```
81+
82+
After:
83+
84+
```json
85+
{
86+
"executionArn": "arn:aws:lambda:...",
87+
"operationId": "child-context-id",
88+
"operationName": "inventory-check"
89+
}
90+
```
91+
92+
What to update:
93+
94+
- CloudWatch Logs Insights queries
95+
- Metric filters and alarms
96+
- Log processors and index mappings
97+
- Dashboards and saved searches
98+
- Any custom JSON or MDC parsing
99+
100+
Important: this rename only applies to logger MDC fields. The SDK API still uses `durableExecutionArn` in places such as `DurableExecutionInput` and plugin invocation records. Do not mechanically rename every `durableExecutionArn` identifier in your codebase.
101+
102+
### Mixed-version rollout query
103+
104+
If you need one query that works during a rolling upgrade, use `coalesce(...)`:
105+
106+
```sql
107+
fields coalesce(executionArn, durableExecutionArn) as executionArn,
108+
coalesce(operationId, contextId) as operationId,
109+
coalesce(operationName, contextName) as operationName
110+
| filter executionArn = "arn:aws:lambda:..."
111+
```
112+
113+
### Temporary compatibility option
114+
115+
If you need to preserve the old MDC keys for a short rollout window, configure `LoggerConfig` with `oldKeyNames=true`:
116+
117+
```java
118+
@Override
119+
protected DurableConfig createConfiguration() {
120+
return DurableConfig.builder()
121+
.withLoggerConfig(new LoggerConfig(true, true))
122+
.build();
123+
}
124+
```
125+
126+
That can reduce migration risk while dashboards and parsers are being updated, but the recommended end state for `2.x` is the new key set.
127+
128+
## 3. Rebaseline replay-sensitive logging and replay APIs
129+
130+
`2.x` uses per-context replay state for logging and plugin callbacks instead of relying on a single global replay view.
131+
132+
What changes in practice:
133+
134+
- Replay suppression is more accurate for child contexts.
135+
- Concurrent child contexts no longer look like fresh execution when that child is still replaying.
136+
- Custom plugins see replay metadata that better reflects the current child context.
137+
- `StepContext` does not expose replay state anymore.
138+
- Step logs are attempt-based and are never replay-suppressed.
139+
140+
API impact:
141+
142+
- `isReplaying()` now belongs on `DurableContext`, not `BaseContext`.
143+
- Code that assumed every context type had `isReplaying()` needs to be updated.
144+
- If you were checking replay state inside step lambdas, move that logic to the surrounding `DurableContext` or redesign it around attempt-based step behavior.
145+
146+
What to review:
147+
148+
- Tests that count log lines across replays
149+
- Dashboards that alert on replay log volume
150+
- Custom plugins using replay-sensitive hooks or `isReplayingChildren`
151+
- Nested workflows that use `parallel()`, `map()`, or `runInChildContext(...)`
152+
- Any code that called `isReplaying()` on `BaseContext` or `StepContext`
153+
154+
The most common upgrade symptom here is not a compile error. It is changed log volume or changed replay-related assertions in tests.
155+
156+
## 4. Update exception handling for context validation failures
157+
158+
In `2.x`, invalid context usage now throws `IllegalStateException` instead of `IllegalDurableOperationException`.
159+
160+
This affects validation failures such as nested durable operations from unsupported thread types, for example calling a blocking durable operation from within a step execution.
161+
162+
What to update:
163+
164+
- Unit and integration tests that assert exception types
165+
- Error classification logic
166+
- Alerting or telemetry that treated `IllegalDurableOperationException` as an SDK defect signal
167+
- Runbooks that distinguished user misuse from SDK or platform failures
168+
169+
Before:
170+
171+
```java
172+
assertThrows(IllegalDurableOperationException.class, future::get);
173+
```
174+
175+
After:
176+
177+
```java
178+
assertThrows(IllegalStateException.class, future::get);
179+
```
180+
181+
## 5. Validate serialization round trips earlier
182+
183+
`2.x` validates serialized results and exceptions with an immediate deserialize pass before checkpointing by default.
184+
185+
What changes in practice:
186+
187+
- Serialization problems now fail on first execution instead of surfacing later on replay.
188+
- Custom `SerDes` implementations must be able to deserialize SDK-managed values they serialize.
189+
- Child-context results are validated consistently, including virtual child-context paths.
190+
191+
This is usually a correctness improvement, but it can surface previously hidden `SerDes` bugs during upgrade.
192+
193+
### New opt-out configuration
194+
195+
If your workload is very performance-sensitive and you need to skip the extra validation deserialize pass, you can opt out:
196+
197+
```java
198+
@Override
199+
protected DurableConfig createConfiguration() {
200+
return DurableConfig.builder()
201+
.withSerializationRoundTripValidation(false)
202+
.build();
203+
}
204+
```
205+
206+
Use that carefully:
207+
208+
- Disabling validation can hide serialization bugs until replay.
209+
- Custom `SerDes` implementations are still expected to be round-trip safe.
210+
211+
## Recommended Validation After Upgrading
212+
213+
1. Build and run your test suite with the `2.x` dependency.
214+
2. Exercise one workflow that replays after `wait()`, `waitForCondition()`, or callback resume.
215+
3. Exercise one workflow with child contexts or concurrency.
216+
4. Verify that your log queries and dashboards still resolve the correct execution and operation identifiers.
217+
5. Verify any code that relied on `BaseContext.isReplaying()` or replay suppression inside step lambdas.
218+
6. If you use custom `SerDes`, run one workflow that checkpoints both a successful result and an exception payload.
219+
7. If you use plugins, verify replay-sensitive metadata in at least one replayed child-context scenario.
220+
221+
## Summary
222+
223+
Most upgrades are straightforward:
224+
225+
- `semantics(...)` becomes `semanticsPerRetry(...)`, and old `AT_MOST_ONCE_PER_RETRY` users may also need `RetryStrategies.Presets.NO_RETRY` to preserve `1.x` behavior
226+
- Logger metadata moves to `executionArn`, `operationId`, and `operationName`
227+
- Replay-sensitive logging becomes per-context, `isReplaying()` moves to `DurableContext`, and step logs are no longer replay-suppressed
228+
- Validation failures now throw `IllegalStateException`
229+
- Serialization round-trip problems surface earlier by default, with an opt-out via `withSerializationRoundTripValidation(false)`
230+
231+
If you update those areas first, the `1.x` to `2.x` migration should be low risk.

0 commit comments

Comments
 (0)