public ExecutionResponse Execute(ExecutionRequest request) { var logger = new LocalLambdaLogger(); var response = new ExecutionResponse(); if (!string.IsNullOrEmpty(request.Function.ErrorMessage)) { response.Error = request.Function.ErrorMessage; return(response); } try { if (!string.IsNullOrEmpty(request.AWSRegion)) { Environment.SetEnvironmentVariable("AWS_REGION", request.AWSRegion); } if (!string.IsNullOrEmpty(request.AWSProfile)) { Environment.SetEnvironmentVariable("AWS_PROFILE", request.AWSProfile); } var context = new LocalLambdaContext() { Logger = logger }; object instance = null; if (!request.Function.LambdaMethod.IsStatic) { instance = Activator.CreateInstance(request.Function.LambdaType); } var parameters = BuildParameters(request, context); // Because a Lambda compute environment never executes more then one event at a time // create a lock around the execution to match that environment. lock (EXECUTE_LOCK) { using (var wrapper = new ConsoleOutWrapper(logger)) { var lambdaReturnObject = request.Function.LambdaMethod.Invoke(instance, parameters); response.Response = ProcessReturn(request, lambdaReturnObject); } } } catch (TargetInvocationException e) { response.Error = GenerateErrorMessage(e.InnerException); } catch (Exception e) { response.Error = GenerateErrorMessage(e); } response.Logs = logger.Buffer; return(response); }
public static async Task <string> ProcessReturnAsync(ExecutionRequest request, object lambdaReturnObject) { Stream lambdaReturnStream = null; if (lambdaReturnObject == null) { return(null); } // If the return was a Task then wait till the task is complete. if (lambdaReturnObject is Task task) { await task; // Check to see if the Task returns back an object. if (task.GetType().IsGenericType) { var resultProperty = task.GetType().GetProperty("Result", BindingFlags.Public | BindingFlags.Instance); if (resultProperty != null) { var taskResult = resultProperty.GetMethod.Invoke(task, null); if (taskResult is Stream stream) { lambdaReturnStream = stream; } else { lambdaReturnStream = new MemoryStream(); request.Function.Serializer.Serialize(taskResult, lambdaReturnStream); } } } } else { lambdaReturnStream = new MemoryStream(); request.Function.Serializer.Serialize(lambdaReturnObject, lambdaReturnStream); } if (lambdaReturnStream == null) { return(null); } lambdaReturnStream.Position = 0; using (var reader = new StreamReader(lambdaReturnStream)) { return(reader.ReadToEnd()); } }
/// <summary> /// Create the parameter array that will be passed into the Invoke for the Lambda function. /// </summary> /// <param name="request"></param> /// <param name="context"></param> /// <returns></returns> /// <exception cref="Exception"></exception> public static object[] BuildParameters(ExecutionRequest request, ILambdaContext context) { var parms = request.Function.LambdaMethod.GetParameters(); var parmValues = new object[parms.Length]; if (parmValues.Length > 2) { throw new Exception($".NET Method has too many parameters, {parmValues.Length}. Methods called by Lambda can have at most 2 parameters. The first is the input object and the second is an ILambdaContext."); } for (var i = 0; i < parms.Length; i++) { if (parms[i].ParameterType == typeof(ILambdaContext)) { parmValues[i] = context; } else { var bytes = Encoding.UTF8.GetBytes((request.Payload != null) ? request.Payload : "{}"); var stream = new MemoryStream(bytes); if (request.Function.Serializer != null) { var genericMethodInfo = request.Function.Serializer.GetType() .GetMethods(BindingFlags.Public | BindingFlags.Instance) .FirstOrDefault(x => string.Equals(x.Name, "Deserialize")); var methodInfo = genericMethodInfo.MakeGenericMethod(new Type[] { parms[i].ParameterType }); try { parmValues[i] = methodInfo.Invoke(request.Function.Serializer, new object[] { stream }); } catch (Exception e) { throw new Exception($"Error deserializing the input JSON to type {parms[i].ParameterType.Name}", e); } } else { parmValues[i] = stream; } } } return(parmValues); }
private async Task Loop(CancellationToken token) { var aws = this._runtime.AWSService; while (!token.IsCancellationRequested) { Message message = null; LogRecord logRecord = null; try { // Read a message from the queue using the ExternalCommands console application. message = await aws.ReadMessageAsync(this._profile, this._region, this._queueUrl); if (token.IsCancellationRequested) { return; } if (message == null) { // Since there are no messages, sleep a bit to wait for messages to come. Thread.Sleep(1000); continue; } // If a message was received execute the Lambda function within the test tool. var request = new ExecutionRequest { AWSProfile = this._profile, AWSRegion = this._region, Function = this._function, Payload = message.Body }; var response = await this._runtime.ExecuteLambdaFunctionAsync(request); // Capture the results to send back to the client application. logRecord = new LogRecord { ProcessTime = DateTime.Now, ReceiptHandle = message.ReceiptHandle, Logs = response.Logs, Error = response.Error }; } catch (Exception e) { logRecord = new LogRecord { ProcessTime = DateTime.Now, Error = e.Message }; Thread.Sleep(1000); } if (logRecord != null && message != null) { logRecord.Event = message.Body; } lock (LOG_LOCK) { this._records.Add(logRecord); } } }
/// <summary> /// Execute the Lambda function. /// </summary> /// <param name="request"></param> /// <returns></returns> public ExecutionResponse ExecuteLambdaFunction(ExecutionRequest request) { return(new LambdaExecutor().Execute(request)); }
/// <summary> /// Execute the Lambda function. /// </summary> /// <param name="request"></param> /// <returns></returns> public async Task <ExecutionResponse> ExecuteLambdaFunctionAsync(ExecutionRequest request) { return(await(new LambdaExecutor()).ExecuteAsync(request)); }