@@ -11,8 +11,7 @@ import (
11
11
"runtime/debug"
12
12
"strconv"
13
13
"strings"
14
- "sync"
15
- "time"
14
+ "syscall"
16
15
17
16
"github.com/aws/aws-sdk-go-v2/config"
18
17
"github.com/localstack/lambda-runtime-init/internal/aws/lambda"
@@ -22,16 +21,17 @@ import (
22
21
"github.com/localstack/lambda-runtime-init/internal/hotreloading"
23
22
"github.com/localstack/lambda-runtime-init/internal/localstack"
24
23
"github.com/localstack/lambda-runtime-init/internal/logging"
24
+ "github.com/localstack/lambda-runtime-init/internal/sandbox"
25
25
"github.com/localstack/lambda-runtime-init/internal/server"
26
26
27
27
"github.com/localstack/lambda-runtime-init/internal/supervisor"
28
28
"github.com/localstack/lambda-runtime-init/internal/tracing"
29
29
"github.com/localstack/lambda-runtime-init/internal/utils"
30
30
log "github.com/sirupsen/logrus"
31
31
"go.amzn.com/lambda/core/directinvoke"
32
+ "go.amzn.com/lambda/extensions"
32
33
"go.amzn.com/lambda/interop"
33
- "go.amzn.com/lambda/rapidcore"
34
- supv "go.amzn.com/lambda/supervisor"
34
+ "go.amzn.com/lambda/rapid"
35
35
)
36
36
37
37
func InitLsOpts () * localstack.Config {
@@ -66,7 +66,7 @@ func InitFunctionConfig() lambda.FunctionConfig {
66
66
InitializationType : utils .GetEnvWithDefault ("AWS_LAMBDA_INITIALIZATION_TYPE" , "on-demand" ),
67
67
LogGroupName : utils .GetEnvWithDefault ("AWS_LAMBDA_LOG_GROUP_NAME" , "/aws/lambda/Functions" ),
68
68
LogStreamName : utils .GetEnvWithDefault ("AWS_LAMBDA_LOG_STREAM_NAME" , "$LATEST" ),
69
- FunctionMemorySizeMb : utils .GetEnvWithDefault ("AWS_LAMBDA_FUNCTION_MEMORY_SIZE" , "3008 " ),
69
+ FunctionMemorySizeMb : utils .GetEnvWithDefault ("AWS_LAMBDA_FUNCTION_MEMORY_SIZE" , "128 " ),
70
70
FunctionHandler : utils .GetEnvWithDefault ("AWS_LAMBDA_FUNCTION_HANDLER" , os .Getenv ("_HANDLER" )),
71
71
}
72
72
}
@@ -101,6 +101,10 @@ func UnsetLsEnvs() {
101
101
}
102
102
}
103
103
104
+ type closer struct { fn func () }
105
+
106
+ func (c * closer ) Close () error { c .fn (); return nil }
107
+
104
108
func main () {
105
109
// we're setting this to the same value as in the official RIE
106
110
debug .SetGCPercent (33 )
@@ -116,31 +120,19 @@ func main() {
116
120
// set up logging following the Logrus logging levels: https://github.com/sirupsen/logrus#level-logging
117
121
log .SetReportCaller (true )
118
122
// https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon-configuration.html
119
- xRayLogLevel := "info"
120
- switch lsOpts .InitLogLevel {
121
- case "trace" :
123
+
124
+ logLevel , err := log .ParseLevel (lsOpts .InitLogLevel )
125
+ if err != nil {
126
+ log .Fatal ("Invalid value for LOCALSTACK_INIT_LOG_LEVEL" )
127
+ }
128
+ log .SetLevel (logLevel )
129
+
130
+ xRayLogLevel := lsOpts .InitLogLevel
131
+ switch logLevel {
132
+ case log .TraceLevel :
122
133
log .SetFormatter (& log.JSONFormatter {})
123
- log .SetLevel (log .TraceLevel )
124
- xRayLogLevel = "debug"
125
- case "debug" :
126
- log .SetLevel (log .DebugLevel )
127
- xRayLogLevel = "debug"
128
- case "info" :
129
- log .SetLevel (log .InfoLevel )
130
- case "warn" :
131
- log .SetLevel (log .WarnLevel )
132
- xRayLogLevel = "warn"
133
- case "error" :
134
- log .SetLevel (log .ErrorLevel )
135
- xRayLogLevel = "error"
136
- case "fatal" :
137
- log .SetLevel (log .FatalLevel )
138
- xRayLogLevel = "error"
139
- case "panic" :
140
- log .SetLevel (log .PanicLevel )
134
+ case log .ErrorLevel , log .FatalLevel , log .PanicLevel :
141
135
xRayLogLevel = "error"
142
- default :
143
- log .Fatal ("Invalid value for LOCALSTACK_INIT_LOG_LEVEL" )
144
136
}
145
137
146
138
// patch MaxPayloadSize
@@ -183,52 +175,62 @@ func main() {
183
175
}
184
176
}
185
177
186
- ctx , stop := signal .NotifyContext (context .Background (), os . Interrupt )
178
+ ctx , stop := signal .NotifyContext (context .Background (), syscall . SIGINT , syscall . SIGTERM )
187
179
defer stop ()
188
180
189
- // file watcher for hot-reloading
190
- fileWatcherContext , cancelFileWatcher := context .WithCancel (ctx )
191
- defer cancelFileWatcher ()
192
-
193
- // Custom Interop Server
194
- defaultServer := rapidcore .NewServer ()
181
+ // LocalStack client used for sending callbacks
195
182
lsClient := localstack .NewLocalStackClient (lsOpts .RuntimeEndpoint , lsOpts .RuntimeId )
196
- interopServer := server .NewInteropServer (defaultServer , lsClient )
197
183
198
184
// Services required for Sandbox environment
185
+ interopServer := server .NewInteropServer (lsClient )
186
+ defer interopServer .Close ()
187
+
199
188
logCollector := logging .NewLogCollector ()
200
189
localStackLogsEgressApi := logging .NewLocalStackLogsEgressAPI (logCollector )
201
190
tracer := tracing .NewLocalStackTracer ()
202
- eventsListener := events .NewLocalStackEventsAPI (lsClient )
203
-
204
- defaultSupv := supv .NewLocalSupervisor ()
205
- localStackSupv := supervisor .NewLocalStackSupervisor (ctx , defaultSupv , eventsListener )
191
+ lsEventsAPI := events .NewLocalStackEventsAPI (lsClient )
192
+ localStackSupv := supervisor .NewLocalStackSupervisor (ctx , lsEventsAPI )
206
193
207
194
// build sandbox
208
- exitChan := make (chan struct {})
209
- sandbox := rapidcore .
210
- NewSandboxBuilder ().
211
- AddShutdownFunc (func () {
212
- log .Debugln ("Stopping file watcher" )
213
- cancelFileWatcher ()
214
- }).
215
- AddShutdownFunc (func () {
216
- exitChan <- struct {}{}
217
- }).
218
- SetExtensionsFlag (true ).
219
- SetInitCachingFlag (true ).
220
- SetLogsEgressAPI (localStackLogsEgressApi ).
221
- SetTracer (tracer ).
222
- SetInteropServer (interopServer ).
223
- SetSupervisor (localStackSupv ).
224
- SetHandler (handler )
195
+ sandboxConfig := rapid.Sandbox {
196
+ EnableTelemetryAPI : false ,
197
+ StandaloneMode : true ,
198
+ InitCachingEnabled : true ,
199
+
200
+ Tracer : tracer ,
201
+ EventsAPI : lsEventsAPI ,
202
+ Supervisor : localStackSupv ,
203
+ InteropServer : interopServer ,
204
+ LogsEgressAPI : localStackLogsEgressApi ,
205
+
206
+ Handler : handler ,
207
+
208
+ RuntimeFsRootPath : "/" ,
209
+ RuntimeAPIHost : "127.0.0.1" ,
210
+ RuntimeAPIPort : 9001 ,
211
+ }
212
+
213
+ extensions .Enable ()
214
+
215
+ rapidCtx , internalStateFn , addr := rapid .Start (ctx , & sandboxConfig )
216
+ sandboxCtx , err := sandbox .CreateSandboxContext (rapidCtx , handler , addr )
217
+ if err != nil {
218
+ log .Fatalf ("fatal error encountered when creating SandboxContext: %w" , err )
219
+ }
220
+
221
+ // Populate our interop server
222
+ interopServer .SetSandboxContext (sandboxCtx )
223
+ interopServer .SetInternalStateGetter (internalStateFn )
225
224
226
225
// Start daemons
227
226
228
- // Start hot-reloading watcher
227
+ // file watcher for hot-reloading
228
+ fileWatcherContext , cancelFileWatcher := context .WithCancel (ctx )
229
+ defer cancelFileWatcher ()
230
+
229
231
go hotreloading .RunHotReloadingListener (interopServer , lsOpts .HotReloadingPaths , fileWatcherContext , lsOpts .FileWatcherStrategy )
230
232
231
- // xray daemon
233
+ // Start xray daemon
232
234
endpoint := "http://" + net .JoinHostPort (lsOpts .LocalstackIP , lsOpts .EdgePort )
233
235
xrayConfig := xray .NewConfig (endpoint , xRayLogLevel )
234
236
d := xray .NewDaemon (xrayConfig , lsOpts .EnableXRayTelemetry == "1" )
@@ -240,15 +242,11 @@ func main() {
240
242
}()
241
243
d .Run () // served async
242
244
243
- // initialize all flows and start runtime API
244
- sandboxContext , internalStateFn := sandbox .Create ()
245
- // Populate our interop server
246
- interopServer .SetSandboxContext (sandboxContext )
247
- interopServer .SetInternalStateGetter (internalStateFn )
248
-
245
+ // Create the LocalStack service
249
246
localStackService := server .NewLocalStackService (
250
247
interopServer , logCollector , lsClient , localStackSupv , xrayConfig .Endpoint , lsOpts , functionConf , awsEnvConf ,
251
248
)
249
+ defer localStackService .Close ()
252
250
253
251
// start runtime init. It is important to start `InitHandler` synchronously because we need to ensure the
254
252
// notification channels and status fields are properly initialized before `AwaitInitialized`
@@ -258,26 +256,18 @@ func main() {
258
256
}
259
257
260
258
invokeServer := server .NewServer (lsOpts .InteropPort , localStackService )
261
- invokeServer .RegisterOnShutdown ( localStackService . Close )
259
+ defer invokeServer .Close ( )
262
260
263
- defer invokeServer .Shutdown (context .Background ())
264
-
265
- var wg sync.WaitGroup
266
-
267
- wg .Add (1 )
261
+ serverErr := make (chan error , 1 )
268
262
go func () {
269
- defer wg .Done ()
270
263
listener , err := net .Listen ("tcp" , fmt .Sprintf (":%s" , lsOpts .InteropPort ))
271
-
272
264
if err != nil {
273
- log .Fatalf ("failed to start listener for custom interops server: %s" , err )
265
+ log .Fatalf ("failed to start LocalStack Lambda Runtime Interface server: %s" , err )
274
266
}
275
- go invokeServer .Serve (listener )
267
+ go func () { serverErr <- invokeServer .Serve (listener ); close ( serverErr ) }( )
276
268
log .Debugf ("LocalStack API gateway listening on %s" , listener .Addr ().String ())
277
269
}()
278
270
279
- wg .Wait ()
280
-
281
271
log .Debugln ("Awaiting initialization of runtime init." )
282
272
if err := interopServer .AwaitInitialized (); err != nil {
283
273
// Error cases: ErrInitDoneFailed or ErrInitResetReceived
@@ -292,16 +282,13 @@ func main() {
292
282
}
293
283
}
294
284
285
+ // Block until context is cancelled OR the server errors out
295
286
select {
296
287
case <- ctx .Done ():
297
- case <- exitChan :
298
- }
299
-
300
- gracefulCtx , cancel := context .WithTimeout (ctx , time .Millisecond * 500 )
301
- defer cancel ()
302
-
303
- if err := localStackService .AwaitCompleted (gracefulCtx ); err != nil {
304
- log .Warnf ("Did not gracefully complete: %w" , err )
288
+ log .Info ("Shutdown signal received." )
289
+ case <- serverErr :
290
+ if err != nil {
291
+ log .Errorf ("Server error: %v" , err )
292
+ }
305
293
}
306
-
307
294
}
0 commit comments