@@ -11,8 +11,7 @@ import (
1111 "runtime/debug"
1212 "strconv"
1313 "strings"
14- "sync"
15- "time"
14+ "syscall"
1615
1716 "github.com/aws/aws-sdk-go-v2/config"
1817 "github.com/localstack/lambda-runtime-init/internal/aws/lambda"
@@ -22,16 +21,17 @@ import (
2221 "github.com/localstack/lambda-runtime-init/internal/hotreloading"
2322 "github.com/localstack/lambda-runtime-init/internal/localstack"
2423 "github.com/localstack/lambda-runtime-init/internal/logging"
24+ "github.com/localstack/lambda-runtime-init/internal/sandbox"
2525 "github.com/localstack/lambda-runtime-init/internal/server"
2626
2727 "github.com/localstack/lambda-runtime-init/internal/supervisor"
2828 "github.com/localstack/lambda-runtime-init/internal/tracing"
2929 "github.com/localstack/lambda-runtime-init/internal/utils"
3030 log "github.com/sirupsen/logrus"
3131 "go.amzn.com/lambda/core/directinvoke"
32+ "go.amzn.com/lambda/extensions"
3233 "go.amzn.com/lambda/interop"
33- "go.amzn.com/lambda/rapidcore"
34- supv "go.amzn.com/lambda/supervisor"
34+ "go.amzn.com/lambda/rapid"
3535)
3636
3737func InitLsOpts () * localstack.Config {
@@ -66,7 +66,7 @@ func InitFunctionConfig() lambda.FunctionConfig {
6666 InitializationType : utils .GetEnvWithDefault ("AWS_LAMBDA_INITIALIZATION_TYPE" , "on-demand" ),
6767 LogGroupName : utils .GetEnvWithDefault ("AWS_LAMBDA_LOG_GROUP_NAME" , "/aws/lambda/Functions" ),
6868 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 " ),
7070 FunctionHandler : utils .GetEnvWithDefault ("AWS_LAMBDA_FUNCTION_HANDLER" , os .Getenv ("_HANDLER" )),
7171 }
7272}
@@ -101,6 +101,10 @@ func UnsetLsEnvs() {
101101 }
102102}
103103
104+ type closer struct { fn func () }
105+
106+ func (c * closer ) Close () error { c .fn (); return nil }
107+
104108func main () {
105109 // we're setting this to the same value as in the official RIE
106110 debug .SetGCPercent (33 )
@@ -116,31 +120,19 @@ func main() {
116120 // set up logging following the Logrus logging levels: https://github.com/sirupsen/logrus#level-logging
117121 log .SetReportCaller (true )
118122 // 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 :
122133 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 :
141135 xRayLogLevel = "error"
142- default :
143- log .Fatal ("Invalid value for LOCALSTACK_INIT_LOG_LEVEL" )
144136 }
145137
146138 // patch MaxPayloadSize
@@ -183,52 +175,62 @@ func main() {
183175 }
184176 }
185177
186- ctx , stop := signal .NotifyContext (context .Background (), os . Interrupt )
178+ ctx , stop := signal .NotifyContext (context .Background (), syscall . SIGINT , syscall . SIGTERM )
187179 defer stop ()
188180
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
195182 lsClient := localstack .NewLocalStackClient (lsOpts .RuntimeEndpoint , lsOpts .RuntimeId )
196- interopServer := server .NewInteropServer (defaultServer , lsClient )
197183
198184 // Services required for Sandbox environment
185+ interopServer := server .NewInteropServer (lsClient )
186+ defer interopServer .Close ()
187+
199188 logCollector := logging .NewLogCollector ()
200189 localStackLogsEgressApi := logging .NewLocalStackLogsEgressAPI (logCollector )
201190 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 )
206193
207194 // 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 )
225224
226225 // Start daemons
227226
228- // Start hot-reloading watcher
227+ // file watcher for hot-reloading
228+ fileWatcherContext , cancelFileWatcher := context .WithCancel (ctx )
229+ defer cancelFileWatcher ()
230+
229231 go hotreloading .RunHotReloadingListener (interopServer , lsOpts .HotReloadingPaths , fileWatcherContext , lsOpts .FileWatcherStrategy )
230232
231- // xray daemon
233+ // Start xray daemon
232234 endpoint := "http://" + net .JoinHostPort (lsOpts .LocalstackIP , lsOpts .EdgePort )
233235 xrayConfig := xray .NewConfig (endpoint , xRayLogLevel )
234236 d := xray .NewDaemon (xrayConfig , lsOpts .EnableXRayTelemetry == "1" )
@@ -240,15 +242,11 @@ func main() {
240242 }()
241243 d .Run () // served async
242244
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
249246 localStackService := server .NewLocalStackService (
250247 interopServer , logCollector , lsClient , localStackSupv , xrayConfig .Endpoint , lsOpts , functionConf , awsEnvConf ,
251248 )
249+ defer localStackService .Close ()
252250
253251 // start runtime init. It is important to start `InitHandler` synchronously because we need to ensure the
254252 // notification channels and status fields are properly initialized before `AwaitInitialized`
@@ -258,26 +256,18 @@ func main() {
258256 }
259257
260258 invokeServer := server .NewServer (lsOpts .InteropPort , localStackService )
261- invokeServer .RegisterOnShutdown ( localStackService . Close )
259+ defer invokeServer .Close ( )
262260
263- defer invokeServer .Shutdown (context .Background ())
264-
265- var wg sync.WaitGroup
266-
267- wg .Add (1 )
261+ serverErr := make (chan error , 1 )
268262 go func () {
269- defer wg .Done ()
270263 listener , err := net .Listen ("tcp" , fmt .Sprintf (":%s" , lsOpts .InteropPort ))
271-
272264 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 )
274266 }
275- go invokeServer .Serve (listener )
267+ go func () { serverErr <- invokeServer .Serve (listener ); close ( serverErr ) }( )
276268 log .Debugf ("LocalStack API gateway listening on %s" , listener .Addr ().String ())
277269 }()
278270
279- wg .Wait ()
280-
281271 log .Debugln ("Awaiting initialization of runtime init." )
282272 if err := interopServer .AwaitInitialized (); err != nil {
283273 // Error cases: ErrInitDoneFailed or ErrInitResetReceived
@@ -292,16 +282,13 @@ func main() {
292282 }
293283 }
294284
285+ // Block until context is cancelled OR the server errors out
295286 select {
296287 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+ }
305293 }
306-
307294}
0 commit comments