Using Yii2 for Lambda Event Driven Approach

I have modified the framework directories and the required files from yii2 framework structure.

For example, I just need backend folder and it’s structure. I don’t need Yii2 Frontend Folder and common so I removed all unnecessary folders, and libraries from the composer.

I have developed the code and deployed successfully in lambda using https://bref.sh using web app approach.

I can call the lambda function using http gateway. However I am looking the solution for event driven approach.

To make the picture very clear.
Web App Approach:

  • Deployed code to lambda
  • Attached HTTP as event
  • Once serverless deploy successful it will give URL as a response.
  • Call the URL and function will be called.

Event Driven Approach:
I would like to call the lambda function when there is a message in SQS.
So for example:

  • Deployed code to lambda
  • Attach the lambda to SQS by using events and SQS ARN
  • so when there is a new message in SQS it will automatically call the lambda function.
Error I got while trigger the function using event test in lambda

Handler `/var/task/backend/web/index.php` must return a function or object handler. See https://bref.sh/docs/runtimes/function.html

Is there anyone who did this?

@samdark can you please provide some solution?

Seems like you needed basic template instead

1 Like

Have you looked at Yii event system?

1 Like

I’m not sure if this can be a solution, but as I can see you are having issue case of passing index.php as “handler”

Handler /var/task/backend/web/index.php must return a function or object handler

May be you can specify other handler, some console controller action? And this action will return correct response as a “handler”

2 Likes

@Brezgalov @evstevemd Thanks for the recommendation. However, I am unable to get the solution.

Here I am attaching the code:

backend/web/index.php

<?php

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require __DIR__ . '/../../vendor/autoload.php';
require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
require __DIR__ . '/../config/bootstrap.php';

$config = require __DIR__ . '/../config/main.php';

(new yii\web\Application($config))->run();

/backend/config/main.php

<?php
$params = array_merge(
    require __DIR__ . '/params.php',
);

return [
    'id' => 'app-backend',
    'basePath' => dirname(__DIR__),
    'controllerNamespace' => 'backend\controllers',
    'bootstrap' => ['log'],
    'modules' => [],
    'aliases' => [
        '@bower' => '@vendor/bower-asset',
        '@npm'   => '@vendor/npm-asset',
    ],
    'vendorPath' => dirname(__DIR__, 2) . '/vendor',
    'components' => [
        'request' => [
            'csrfParam' => '_csrf-backend',
            'cookieValidationKey' => '1NSfZdOn2doGFzKe9JJiXdpjDF5qQ1NO',
        ],
        'cache' => [
            'class' => \yii\caching\FileCache::class,
        ],
        'session' => [
            // this is the name of the session cookie used for login on the backend
            'name' => 'advanced-backend',
        ],
        'errorHandler' => [
            'errorAction' => 'site/error',
        ],
        /*
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'rules' => [
            ],
        ],
        */
    ],
    'params' => $params
];

/backend/controllers/SiteController.php

<?php

namespace backend\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
    public function actionIndex()
    {
        echo "Welcome Here";
        exit;
    }

    public function actions()
    {
        return [
            'error' => [
                'class' => \yii\web\ErrorAction::class,
            ],
        ];
    }    
}

backend/components/SqsHandlerClass.php

<?php
namespace backend\components;

use Bref\Context\Context;
use Bref\Event\Handler;
use yii\base\Component;

class SqsHandlerClass extends Component implements Handler
{
	public function handle($event, Context $context)
	{
		echo "<pre>"; print_r(json_encode($event)); echo "</pre>"; exit;
	}
}

As per the instruction given on the official bref.sh website

However, Bref also provides classes specific to each Lambda event for a better development experience.

<?php

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

use Bref\Context\Context;

class Handler implements \Bref\Event\Handler
{
    public function handle($event, Context $context)
    {
        return 'Hello ' . $event['name'];
    }
}

return new Handler();

When lambda is triggered by SQS, how can I call the SqsHandlerClass handle method with given parameters?

I missed Bref thing. I will find time to checkout Bref and see if I can recommend something!

2 Likes

Looking forward to it.

Once we get the solution, I will publish the entire solution to make Yii2 comfortable with AWS Lambda.

1 Like

Meanwhile Quick search found this. You can use Google translate to understand it and be starting point

@evstevemd Correct.

The solution given here is BREF FOR WEB APPS solution. How ever we are looking for BREF FOR EVENT-DRIVEN FUNCTIONS

using HTTP we can do this.

@samdark @softark

Hi @sahil.r2050

I’m sorry but I don’t have experience with AWS Lambda. You know it better than I do.
I’ll be watching this thread and hope you get the solution.

I once use lambda with cloudwatch as a trigger, when cloudwatch triggered will access the lambda endpoint and run Yii2. So its not call directly to php. This is my writing Serverless Yii2 - Menggunakan Yii2 pada AWS Lambda - BelajarArief to make it works.

Guys, The excellent news is I have made it possible with Yii2.

All I need is your guidance, whether structure-wise or security-wise, whether it is good or not. I will soon upload the new code here.

3 Likes

As per the serverless documentation, handling Lambda events via an anonymous function is the most straightforward approach: However, in Yii2, the application starting point calls the method ->run() in the index.php file.

Modified file /backend/index.php

<?php

use backend\components\HandlerComponents;

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require __DIR__ . '/../../vendor/autoload.php';
require __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
require __DIR__ . '/../config/bootstrap.php';

$config = require __DIR__ . '/../config/main.php';

//I made a change here. Removed RUN method.
new yii\web\Application($config);

// Calling Handler Method from Yii2 Component file.
return new HandlerComponents();

Handler Code:

<?php

namespace backend\components;

Class HandlerComponents extends SqsHandler
{
	/**
	 * @throws InvalidConfigException
	 * @throws Exception
	 * @throws JsonException
	 */
	public function handleSqs(SqsEvent $event, Context $context): void
	{
		// Application code with Yii2 helpers etc.
	}
}

return new HandlerComponents();

So with this, I can say that all the configurations, models, components, and helpers can be used while converting the existing code to comply with Serverless Lambda.

Now please mention all the limitations or issues that can be faced as we do not call the RUN method.

1 Like