diff options
Diffstat (limited to 'docs/library/aws-lambda.md')
-rw-r--r-- | docs/library/aws-lambda.md | 262 |
1 files changed, 0 insertions, 262 deletions
diff --git a/docs/library/aws-lambda.md b/docs/library/aws-lambda.md deleted file mode 100644 index 3fb0a5c0..00000000 --- a/docs/library/aws-lambda.md +++ /dev/null @@ -1,262 +0,0 @@ -# AWS Lambda -RoadRunner can run PHP as AWS Lambda function. - -### Installation -Prior to the function deployment, you must compile or download PHP binary files to run your application. There are multiple projects available for such goal: - -- https://github.com/araines/serverless-php -- https://github.com/stechstudio/php-lambda (includes pre-built versions of PHP binaries) - -Place PHP binaries in a `bin/` folder of your project. - -### PHP Worker -PHP worker does not require any specific configuration to run inside Lambda function. We can use default snippet with internal counter to demonstrate how workers are being reused: - -```php -<?php -/** - * @var Goridge\RelayInterface $relay - */ -use Spiral\Goridge; -use Spiral\RoadRunner; - -ini_set('display_errors', 'stderr'); -require __DIR__ . "/vendor/autoload.php"; - -$worker = new RoadRunner\Worker(new Goridge\StreamRelay(STDIN, STDOUT)); -$psr7 = new RoadRunner\Http\PSR7Worker( - $worker, - new \Nyholm\Psr7\Factory\Psr17Factory(), - new \Nyholm\Psr7\Factory\Psr17Factory(), - new \Nyholm\Psr7\Factory\Psr17Factory() -); - -while ($req = $psr7->waitRequest()) { - try { - $resp = new \Nyholm\Psr7\Response(); - $resp->getBody()->write(str_repeat("hello world", 1000)); - - $psr7->respond($resp); - } catch (\Throwable $e) { - $psr7->getWorker()->error((string)$e); - } - -``` - -Name this file `handler.php` and put it into the root of your project. Make sure to run `composer require spiral/roadrunner`. - -### Application -We can create a simple application to demonstrate how it works: -1. You need 3 files, main.go with the `Endure` container: - -```golang -import ( - _ "embed" - "log" - "os" - "os/signal" - "sync" - "syscall" - "time" - - endure "github.com/spiral/endure/pkg/container" - "github.com/spiral/roadrunner/v2/plugins/config" - "github.com/spiral/roadrunner/v2/plugins/logger" - "github.com/spiral/roadrunner/v2/plugins/server" -) - -//go:embed .rr.yaml -var rrYaml []byte - -func main() { - _ = os.Setenv("PATH", os.Getenv("PATH")+":"+os.Getenv("LAMBDA_TASK_ROOT")) - _ = os.Setenv("LD_LIBRARY_PATH", "./lib:/lib64:/usr/lib64") - - cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel)) - if err != nil { - log.Fatal(err) - } - - cfg := &config.Viper{} - cfg.CommonConfig = &config.General{GracefulTimeout: time.Second * 30} - cfg.ReadInCfg = rrYaml - cfg.Type = "yaml" - - // only 4 plugins needed here - // 1. Server which should provide pool to us - // 2. Our mini plugin, which expose this pool for us - // 3. Logger - // 4. Configurer - err = cont.RegisterAll( - cfg, - &logger.ZapLogger{}, - &Plugin{}, - &server.Plugin{}, - ) - if err != nil { - log.Fatal(err) - } - - err = cont.Init() - if err != nil { - log.Fatal(err) - } - - ch, err := cont.Serve() - if err != nil { - log.Fatal(err) - } - - sig := make(chan os.Signal, 1) - signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) - - wg := &sync.WaitGroup{} - wg.Add(1) - - go func() { - defer wg.Done() - for { - select { - case e := <-ch: - log.Println(e.Error.Error()) - case <-sig: - err = cont.Stop() - if err != nil { - log.Println(err) - } - return - } - } - }() - - wg.Wait() -} -``` - -2. And `Plugin` for the RR: -```golang -package main - -import ( - "context" - "sync" - "unsafe" - - "github.com/aws/aws-lambda-go/lambda" - "github.com/spiral/roadrunner/v2/pkg/payload" - "github.com/spiral/roadrunner/v2/pkg/pool" - "github.com/spiral/roadrunner/v2/plugins/logger" - "github.com/spiral/roadrunner/v2/plugins/server" -) - -type Plugin struct { - sync.Mutex - log logger.Logger - srv server.Server - wrkPool pool.Pool -} - -func (p *Plugin) Init(srv server.Server, log logger.Logger) error { - var err error - p.srv = srv - p.log = log - return err -} - -func (p *Plugin) Serve() chan error { - errCh := make(chan error, 1) - p.Lock() - defer p.Unlock() - var err error - - p.wrkPool, err = p.srv.NewWorkerPool(context.Background(), pool.Config{ - Debug: false, - NumWorkers: 1, - MaxJobs: 0, - AllocateTimeout: 0, - DestroyTimeout: 0, - Supervisor: &pool.SupervisorConfig{ - WatchTick: 0, - TTL: 0, - IdleTTL: 0, - ExecTTL: 0, - MaxWorkerMemory: 0, - }, - }, nil, nil) - - go func() { - // register handler - lambda.Start(p.handler()) - }() - - if err != nil { - errCh <- err - } - return errCh -} - -func (p *Plugin) Stop() error { - p.Lock() - defer p.Unlock() - - if p.wrkPool != nil { - p.wrkPool.Destroy(context.Background()) - } - return nil -} - -func (p *Plugin) handler() func(pld string) (string, error) { - return func(pld string) (string, error) { - data := fastConvert(pld) - // execute on worker pool - if p.wrkPool == nil { - // or any error - return "", nil - } - exec, err := p.wrkPool.Exec(payload.Payload{ - Context: nil, - Body: data, - }) - if err != nil { - return "", err - } - return exec.String(), nil - } -} - -// reinterpret_cast conversion cast from string to []byte -// unsafe -func fastConvert(d string) []byte { - return *(*[]byte)(unsafe.Pointer(&d)) -} -``` -3. Config file, which can be embedded into the binary with `embed` import: -```yaml -server: - command: "php handler.php" - user: "" - group: "" - env: - - SOME_KEY: "SOME_VALUE" - - SOME_KEY2: "SOME_VALUE2" - relay: pipes - relay_timeout: 60s -``` -Here you can use full advantage of the RR2, you can include any plugin here and configure it with the embedded config (within reasonable limits). - -To build and package your lambda function run: - -``` -$ GOOS=linux GOARCH=amd64 go build -o main main.go -$ zip main.zip * -r -``` - -You can now upload and invoke your handler using simple string event. - -## Notes -There are multiple notes you have to acknowledge. - -- start with 1 worker per lambda function in order to control your memory usage. -- make sure to include env variables listed in the code to properly resolve the location of PHP binary and it's dependencies. -- avoid database connections without concurrency limit -- avoid database connections |