forked from aws/aws-lambda-runtime-interface-emulator
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathexit.go
More file actions
125 lines (101 loc) · 5.06 KB
/
Copy pathexit.go
File metadata and controls
125 lines (101 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package rapid
import (
"time"
"github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/appctx"
"github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/extensions"
"github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/fatalerror"
"github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/interop"
"github.com/aws/aws-lambda-runtime-interface-emulator/internal/lambda/telemetry"
log "github.com/sirupsen/logrus"
)
func handleInvokeError(execCtx *rapidContext, invokeRequest *interop.Invoke, invokeMx *invokeMetrics, err error) *interop.InvokeFailure {
invokeFailure := newInvokeFailureMsg(execCtx, invokeRequest, invokeMx, err)
// This is the default error response that gets sent back as the function response in failure cases
invokeFailure.DefaultErrorResponse = interop.GetErrorResponseWithFormattedErrorMessage(invokeFailure.ErrorType, invokeFailure.ErrorMessage, invokeRequest.ID)
// Invoke with extensions disabled maintains behaviour parity with pre-extensions rapid
if !extensions.AreEnabled() {
invokeFailure.RequestReset = false
return invokeFailure
}
if err == errResetReceived {
// errResetReceived is returned when execution flow was interrupted by the Reset message,
// hence this error deserves special handling and we yield to main receive loop to handle it
invokeFailure.ResetReceived = true
return invokeFailure
}
invokeFailure.RequestReset = true
return invokeFailure
}
func newInvokeFailureMsg(execCtx *rapidContext, invokeRequest *interop.Invoke, invokeMx *invokeMetrics, err error) *interop.InvokeFailure {
errorType, found := appctx.LoadFirstFatalError(execCtx.appCtx)
if !found {
errorType = fatalerror.SandboxFailure
}
invokeFailure := &interop.InvokeFailure{
ErrorType: errorType,
ErrorMessage: err,
RequestReset: true,
ResetReceived: false,
RuntimeRelease: appctx.GetRuntimeRelease(execCtx.appCtx),
NumActiveExtensions: execCtx.registrationService.CountAgents(),
InvokeReceivedTime: invokeRequest.InvokeReceivedTime,
}
if invokeRequest.InvokeResponseMetrics != nil && interop.IsResponseStreamingMetrics(invokeRequest.InvokeResponseMetrics) {
invokeFailure.ResponseMetrics.RuntimeResponseLatencyMs = telemetry.CalculateDuration(execCtx.RuntimeStartedTime, invokeRequest.InvokeResponseMetrics.StartReadingResponseMonoTimeMs)
invokeFailure.ResponseMetrics.RuntimeTimeThrottledMs = invokeRequest.InvokeResponseMetrics.TimeShapedNs / int64(time.Millisecond)
invokeFailure.ResponseMetrics.RuntimeProducedBytes = invokeRequest.InvokeResponseMetrics.ProducedBytes
invokeFailure.ResponseMetrics.RuntimeOutboundThroughputBps = invokeRequest.InvokeResponseMetrics.OutboundThroughputBps
}
if invokeMx != nil {
invokeFailure.InvokeMetrics.InvokeRequestReadTimeNs = invokeMx.rendererMetrics.ReadTime.Nanoseconds()
invokeFailure.InvokeMetrics.InvokeRequestSizeBytes = int64(invokeMx.rendererMetrics.SizeBytes)
invokeFailure.InvokeMetrics.RuntimeReadyTime = int64(invokeMx.runtimeReadyTime)
invokeFailure.ExtensionNames = execCtx.GetExtensionNames()
}
if execCtx.telemetryAPIEnabled {
invokeFailure.LogsAPIMetrics = interop.MergeSubscriptionMetrics(execCtx.logsSubscriptionAPI.FlushMetrics(), execCtx.telemetrySubscriptionAPI.FlushMetrics())
}
invokeFailure.InvokeResponseMode = invokeRequest.InvokeResponseMode
return invokeFailure
}
func generateInitFailureMsg(execCtx *rapidContext, err error) interop.InitFailure {
errorType, found := appctx.LoadFirstFatalError(execCtx.appCtx)
if !found {
errorType = fatalerror.SandboxFailure
}
initFailureMsg := interop.InitFailure{
RequestReset: true,
ErrorType: errorType,
ErrorMessage: err,
RuntimeRelease: appctx.GetRuntimeRelease(execCtx.appCtx),
NumActiveExtensions: execCtx.registrationService.CountAgents(),
Ack: make(chan struct{}),
}
if execCtx.telemetryAPIEnabled {
initFailureMsg.LogsAPIMetrics = interop.MergeSubscriptionMetrics(execCtx.logsSubscriptionAPI.FlushMetrics(), execCtx.telemetrySubscriptionAPI.FlushMetrics())
}
return initFailureMsg
}
func handleInitError(execCtx *rapidContext, invokeID string, err error, initFailureResponse chan<- interop.InitFailure) {
log.WithError(err).WithField("InvokeID", invokeID).Error("Init failed")
initFailureMsg := generateInitFailureMsg(execCtx, err)
if err == errResetReceived {
// errResetReceived is returned when execution flow was interrupted by the Reset message,
// hence this error deserves special handling and we yield to main receive loop to handle it
initFailureMsg.ResetReceived = true
initFailureResponse <- initFailureMsg
<-initFailureMsg.Ack
return
}
if !execCtx.HasActiveExtensions() && !execCtx.standaloneMode {
// different behaviour when no extensions are present,
// for compatibility with previous implementations
initFailureMsg.RequestReset = false
} else {
initFailureMsg.RequestReset = true
}
initFailureResponse <- initFailureMsg
<-initFailureMsg.Ack
}