Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should I use single instance AmazonS3Client for whole web application or per web request create new instance #1713

Closed
madhub opened this issue Sep 18, 2020 · 7 comments
Labels
closed-for-staleness guidance Question that needs advice or information. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. s3

Comments

@madhub
Copy link
Contributor

madhub commented Sep 18, 2020

The Question

Should I use single instance AmazonS3Client for whole web application or per web request create new instance.

We are using AWS S3 SDK to upload objects inside our ASP.NET Core web application.

  • Is AmazonS3Client thread safe to use across requests processing in ASP.NET core Web application?
  • Should we use single instance of AmazonS3Client or create per request new instance ?
  • Should we register AmazonS3Client in the ASP.NET DI system as transient, scoped or singleton ?.

Environment

  • SDK Version: AWSSDK.Core 3.3.103.70, AWSSDK.S3 3.3.108.4
  • Package Version:
  • OS Info: Linux
  • Build Environment : Visual Studio
  • Targeted .NET Platform: .NET Core 2.1

This is a ❓ general question

@madhub madhub added guidance Question that needs advice or information. needs-triage This issue or PR still needs to be triaged. labels Sep 18, 2020
@ashishdhingra
Copy link
Contributor

Hi @madhub,

As a general guidance, using the Singleton instance of AmazonS3Client class is a better approach as opposed to creating instance every time, since the credentials and profile resolution are done once. Also, if you use the AWSSDK.Extensions.NETCore.Setup to configure AWS services (example here), it creates the service client as Singleton.

Hope this provides some guidance.

Thanks,
Ashish

@ashishdhingra ashishdhingra added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed needs-triage This issue or PR still needs to be triaged. labels Sep 18, 2020
@ArchanaNeog
Copy link

ArchanaNeog commented Sep 18, 2020

@ashishdhingra: I am using a single instance of AmazonS3Client for one of my web applications. It is noticed that if I make a concurrent request to PutObjectAsync, it throws an intermittent error. Below is the stack trace

InnerException StackTrace at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token)
at System.Net.FixedSizeReader.ReadPacketAsync(Stream transport, AsyncProtocolRequest request)
at System.Net.Security.SslState.ThrowIfExceptional()
at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
at System.Net.Security.SslStream.<>c.b__47_1(IAsyncResult iar)
at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Threading.Tasks.ValueTask1.get_Result() at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask1 creationTask)
at System.Threading.Tasks.ValueTask1.get_Result() at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Amazon.Runtime.HttpWebRequestMessage.GetResponseAsync(CancellationToken cancellationToken)
at Amazon.Runtime.Internal.HttpHandler`1.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.RedirectHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.Unmarshaller.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.S3.Internal.AmazonS3ResponseHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.S3.Internal.AmazonS3ExceptionHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
at Amazon.Runtime.Internal.MetricsHandler.InvokeAsync[T](IExecutionContext executionContext)

Any input is really appreciated.

Thanks.

@ashishdhingra
Copy link
Contributor

@ArchanaNeog Could you please share code snippet to investigate further? I'm not sure if this is an issue with the SDK since it appears to be SocketException. Also confirm of instantiating client for every request gives the same intermittent error.

Also note that objects which are Disposable should be disposed properly.

@ashishdhingra ashishdhingra added response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. and removed response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. labels Sep 18, 2020
@madhub
Copy link
Contributor Author

madhub commented Sep 19, 2020

@ashishdhingra
Thanks for the reply.

What if we have use temporary credentials ? then single instance created in the beginning won't work right ?.

Our application is Asp.net Core web API which stores data to into S3 , it receives temporary S3 credentials and bucket from another service. What is the recommendation for this use case ?.
Currently we create AmazonS3Client instance for temporary S3 credentials and bucket combination and when token expires we dispose AmazonS3Client instance . In this approach we may have multiple instance of AmazonS3Clients (temp creds+bucket combination) in single ASP.NET core process , Is it right approach ?. Is their better way to handle this ?

Madhu

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Sep 20, 2020
@ashishdhingra
Copy link
Contributor

@madhub The use of single instance versus instance per request depends on your application scenario, where single instance has added benefit of executing initialization tasks only once. In case your AmazonS3Client requests temporary credentials from another service, then using instance per request is recommended. In this case, if you decide to use single/shared instance, then extra step to refresh the credentials, if expired, is required. Hope this helps.

Thanks,
Ashish

@ashishdhingra ashishdhingra added the response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. label Sep 21, 2020
@github-actions
Copy link

github-actions bot commented Oct 6, 2020

This issue has not recieved a response in 2 weeks. If you want to keep this issue open, please just leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Oct 6, 2020
@github-actions github-actions bot added closed-for-staleness and removed closing-soon This issue will automatically close in 4 days unless further comments are made. labels Oct 13, 2020
@madhub
Copy link
Contributor Author

madhub commented Oct 14, 2020

One observation was if AmazonS3Client.PutObjectAsync function times out , API was throwing "OperationCanceledException/TaskCanceledException ." even though we did not use the cancellation tokens, after further investigation found that issue is due to .NET HttpClient behavior . It good to document this behavior in the API.

For information about the HttpClient API behavior here
dotnet/runtime#21965
dotnet/runtime#2281
Update MSDN documentation on this issue https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.sendasync?view=net-5.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-for-staleness guidance Question that needs advice or information. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. s3
Projects
None yet
Development

No branches or pull requests

3 participants