Skip to content

Commit 697d037

Browse files
Add commandIndex to mismatch exceptions (#518)
1 parent 4b97c9b commit 697d037

File tree

3 files changed

+92
-49
lines changed

3 files changed

+92
-49
lines changed

sdk-core/src/main/java/dev/restate/sdk/core/statemachine/CommandAccessor.java

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ interface CommandAccessor<E extends MessageLite> {
1616

1717
String getName(E expected);
1818

19-
void checkEntryHeader(E expected, MessageLite actual) throws ProtocolException;
19+
void checkEntryHeader(int commandIndex, E expected, MessageLite actual) throws ProtocolException;
2020

2121
CommandAccessor<Protocol.InputCommandMessage> INPUT =
2222
new CommandAccessor<>() {
@@ -26,7 +26,8 @@ public String getName(Protocol.InputCommandMessage expected) {
2626
}
2727

2828
@Override
29-
public void checkEntryHeader(Protocol.InputCommandMessage expected, MessageLite actual)
29+
public void checkEntryHeader(
30+
int commandIndex, Protocol.InputCommandMessage expected, MessageLite actual)
3031
throws ProtocolException {
3132
// Nothing to check
3233
}
@@ -39,9 +40,11 @@ public String getName(Protocol.OutputCommandMessage expected) {
3940
}
4041

4142
@Override
42-
public void checkEntryHeader(Protocol.OutputCommandMessage expected, MessageLite actual)
43+
public void checkEntryHeader(
44+
int commandIndex, Protocol.OutputCommandMessage expected, MessageLite actual)
4345
throws ProtocolException {
44-
EntryHeaderChecker.check(Protocol.OutputCommandMessage.class, expected, actual)
46+
EntryHeaderChecker.check(
47+
commandIndex, Protocol.OutputCommandMessage.class, expected, actual)
4548
.checkField("name", Protocol.OutputCommandMessage::getName)
4649
.checkField("result", Protocol.OutputCommandMessage::getResultCase)
4750
.checkField("value", Protocol.OutputCommandMessage::getValue)
@@ -53,9 +56,10 @@ public void checkEntryHeader(Protocol.OutputCommandMessage expected, MessageLite
5356
new CommandAccessor<>() {
5457
@Override
5558
public void checkEntryHeader(
56-
Protocol.GetEagerStateCommandMessage expected, MessageLite actual)
59+
int commandIndex, Protocol.GetEagerStateCommandMessage expected, MessageLite actual)
5760
throws ProtocolException {
58-
EntryHeaderChecker.check(Protocol.GetEagerStateCommandMessage.class, expected, actual)
61+
EntryHeaderChecker.check(
62+
commandIndex, Protocol.GetEagerStateCommandMessage.class, expected, actual)
5963
.checkField("name", Protocol.GetEagerStateCommandMessage::getName)
6064
.checkField("key", Protocol.GetEagerStateCommandMessage::getKey)
6165
.verify();
@@ -75,9 +79,10 @@ public String getName(Protocol.GetLazyStateCommandMessage expected) {
7579

7680
@Override
7781
public void checkEntryHeader(
78-
Protocol.GetLazyStateCommandMessage expected, MessageLite actual)
82+
int commandIndex, Protocol.GetLazyStateCommandMessage expected, MessageLite actual)
7983
throws ProtocolException {
80-
EntryHeaderChecker.check(Protocol.GetLazyStateCommandMessage.class, expected, actual)
84+
EntryHeaderChecker.check(
85+
commandIndex, Protocol.GetLazyStateCommandMessage.class, expected, actual)
8186
.checkField("name", Protocol.GetLazyStateCommandMessage::getName)
8287
.checkField("key", Protocol.GetLazyStateCommandMessage::getKey)
8388
.checkField(
@@ -95,9 +100,10 @@ public String getName(Protocol.GetEagerStateKeysCommandMessage expected) {
95100

96101
@Override
97102
public void checkEntryHeader(
98-
Protocol.GetEagerStateKeysCommandMessage expected, MessageLite actual)
103+
int commandIndex, Protocol.GetEagerStateKeysCommandMessage expected, MessageLite actual)
99104
throws ProtocolException {
100-
EntryHeaderChecker.check(Protocol.GetEagerStateKeysCommandMessage.class, expected, actual)
105+
EntryHeaderChecker.check(
106+
commandIndex, Protocol.GetEagerStateKeysCommandMessage.class, expected, actual)
101107
.checkField("name", Protocol.GetEagerStateKeysCommandMessage::getName)
102108
.verify();
103109
}
@@ -111,9 +117,10 @@ public String getName(Protocol.GetLazyStateKeysCommandMessage expected) {
111117

112118
@Override
113119
public void checkEntryHeader(
114-
Protocol.GetLazyStateKeysCommandMessage expected, MessageLite actual)
120+
int commandIndex, Protocol.GetLazyStateKeysCommandMessage expected, MessageLite actual)
115121
throws ProtocolException {
116-
EntryHeaderChecker.check(Protocol.GetLazyStateKeysCommandMessage.class, expected, actual)
122+
EntryHeaderChecker.check(
123+
commandIndex, Protocol.GetLazyStateKeysCommandMessage.class, expected, actual)
117124
.checkField("name", Protocol.GetLazyStateKeysCommandMessage::getName)
118125
.verify();
119126
}
@@ -126,9 +133,11 @@ public String getName(Protocol.ClearStateCommandMessage expected) {
126133
}
127134

128135
@Override
129-
public void checkEntryHeader(Protocol.ClearStateCommandMessage expected, MessageLite actual)
136+
public void checkEntryHeader(
137+
int commandIndex, Protocol.ClearStateCommandMessage expected, MessageLite actual)
130138
throws ProtocolException {
131-
EntryHeaderChecker.check(Protocol.ClearStateCommandMessage.class, expected, actual)
139+
EntryHeaderChecker.check(
140+
commandIndex, Protocol.ClearStateCommandMessage.class, expected, actual)
132141
.checkField("name", Protocol.ClearStateCommandMessage::getName)
133142
.checkField("key", Protocol.ClearStateCommandMessage::getKey)
134143
.verify();
@@ -143,9 +152,10 @@ public String getName(Protocol.ClearAllStateCommandMessage expected) {
143152

144153
@Override
145154
public void checkEntryHeader(
146-
Protocol.ClearAllStateCommandMessage expected, MessageLite actual)
155+
int commandIndex, Protocol.ClearAllStateCommandMessage expected, MessageLite actual)
147156
throws ProtocolException {
148-
EntryHeaderChecker.check(Protocol.ClearAllStateCommandMessage.class, expected, actual)
157+
EntryHeaderChecker.check(
158+
commandIndex, Protocol.ClearAllStateCommandMessage.class, expected, actual)
149159
.checkField("name", Protocol.ClearAllStateCommandMessage::getName)
150160
.verify();
151161
}
@@ -158,9 +168,11 @@ public String getName(Protocol.SetStateCommandMessage expected) {
158168
}
159169

160170
@Override
161-
public void checkEntryHeader(Protocol.SetStateCommandMessage expected, MessageLite actual)
171+
public void checkEntryHeader(
172+
int commandIndex, Protocol.SetStateCommandMessage expected, MessageLite actual)
162173
throws ProtocolException {
163-
EntryHeaderChecker.check(Protocol.SetStateCommandMessage.class, expected, actual)
174+
EntryHeaderChecker.check(
175+
commandIndex, Protocol.SetStateCommandMessage.class, expected, actual)
164176
.checkField("name", Protocol.SetStateCommandMessage::getName)
165177
.checkField("key", Protocol.SetStateCommandMessage::getKey)
166178
.checkField("value", Protocol.SetStateCommandMessage::getValue)
@@ -176,9 +188,11 @@ public String getName(Protocol.SleepCommandMessage expected) {
176188
}
177189

178190
@Override
179-
public void checkEntryHeader(Protocol.SleepCommandMessage expected, MessageLite actual)
191+
public void checkEntryHeader(
192+
int commandIndex, Protocol.SleepCommandMessage expected, MessageLite actual)
180193
throws ProtocolException {
181-
EntryHeaderChecker.check(Protocol.SleepCommandMessage.class, expected, actual)
194+
EntryHeaderChecker.check(
195+
commandIndex, Protocol.SleepCommandMessage.class, expected, actual)
182196
.checkField("name", Protocol.SleepCommandMessage::getName)
183197
.checkField(
184198
"result_completion_id", Protocol.SleepCommandMessage::getResultCompletionId)
@@ -194,9 +208,11 @@ public String getName(Protocol.CallCommandMessage expected) {
194208
}
195209

196210
@Override
197-
public void checkEntryHeader(Protocol.CallCommandMessage expected, MessageLite actual)
211+
public void checkEntryHeader(
212+
int commandIndex, Protocol.CallCommandMessage expected, MessageLite actual)
198213
throws ProtocolException {
199-
EntryHeaderChecker.check(Protocol.CallCommandMessage.class, expected, actual)
214+
EntryHeaderChecker.check(
215+
commandIndex, Protocol.CallCommandMessage.class, expected, actual)
200216
.checkField("name", Protocol.CallCommandMessage::getName)
201217
.checkField("service_name", Protocol.CallCommandMessage::getServiceName)
202218
.checkField("handler_name", Protocol.CallCommandMessage::getHandlerName)
@@ -220,9 +236,11 @@ public String getName(Protocol.OneWayCallCommandMessage expected) {
220236
}
221237

222238
@Override
223-
public void checkEntryHeader(Protocol.OneWayCallCommandMessage expected, MessageLite actual)
239+
public void checkEntryHeader(
240+
int commandIndex, Protocol.OneWayCallCommandMessage expected, MessageLite actual)
224241
throws ProtocolException {
225-
EntryHeaderChecker.check(Protocol.OneWayCallCommandMessage.class, expected, actual)
242+
EntryHeaderChecker.check(
243+
commandIndex, Protocol.OneWayCallCommandMessage.class, expected, actual)
226244
.checkField("name", Protocol.OneWayCallCommandMessage::getName)
227245
.checkField("service_name", Protocol.OneWayCallCommandMessage::getServiceName)
228246
.checkField("handler_name", Protocol.OneWayCallCommandMessage::getHandlerName)
@@ -246,9 +264,10 @@ public String getName(Protocol.CompleteAwakeableCommandMessage expected) {
246264

247265
@Override
248266
public void checkEntryHeader(
249-
Protocol.CompleteAwakeableCommandMessage expected, MessageLite actual)
267+
int commandIndex, Protocol.CompleteAwakeableCommandMessage expected, MessageLite actual)
250268
throws ProtocolException {
251-
EntryHeaderChecker.check(Protocol.CompleteAwakeableCommandMessage.class, expected, actual)
269+
EntryHeaderChecker.check(
270+
commandIndex, Protocol.CompleteAwakeableCommandMessage.class, expected, actual)
252271
.checkField("name", Protocol.CompleteAwakeableCommandMessage::getName)
253272
.checkField("awakeable_id", Protocol.CompleteAwakeableCommandMessage::getAwakeableId)
254273
.checkField("result", Protocol.CompleteAwakeableCommandMessage::getResultCase)
@@ -265,9 +284,10 @@ public String getName(Protocol.RunCommandMessage expected) {
265284
}
266285

267286
@Override
268-
public void checkEntryHeader(Protocol.RunCommandMessage expected, MessageLite actual)
287+
public void checkEntryHeader(
288+
int commandIndex, Protocol.RunCommandMessage expected, MessageLite actual)
269289
throws ProtocolException {
270-
EntryHeaderChecker.check(Protocol.RunCommandMessage.class, expected, actual)
290+
EntryHeaderChecker.check(commandIndex, Protocol.RunCommandMessage.class, expected, actual)
271291
.checkField("name", Protocol.RunCommandMessage::getName)
272292
.verify();
273293
}
@@ -281,9 +301,11 @@ public String getName(Protocol.GetPromiseCommandMessage expected) {
281301
}
282302

283303
@Override
284-
public void checkEntryHeader(Protocol.GetPromiseCommandMessage expected, MessageLite actual)
304+
public void checkEntryHeader(
305+
int commandIndex, Protocol.GetPromiseCommandMessage expected, MessageLite actual)
285306
throws ProtocolException {
286-
EntryHeaderChecker.check(Protocol.GetPromiseCommandMessage.class, expected, actual)
307+
EntryHeaderChecker.check(
308+
commandIndex, Protocol.GetPromiseCommandMessage.class, expected, actual)
287309
.checkField("name", Protocol.GetPromiseCommandMessage::getName)
288310
.checkField("key", Protocol.GetPromiseCommandMessage::getKey)
289311
.checkField(
@@ -300,9 +322,10 @@ public String getName(Protocol.PeekPromiseCommandMessage expected) {
300322

301323
@Override
302324
public void checkEntryHeader(
303-
Protocol.PeekPromiseCommandMessage expected, MessageLite actual)
325+
int commandIndex, Protocol.PeekPromiseCommandMessage expected, MessageLite actual)
304326
throws ProtocolException {
305-
EntryHeaderChecker.check(Protocol.PeekPromiseCommandMessage.class, expected, actual)
327+
EntryHeaderChecker.check(
328+
commandIndex, Protocol.PeekPromiseCommandMessage.class, expected, actual)
306329
.checkField("name", Protocol.PeekPromiseCommandMessage::getName)
307330
.checkField("key", Protocol.PeekPromiseCommandMessage::getKey)
308331
.checkField(
@@ -319,9 +342,10 @@ public String getName(Protocol.CompletePromiseCommandMessage expected) {
319342

320343
@Override
321344
public void checkEntryHeader(
322-
Protocol.CompletePromiseCommandMessage expected, MessageLite actual)
345+
int commandIndex, Protocol.CompletePromiseCommandMessage expected, MessageLite actual)
323346
throws ProtocolException {
324-
EntryHeaderChecker.check(Protocol.CompletePromiseCommandMessage.class, expected, actual)
347+
EntryHeaderChecker.check(
348+
commandIndex, Protocol.CompletePromiseCommandMessage.class, expected, actual)
325349
.checkField("name", Protocol.CompletePromiseCommandMessage::getName)
326350
.checkField("key", Protocol.CompletePromiseCommandMessage::getKey)
327351
.checkField(
@@ -344,9 +368,11 @@ public String getName(Protocol.SendSignalCommandMessage expected) {
344368
}
345369

346370
@Override
347-
public void checkEntryHeader(Protocol.SendSignalCommandMessage expected, MessageLite actual)
371+
public void checkEntryHeader(
372+
int commandIndex, Protocol.SendSignalCommandMessage expected, MessageLite actual)
348373
throws ProtocolException {
349-
EntryHeaderChecker.check(Protocol.SendSignalCommandMessage.class, expected, actual)
374+
EntryHeaderChecker.check(
375+
commandIndex, Protocol.SendSignalCommandMessage.class, expected, actual)
350376
.checkField("entry_name", Protocol.SendSignalCommandMessage::getEntryName)
351377
.checkField(
352378
"target_invocation_id", Protocol.SendSignalCommandMessage::getTargetInvocationId)
@@ -368,9 +394,10 @@ public String getName(Protocol.AttachInvocationCommandMessage expected) {
368394

369395
@Override
370396
public void checkEntryHeader(
371-
Protocol.AttachInvocationCommandMessage expected, MessageLite actual)
397+
int commandIndex, Protocol.AttachInvocationCommandMessage expected, MessageLite actual)
372398
throws ProtocolException {
373-
EntryHeaderChecker.check(Protocol.AttachInvocationCommandMessage.class, expected, actual)
399+
EntryHeaderChecker.check(
400+
commandIndex, Protocol.AttachInvocationCommandMessage.class, expected, actual)
374401
.checkField("name", Protocol.AttachInvocationCommandMessage::getName)
375402
.checkField("invocation_id", Protocol.AttachInvocationCommandMessage::getInvocationId)
376403
.checkField(
@@ -389,10 +416,12 @@ public String getName(Protocol.GetInvocationOutputCommandMessage expected) {
389416

390417
@Override
391418
public void checkEntryHeader(
392-
Protocol.GetInvocationOutputCommandMessage expected, MessageLite actual)
419+
int commandIndex,
420+
Protocol.GetInvocationOutputCommandMessage expected,
421+
MessageLite actual)
393422
throws ProtocolException {
394423
EntryHeaderChecker.check(
395-
Protocol.GetInvocationOutputCommandMessage.class, expected, actual)
424+
commandIndex, Protocol.GetInvocationOutputCommandMessage.class, expected, actual)
396425
.checkField("name", Protocol.GetInvocationOutputCommandMessage::getName)
397426
.checkField(
398427
"invocation_id", Protocol.GetInvocationOutputCommandMessage::getInvocationId)

sdk-core/src/main/java/dev/restate/sdk/core/statemachine/EntryHeaderChecker.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,38 +23,43 @@
2323
* exceptions when mismatches are found.
2424
*/
2525
final class EntryHeaderChecker<E extends MessageLite> {
26+
private final int commandIndex;
2627
private final E expected;
2728
private final E actual;
2829
private List<FieldMismatch> mismatches;
2930

30-
private EntryHeaderChecker(E expected, E actual) {
31+
private EntryHeaderChecker(int commandIndex, E expected, E actual) {
32+
this.commandIndex = commandIndex;
3133
this.expected = expected;
3234
this.actual = actual;
3335
}
3436

3537
/**
3638
* Creates a new EntryHeaderChecker for the given expected and actual messages.
3739
*
40+
* @param <E> The type of the expected message
41+
* @param commandIndex The index of this command
3842
* @param expected The expected message
3943
* @param actual The actual message
40-
* @param <E> The type of the expected message
4144
* @return A new EntryHeaderChecker
4245
*/
4346
@SuppressWarnings("unchecked")
4447
public static <E extends MessageLite> EntryHeaderChecker<E> check(
45-
Class<E> expectedClass, E expected, MessageLite actual) {
48+
int commandIndex, Class<E> expectedClass, E expected, MessageLite actual) {
4649
if (!expectedClass.isInstance(actual)) {
4750
throw new ProtocolException(
4851
"Found a mismatch between the code paths taken during the previous execution and the paths taken during this execution.\n"
4952
+ "This typically happens when some parts of the code are non-deterministic.\n"
5053
+ "- Expecting command '"
5154
+ Util.commandMessageToString(expected)
52-
+ "' but was '"
55+
+ "' (index "
56+
+ commandIndex
57+
+ ") but was '"
5358
+ Util.commandMessageToString(actual)
5459
+ "'",
5560
JOURNAL_MISMATCH_CODE);
5661
}
57-
return new EntryHeaderChecker<>(expected, (E) actual);
62+
return new EntryHeaderChecker<>(commandIndex, expected, (E) actual);
5863
}
5964

6065
/**
@@ -97,7 +102,9 @@ private ProtocolException createMismatchException() {
97102
+ "This typically happens when some parts of the code are non-deterministic.\n"
98103
+ "- The mismatch happened while executing '"
99104
+ Util.commandMessageToString(expected)
100-
+ "'\n"
105+
+ " (index "
106+
+ commandIndex
107+
+ ")'\n"
101108
+ "- Difference:");
102109
for (FieldMismatch mismatch : mismatches) {
103110
customMessage

0 commit comments

Comments
 (0)