@@ -3,63 +3,68 @@ package server
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+ "errors"
6
7
"fmt"
7
8
"net/http"
8
- "sync"
9
9
10
10
"github.com/aws/aws-sdk-go/aws"
11
11
"github.com/localstack/lambda-runtime-init/internal/localstack"
12
12
log "github.com/sirupsen/logrus"
13
13
"go.amzn.com/lambda/core/directinvoke"
14
+ "go.amzn.com/lambda/core/statejson"
14
15
"go.amzn.com/lambda/interop"
15
16
"go.amzn.com/lambda/metering"
16
17
"go.amzn.com/lambda/rapi/model"
17
18
"go.amzn.com/lambda/rapidcore"
18
19
"golang.org/x/sync/errgroup"
19
20
)
20
21
21
- type CustomInteropServer struct {
22
+ type LocalStackInteropsServer struct {
22
23
* rapidcore.Server
23
24
localStackAdapter * localstack.LocalStackClient
24
- mutex * sync.Mutex
25
25
}
26
26
27
- func NewInteropServer (server * rapidcore.Server , ls * localstack.LocalStackClient ) * CustomInteropServer {
28
- return & CustomInteropServer {
27
+ func NewInteropServer (server * rapidcore.Server , ls * localstack.LocalStackClient ) * LocalStackInteropsServer {
28
+ return & LocalStackInteropsServer {
29
29
Server : server ,
30
30
localStackAdapter : ls ,
31
- mutex : & sync.Mutex {},
32
31
}
33
32
}
34
33
35
- func (c * CustomInteropServer ) Invoke ( responseWriter http.ResponseWriter , invoke * interop.Invoke ) error {
34
+ func (c * LocalStackInteropsServer ) Execute ( ctx context. Context , responseWriter http.ResponseWriter , invoke * interop.Invoke ) error {
36
35
ctx , cancel := context .WithTimeout (context .Background (), c .Server .GetInvokeTimeout ())
37
36
defer cancel ()
38
37
39
- if err := c .reserveForInvoke (ctx , invoke ); err != nil {
38
+ if err := c .reserve (ctx , invoke ); err != nil {
40
39
return err
41
40
}
42
41
43
- return c .executeInvoke (ctx , responseWriter , invoke )
42
+ if err := c .executeInvoke (ctx , responseWriter , invoke ); err != nil {
43
+ return err
44
+ }
45
+
46
+ return nil
44
47
}
45
48
46
- func (c * CustomInteropServer ) executeInvoke (ctx context.Context , responseWriter http.ResponseWriter , invoke * interop.Invoke ) error {
49
+ func (c * LocalStackInteropsServer ) Invoke (responseWriter http.ResponseWriter , invoke * interop.Invoke ) error {
50
+ return c .Execute (context .Background (), responseWriter , invoke )
51
+ }
52
+
53
+ func (c * LocalStackInteropsServer ) executeInvoke (ctx context.Context , responseWriter http.ResponseWriter , invoke * interop.Invoke ) error {
47
54
g , gCtx := errgroup .WithContext (ctx )
48
55
49
56
g .Go (func () error {
50
57
isDirect := directinvoke .MaxDirectResponseSize > interop .MaxPayloadSize
51
- if err := c .Server .FastInvoke (responseWriter , invoke , isDirect ); err != nil {
52
- log .Debugf ("FastInvoke() error: %s" , err )
58
+ err := c .Server .FastInvoke (responseWriter , invoke , isDirect )
59
+ if err != nil {
60
+ log .WithError (err ).Debug ("FastInvoke() failed" )
53
61
}
54
- return nil
62
+ return err
55
63
})
56
64
57
65
g .Go (func () error {
58
- _ , err := c .Server .AwaitRelease ()
59
- if err != nil {
60
- return c .handleReleaseError (err )
61
- }
62
- return nil
66
+ _ , err := c .AwaitRelease ()
67
+ return err
63
68
})
64
69
65
70
done := make (chan error , 1 )
@@ -71,11 +76,17 @@ func (c *CustomInteropServer) executeInvoke(ctx context.Context, responseWriter
71
76
case err := <- done :
72
77
return err
73
78
case <- gCtx .Done ():
74
- return c .handleTimeout ()
79
+ if errors .Is (gCtx .Err (), context .DeadlineExceeded ) {
80
+ if _ , resetErr := c .Server .Reset ("Timeout" , 2000 ); resetErr != nil {
81
+ log .WithError (resetErr ).Errorf ("Reset failed" )
82
+ }
83
+ return rapidcore .ErrInvokeTimeout
84
+ }
85
+ return nil
75
86
}
76
87
}
77
88
78
- func (c * CustomInteropServer ) reserveForInvoke (ctx context.Context , invoke * interop.Invoke ) error {
89
+ func (c * LocalStackInteropsServer ) reserve (ctx context.Context , invoke * interop.Invoke ) error {
79
90
reserveResp , err := c .Server .Reserve (invoke .ID , invoke .TraceID , invoke .LambdaSegmentID )
80
91
if err != nil {
81
92
return err
@@ -89,12 +100,18 @@ func (c *CustomInteropServer) reserveForInvoke(ctx context.Context, invoke *inte
89
100
switch err {
90
101
case rapidcore .ErrInitDoneFailed :
91
102
if _ , resetErr := c .Server .Reset ("InitFailed" , 2000 ); resetErr != nil {
92
- log .Errorf ( "Reset failed: %v" , resetErr )
103
+ log .WithError ( resetErr ). Debug ( "Reset failed" )
93
104
}
94
105
95
- if _ , reserveErr := c .Server .Reserve (invoke .ID , invoke .TraceID , invoke .LambdaSegmentID ); reserveErr != nil {
96
- return reserveErr
106
+ if _ , err := c .Server .Reserve (invoke .ID , invoke .TraceID , invoke .LambdaSegmentID ); err != nil {
107
+ return err
97
108
}
109
+
110
+ // If the original INIT failed, let's do another wait since we've triggered a RESERVE
111
+ if err := c .Server .AwaitInitialized (); err != nil {
112
+ return err
113
+ }
114
+
98
115
return nil
99
116
default :
100
117
return err
@@ -104,31 +121,25 @@ func (c *CustomInteropServer) reserveForInvoke(ctx context.Context, invoke *inte
104
121
return nil
105
122
}
106
123
107
- func (c * CustomInteropServer ) handleReleaseError (err error ) error {
124
+ func (c * LocalStackInteropsServer ) AwaitRelease () (* statejson.ReleaseResponse , error ) {
125
+ resp , err := c .Server .AwaitRelease ()
108
126
switch err {
109
- case rapidcore .ErrReleaseReservationDone :
110
- return nil
127
+ case rapidcore .ErrReleaseReservationDone , nil :
128
+ return resp , nil
111
129
case rapidcore .ErrInitDoneFailed , rapidcore .ErrInvokeDoneFailed :
112
130
if _ , resetErr := c .Server .Reset ("ReleaseFail" , 2000 ); resetErr != nil {
113
131
log .Errorf ("Reset failed: %v" , resetErr )
114
132
}
115
- return err
133
+ return nil , err
116
134
default :
117
135
if _ , resetErr := c .Server .Reset ("UnexpectedError" , 2000 ); resetErr != nil {
118
136
log .Errorf ("Reset failed: %v" , resetErr )
119
137
}
120
- return err
121
- }
122
- }
123
-
124
- func (c * CustomInteropServer ) handleTimeout () error {
125
- if _ , resetErr := c .Server .Reset ("Timeout" , 2000 ); resetErr != nil {
126
- log .Errorf ("Reset failed: %v" , resetErr )
138
+ return nil , err
127
139
}
128
- return rapidcore .ErrInvokeTimeout
129
140
}
130
141
131
- func (c * CustomInteropServer ) SendInitErrorResponse (resp * interop.ErrorInvokeResponse ) error {
142
+ func (c * LocalStackInteropsServer ) SendInitErrorResponse (resp * interop.ErrorInvokeResponse ) error {
132
143
errResp := & model.ErrorResponse {}
133
144
err := json .Unmarshal (resp .Payload , errResp )
134
145
if err != nil {
0 commit comments