You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(workflow,grpc,webapi): Record auto-upgrade outcome in history
Replace the success-only `ComponentUpgraded` event with
`ComponentUpgradeFinished` so both successful and failed auto-upgrades are
recorded in the execution log. Failed upgrades mark the new digest as
incompatible through the log instead of updating t_state directly.
Tighten `Unlocked` so it only releases a locked execution back to `PendingAt`,
while keeping the previous `backoff_expires_at` wire shape for JSON/proto
compatibility. Auto-upgrade appends `Unlocked` only when replay stops during
a stub-response flush and would otherwise leave the execution locked, leading
to a timeout.
This fixes the case where auto-upgrade unconditionally moved executions to
`PendingAt` (via `ComponentUpgraded`, allowing a blocked workflow to be
picked up immediately and panic on the next execution run if the response
had not arrived yet.
Add tests for blocked upgrades, failed upgrades, and the stub-write path
that still needs Unlocked.
Copy file name to clipboardExpand all lines: assets/schemas/db.json
+30-28Lines changed: 30 additions & 28 deletions
Original file line number
Diff line number
Diff line change
@@ -147,24 +147,11 @@
147
147
"additionalProperties": false
148
148
},
149
149
{
150
-
"description": "Returns execution to [`PendingState::PendingAt`] state at the specified time.\nThis can happen when:\n- executor is running out of resources like [`WorkerError::LimitReached`]\n- executor is being closed (shutdown or hot redeploy requested)\n- activity is paused\n- workflow made progress but then its lock expired\n- workflow attempted to auto-upgrade an execution and failed, recording its digest in `incompatible_digest`",
150
+
"description": "Releases a lock.\n\nState transition semantics:\n- [`PendingState::Locked`] becomes [`PendingState::PendingAt`] at\n [`Unlocked::backoff_expires_at`]. The field name is kept for persisted JSON and gRPC\n compatibility, but it is the next pending instant for every unlock reason.\n- [`PendingState::PendingAt`], [`PendingState::BlockedByJoinSet`],\n [`PendingState::Paused`], and [`PendingState::Finished`] reject this event.",
151
151
"type": "object",
152
152
"properties": {
153
153
"unlocked": {
154
-
"type": "object",
155
-
"properties": {
156
-
"backoff_expires_at": {
157
-
"type": "string",
158
-
"format": "date-time"
159
-
},
160
-
"reason": {
161
-
"$ref": "#/$defs/UnlockedReason"
162
-
}
163
-
},
164
-
"required": [
165
-
"backoff_expires_at",
166
-
"reason"
167
-
]
154
+
"$ref": "#/$defs/Unlocked"
168
155
}
169
156
},
170
157
"required": [
@@ -173,9 +160,10 @@
173
160
"additionalProperties": false
174
161
},
175
162
{
163
+
"description": "Does not change `PendingState`.",
176
164
"type": "object",
177
165
"properties": {
178
-
"component_upgraded": {
166
+
"component_upgrade_finished": {
179
167
"type": "object",
180
168
"properties": {
181
169
"component_digest": {
@@ -184,19 +172,19 @@
184
172
"deployment_id": {
185
173
"type": "string"
186
174
},
187
-
"reason": {
188
-
"$ref": "#/$defs/ComponentUpgradeReason"
175
+
"outcome": {
176
+
"$ref": "#/$defs/ComponentUpgradeOutcome"
189
177
}
190
178
},
191
179
"required": [
192
180
"component_digest",
193
181
"deployment_id",
194
-
"reason"
182
+
"outcome"
195
183
]
196
184
}
197
185
},
198
186
"required": [
199
-
"component_upgraded"
187
+
"component_upgrade_finished"
200
188
],
201
189
"additionalProperties": false
202
190
},
@@ -410,17 +398,34 @@
410
398
"nanos"
411
399
]
412
400
},
413
-
"UnlockedReason": {
401
+
"Unlocked": {
402
+
"type": "object",
403
+
"properties": {
404
+
"backoff_expires_at": {
405
+
"description": "Instant used when releasing a currently locked execution back to\n[`PendingState::PendingAt`]. This field keeps the released JSON and gRPC name.",
0 commit comments