/*
* Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
using System;
using Amazon.Runtime.Internal.Util;
namespace Amazon.Runtime.Internal
{
///
/// This handler executes the subsequent handlers on a ThreadPool thread.
/// This feature is only implemented for APM based async methods.
///
public class ThreadPoolExecutionHandler : PipelineHandler
{
private static ThreadPoolThrottler _throttler;
private static object _lock = new object();
public ThreadPoolExecutionHandler(int concurrentRequests)
{
lock (_lock)
{
if (_throttler == null)
_throttler = new ThreadPoolThrottler(concurrentRequests);
}
}
#if AWS_APM_API
public override IAsyncResult InvokeAsync(IAsyncExecutionContext executionContext)
{
if (UnityInitializer.IsMainThread())
{
_throttler.Enqueue(executionContext, InvokeAsyncHelper, ErrorCallback);
return null;
}
else
{
return base.InvokeAsync(executionContext);
}
}
#endif
void InvokeAsyncHelper(IAsyncExecutionContext executionContext)
{
base.InvokeAsync(executionContext);
}
void ErrorCallback(Exception exception, IAsyncExecutionContext executionContext)
{
// Handle the exception by logging it and setting the exception on the context,
// so that the exception is visible to the caller
this.Logger.Error(exception, "An exception of type {0} was thrown from InvokeAsyncCallback().",
exception.GetType().Name);
executionContext.RequestContext.Metrics.AddProperty(Metric.Exception, exception);
// An unhandled exception occured in the callback implementation.
// Capture the exception and end the callback processing by signalling the
// wait handle.
executionContext.RequestContext.Metrics.StopEvent(Metric.ClientExecuteTime);
LogMetrics(ExecutionContext.CreateFromAsyncContext(executionContext));
executionContext.ResponseContext.AsyncResult =
new RuntimeAsyncResult(executionContext.RequestContext.Callback,
executionContext.RequestContext.State);
executionContext.ResponseContext.AsyncResult.Exception = exception;
executionContext.ResponseContext.AsyncResult.AsyncOptions = executionContext.RequestContext.AsyncOptions;
executionContext.ResponseContext.AsyncResult.Action = executionContext.RequestContext.Action;
executionContext.ResponseContext.AsyncResult.Request = executionContext.RequestContext.OriginalRequest;
executionContext.ResponseContext.AsyncResult.InvokeCallback();
}
}
}