brefphp / bref

Serverless PHP on AWS Lambda
https://bref.sh
MIT License
3.12k stars 367 forks source link

How use SQS Trigger Lambda ? #109

Closed pmayet closed 5 years ago

pmayet commented 5 years ago

A big thank you for this work! I'm looking to use the SQS/Lambda Trigger.

I can push in a queue, but I can't understand or find out how SQS notifies Lambda? I work with Laravel. From my idea, SQS call Lambda on /dev, and in my controller, I invoke the artisan command to consume the queue:

class JobController extends Controller
{
    public function __invoke()
    {
        Artisan::call('queue:work', [
            '--queue' => 'serverless'
        ]);
    }
}

But nothing is done, my job is removed from my queue but the process on the job is not applied?

A logic problem?

Thank you !

mnapoli commented 5 years ago

Thank you! You would basically have this:

The lambda would have to be implemented as a "simple handler":

$app = new \Bref\Application;
$app->simpleHandler(function (array $event) {
    // process $event
});
$app->run();

Check this out to configure serverless.yml to have the lambda trigger when a SQS message is published: https://serverless.com/framework/docs/providers/aws/events/sqs/

I'm sorry I cannot provide more detailed help as there is a lot to do on this project and I have to split my time between client work and improving this project. I do plan on writing a guide in the future.

thiagomarini commented 5 years ago

Did you manage to get it to work with Laravel @pmayet ? I need to do the same thing...

incoming-th commented 5 years ago

We are a lot using Laravel here and playing with Bref.

If someone managed to make it works, it should be good to have a Wiki to explain how to do it.

There are lot of changes needed like for example the sessions, or the assets. If @mnapoli gives us a space to make a todo list, this will help to save our knowledge for other to get started faster.

I also did Laravel + Bref + Aurora Serverless and that's a pain as the AWS API Gateway timeout before the DB is running (from cold start). Best way is to have VueJS for frontend and Laravel as backend (less changes).

mnapoli commented 5 years ago

@MickaelTH the Lavarel docs should be the best place: https://github.com/mnapoli/bref/blob/master/docs/Laravel.md

thiagomarini commented 5 years ago

Just made it work, hacky as fuck but it does the job. Will do a proper solution when I have time.

Also created a migration guide based on my experience: https://medium.com/no-deploys-on-friday/migration-guide-serverless-bref-laravel-fbb513b4c54b

So basically the LaravelAdapter only understands HTTP requests, SQS events will endup on the simple handler:

$app = new \Bref\Application;
$app->simpleHandler(function (array $event) {
    // process $event
});
$app->run();

What I did was to boot the application, call the console with nothing just to make the container ready and have the global functions available so I could manually fire the serialised job from the SQS event body.

Everything can be done in the bref.php file, take a look:

<?php

define('LARAVEL_START', microtime(true));

require __DIR__.'/vendor/autoload.php';

$app = require_once __DIR__ . '/bootstrap/app.php';

// Laravel does not create that directory automatically so we have to create it
// You can remove this if you do not use views in your application (e.g. for an API)
if (!is_dir(storage_path('framework/views'))) {
    if (!mkdir(storage_path('framework/views'), 0755, true)) {
        throw new \RuntimeException('Cannot create directory ' . storage_path('framework/views'));
    }
}

$bref = new \Bref\Application;

$bref->httpHandler($app->getBrefHttpAdapter());

$non_http_events_handler = function (array $event) use ($app) {

    $statuses = [];

    /**
     * Get the kernel
     */
    $kernel = $app->make(\App\Console\Kernel::class);

    /**
     * Boot the kernel to make the container ready
     */
    $kernel->bootstrap();

    $container = resolve(\Psr\Container\ContainerInterface::class);

    /**
     * SQS events
     */
    foreach ($event['Records'] ?? [] as $record) {

        /**
         * Fire the job manually
         */
        $job = new \Illuminate\Queue\Jobs\SyncJob($container, $record['body'], 'sync', 'sync');

        $job->fire();

        $statuses[] = 1;
    }

    return [
        'statusCode' => 200,
        'headers'    => [
            'Content-Type'                     => 'application/json',
            'Access-Control-Allow-Origin'      => '*',
            'Access-Control-Allow-Credentials' => true,
        ],
        'body'       => ['message' => 'All good in the hood :)'],
        'status'     => $statuses,
    ];
};

$bref->simpleHandler($non_http_events_handler);

$bref->run();