Skip to content

Commit 7829fd3

Browse files
Allow unaltered payload response from codec (#425)
1 parent 612fe2f commit 7829fd3

File tree

2 files changed

+50
-15
lines changed

2 files changed

+50
-15
lines changed

src/Temporalio/Worker/WorkflowCodecHelper.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,11 +275,16 @@ private static async Task EncodeAsync(IPayloadCodec codec, Payload payload)
275275
{
276276
// We are gonna require a single result here. It is important that we do Single() call
277277
// before clearing out payload to merge with since underlying enumerable may be lazy.
278+
// If the returned payload is literally the same object as the one sent to the codec,
279+
// we leave it alone.
278280
var encodedList = await codec.EncodeAsync(new Payload[] { payload }).ConfigureAwait(false);
279281
var encoded = encodedList.Single();
280-
payload.Metadata.Clear();
281-
payload.Data = ByteString.Empty;
282-
payload.MergeFrom(encoded);
282+
if (!ReferenceEquals(encoded, payload))
283+
{
284+
payload.Metadata.Clear();
285+
payload.Data = ByteString.Empty;
286+
payload.MergeFrom(encoded);
287+
}
283288
}
284289

285290
private static async Task DecodeAsync(IPayloadCodec codec, ActivityResolution res)
@@ -377,11 +382,16 @@ private static async Task DecodeAsync(IPayloadCodec codec, RepeatedField<Payload
377382

378383
private static async Task DecodeAsync(IPayloadCodec codec, Payload payload)
379384
{
380-
// We are gonna require a single result here
385+
// We are gonna require a single result here.
386+
// Similarly with encode, we leave the payload alone if it's exactly the same object as the original.
381387
var decoded = await codec.DecodeAsync(new Payload[] { payload }).ConfigureAwait(false);
382-
payload.Metadata.Clear();
383-
payload.Data = ByteString.Empty;
384-
payload.MergeFrom(decoded.Single());
388+
var decodedPayload = decoded.Single();
389+
if (!ReferenceEquals(decodedPayload, payload))
390+
{
391+
payload.Metadata.Clear();
392+
payload.Data = ByteString.Empty;
393+
payload.MergeFrom(decodedPayload);
394+
}
385395
}
386396
}
387397
}

tests/Temporalio.Tests/Worker/WorkflowCodecHelperTests.cs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ await CreateAndVisitPayload(
4040
public async Task EncodeAsync_AllPayloads_EncodesAll()
4141
{
4242
var comp = new WorkflowActivationCompletion();
43-
var codec = new MarkerPayloadCodec();
43+
var codecs = new List<IPayloadCodec> { new MarkerPayloadCodec(), new MarkerNoClonePayloadCodec() };
4444
await CreateAndVisitPayload(new(), comp, async (ctx, payload) =>
4545
{
4646
// We don't check search attributes on purpose
@@ -49,10 +49,13 @@ await CreateAndVisitPayload(new(), comp, async (ctx, payload) =>
4949
return;
5050
}
5151
Assert.DoesNotContain("encoded", payload().Metadata.Keys);
52-
await WorkflowCodecHelper.EncodeAsync(codec, comp);
53-
if (!payload().Metadata.ContainsKey("encoded"))
52+
foreach (var codec in codecs)
5453
{
55-
Assert.Fail($"Payload at path {ctx.Path} not encoded");
54+
await WorkflowCodecHelper.EncodeAsync(codec, comp);
55+
if (!payload().Metadata.ContainsKey("encoded"))
56+
{
57+
Assert.Fail($"Payload at path {ctx.Path} not encoded with codec {codec}");
58+
}
5659
}
5760
});
5861
}
@@ -61,7 +64,7 @@ await CreateAndVisitPayload(new(), comp, async (ctx, payload) =>
6164
public async Task DecodeAsync_AllPayloads_DecodesAll()
6265
{
6366
var act = new WorkflowActivation();
64-
var codec = new MarkerPayloadCodec();
67+
var codecs = new List<IPayloadCodec> { new MarkerPayloadCodec(), new MarkerNoClonePayloadCodec() };
6568
await CreateAndVisitPayload(new(), act, async (ctx, payload) =>
6669
{
6770
// We don't check search attributes on purpose
@@ -70,10 +73,13 @@ await CreateAndVisitPayload(new(), act, async (ctx, payload) =>
7073
return;
7174
}
7275
Assert.DoesNotContain("decoded", payload().Metadata.Keys);
73-
await WorkflowCodecHelper.DecodeAsync(codec, act);
74-
if (!payload().Metadata.ContainsKey("decoded"))
76+
foreach (var codec in codecs)
7577
{
76-
Assert.Fail($"Payload at path {ctx.Path} not decoded");
78+
await WorkflowCodecHelper.DecodeAsync(codec, act);
79+
if (!payload().Metadata.ContainsKey("decoded"))
80+
{
81+
Assert.Fail($"Payload at path {ctx.Path} not decoded with codec {codec}");
82+
}
7783
}
7884
});
7985
}
@@ -189,4 +195,23 @@ public Task<IReadOnlyCollection<Payload>> DecodeAsync(IReadOnlyCollection<Payloa
189195
return newP;
190196
}).ToList());
191197
}
198+
199+
private class MarkerNoClonePayloadCodec : IPayloadCodec
200+
{
201+
public Task<IReadOnlyCollection<Payload>> EncodeAsync(IReadOnlyCollection<Payload> payloads) =>
202+
Task.FromResult<IReadOnlyCollection<Payload>>(payloads.Select(p =>
203+
{
204+
var newP = p;
205+
newP.Metadata["encoded"] = ByteString.Empty;
206+
return newP;
207+
}).ToList());
208+
209+
public Task<IReadOnlyCollection<Payload>> DecodeAsync(IReadOnlyCollection<Payload> payloads) =>
210+
Task.FromResult<IReadOnlyCollection<Payload>>(payloads.Select(p =>
211+
{
212+
var newP = p;
213+
newP.Metadata["decoded"] = ByteString.Empty;
214+
return newP;
215+
}).ToList());
216+
}
192217
}

0 commit comments

Comments
 (0)