Skip to content

Commit a121a9a

Browse files
committed
Merge branch 'normj/response-streaming' into normj/aspnetcore-responsestreaming
2 parents e9f7dd7 + 2eb2eb4 commit a121a9a

24 files changed

+917
-363
lines changed

.autover/changes/c27a62e6-91ca-4a59-9406-394866cdfa62.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,15 @@
44
"Name": "Amazon.Lambda.RuntimeSupport",
55
"Type": "Minor",
66
"ChangelogMessages": [
7-
"Add response streaming support"
7+
"(Preview) Add response streaming support"
88
]
9-
}
9+
},
10+
{
11+
"Name": "Amazon.Lambda.Core",
12+
"Type": "Minor",
13+
"ChangelogMessages": [
14+
"(Preview) Add response streaming support"
15+
]
16+
}
1017
]
1118
}

Libraries/src/Amazon.Lambda.Core/ResponseStreaming/HttpResponseStreamPrelude.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Amazon.Lambda.Core.ResponseStreaming
1111
/// <summary>
1212
/// The HTTP response prelude to be sent as the first chunk of a streaming response when using <see cref="LambdaResponseStreamFactory.CreateHttpStream"/>.
1313
/// </summary>
14-
[RequiresPreviewFeatures(LambdaResponseStreamFactory.ParameterizedPreviewMessage)]
14+
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
1515
public class HttpResponseStreamPrelude
1616
{
1717
/// <summary>

Libraries/src/Amazon.Lambda.Core/ResponseStreaming/LambdaResponseStream.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Amazon.Lambda.Core.ResponseStreaming
1515
/// to the Lambda Runtime API. Returned by <see cref="LambdaResponseStreamFactory.CreateStream"/>.
1616
/// Integrates with standard .NET stream consumers such as <see cref="System.IO.StreamWriter"/>.
1717
/// </summary>
18-
[RequiresPreviewFeatures(LambdaResponseStreamFactory.ParameterizedPreviewMessage)]
18+
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
1919
public class LambdaResponseStream : Stream
2020
{
2121
private readonly ILambdaResponseStream _responseStream;
@@ -82,24 +82,24 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc
8282
/// <exception cref="NotSupportedException">Always thrown.</exception>
8383
public override long Position
8484
{
85-
get => throw new NotSupportedException("LambdaResponseStream does not support seeking.");
86-
set => throw new NotSupportedException("LambdaResponseStream does not support seeking.");
85+
get => throw new NotSupportedException($"{nameof(LambdaResponseStream)} does not support seeking.");
86+
set => throw new NotSupportedException($"{nameof(LambdaResponseStream)} does not support seeking.");
8787
}
8888

8989
/// <summary>Not supported.</summary>
9090
/// <exception cref="NotImplementedException">Always thrown.</exception>
9191
public override long Seek(long offset, SeekOrigin origin)
92-
=> throw new NotImplementedException("LambdaResponseStream does not support seeking.");
92+
=> throw new NotImplementedException($"{nameof(LambdaResponseStream)} does not support seeking.");
9393

9494
/// <summary>Not supported.</summary>
9595
/// <exception cref="NotImplementedException">Always thrown.</exception>
9696
public override int Read(byte[] buffer, int offset, int count)
97-
=> throw new NotImplementedException("LambdaResponseStream does not support reading.");
97+
=> throw new NotImplementedException($"{nameof(LambdaResponseStream)} does not support reading.");
9898

9999
/// <summary>Not supported.</summary>
100100
/// <exception cref="NotImplementedException">Always thrown.</exception>
101101
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
102-
=> throw new NotImplementedException("LambdaResponseStream does not support reading.");
102+
=> throw new NotImplementedException($"{nameof(LambdaResponseStream)} does not support reading.");
103103

104104
/// <summary>
105105
/// Writes a sequence of bytes to the stream. Delegates to the async path synchronously.
@@ -116,7 +116,7 @@ public override void Flush() { }
116116
/// <summary>Not supported.</summary>
117117
/// <exception cref="NotSupportedException">Always thrown.</exception>
118118
public override void SetLength(long value)
119-
=> throw new NotSupportedException("LambdaResponseStream does not support SetLength.");
119+
=> throw new NotSupportedException($"{nameof(LambdaResponseStream)} does not support SetLength.");
120120
#endregion
121121
}
122122
}

Libraries/src/Amazon.Lambda.Core/ResponseStreaming/LambdaResponseStreamFactory.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@ namespace Amazon.Lambda.Core.ResponseStreaming
1010
/// <summary>
1111
/// Factory to create Lambda response streams for writing streaming responses in AWS Lambda functions. The created streams are write-only and non-seekable.
1212
/// </summary>
13-
[RequiresPreviewFeatures(LambdaResponseStreamFactory.ParameterizedPreviewMessage)]
13+
[RequiresPreviewFeatures(LambdaResponseStreamFactory.PreviewMessage)]
1414
public class LambdaResponseStreamFactory
1515
{
16-
internal const string ParameterizedPreviewMessage =
16+
internal const string PreviewMessage =
1717
"Response streaming is in preview till a new version of .NET Lambda runtime client that supports response streaming " +
1818
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
1919
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"EnablePreviewFeatures\" in the Lambda " +
2020
"project file to \"true\"";
2121

22+
internal const string UninitializedFactoryMessage =
23+
"LambdaResponseStreamFactory is not initialized. This is caused by mismatch versions of Amazon.Lambda.Core and Amazon.Lambda.RuntimeSupport. " +
24+
"Update both packages to the current version to address the issue.";
25+
2226
private static Func<byte[], ILambdaResponseStream> _streamFactory;
2327

2428
internal static void SetLambdaResponseStream(Func<byte[], ILambdaResponseStream> streamFactory)
@@ -27,19 +31,22 @@ internal static void SetLambdaResponseStream(Func<byte[], ILambdaResponseStream>
2731
}
2832

2933
/// <summary>
30-
/// Creates a <see cref="Stream"/> that can be used to write streaming responses back to callers of the Lambda function. Once
34+
/// Creates a <see cref="LambdaResponseStream"/> a subclass of <see cref="Stream"/> that can be used to write streaming responses back to callers of the Lambda function. Once
3135
/// a Lambda function creates a response stream all output must be returned by writing to the stream; the Lambda function's handler
3236
/// return value will be ignored. The stream is write-only and non-seekable.
3337
/// </summary>
3438
/// <returns></returns>
35-
public static Stream CreateStream()
39+
public static LambdaResponseStream CreateStream()
3640
{
41+
if (_streamFactory == null)
42+
throw new InvalidOperationException(UninitializedFactoryMessage);
43+
3744
var runtimeResponseStream = _streamFactory(Array.Empty<byte>());
3845
return new LambdaResponseStream(runtimeResponseStream);
3946
}
4047

4148
/// <summary>
42-
/// Create a <see cref="Stream"/> for writing streaming responses, with an HTTP response prelude containing status code and headers. This should be used for
49+
/// Creates a <see cref="LambdaResponseStream"/> a subclass of <see cref="Stream"/> for writing streaming responses, with an HTTP response prelude containing status code and headers. This should be used for
4350
/// Lambda functions using response streaming that are invoked via the Lambda Function URLs or API Gateway HTTP APIs, where the response format is expected to be an HTTP response.
4451
/// The prelude will be serialized and sent as the first chunk of the response stream, and should contain any necessary HTTP status code and headers.
4552
/// <para>
@@ -49,8 +56,14 @@ public static Stream CreateStream()
4956
/// </summary>
5057
/// <param name="prelude">The HTTP response prelude including status code and headers.</param>
5158
/// <returns></returns>
52-
public static Stream CreateHttpStream(HttpResponseStreamPrelude prelude)
59+
public static LambdaResponseStream CreateHttpStream(HttpResponseStreamPrelude prelude)
5360
{
61+
if (_streamFactory == null)
62+
throw new InvalidOperationException(UninitializedFactoryMessage);
63+
64+
if (prelude is null)
65+
throw new ArgumentNullException(nameof(prelude));
66+
5467
var runtimeResponseStream = _streamFactory(prelude.ToByteArray());
5568
return new LambdaResponseStream(runtimeResponseStream);
5669
}

Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/LambdaBootstrap.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ internal async Task InvokeOnceAsync(CancellationToken cancellationToken = defaul
425425
{
426426
// Wait for the streaming response to finish sending before allowing the next invocation to be processed. This ensures that responses are sent in the order the invocations were received.
427427
await sendTask;
428+
sendTask.Result.Dispose();
428429
}
429430

430431
streamIfCreated.Dispose();
@@ -466,10 +467,7 @@ internal async Task InvokeOnceAsync(CancellationToken cancellationToken = defaul
466467
}
467468
finally
468469
{
469-
if (runtimeApiClient != null)
470-
{
471-
ResponseStreamFactory.CleanupInvocation(isMultiConcurrency);
472-
}
470+
ResponseStreamFactory.CleanupInvocation(isMultiConcurrency);
473471
invocation.Dispose();
474472
}
475473
};

0 commit comments

Comments
 (0)