I'm using laravel 8 and bref to deploy it on lambda. After making a cron job function to send email. When I deploy it, there's a problem with the facade
{
"errorType": "RuntimeException",
"errorMessage": "A facade root has not been set.",
"stackTrace": [
"#0 /var/task/app/functions/sendTestMail.php(11): Illuminate\\Support\\Facades\\Facade::__callStatic()",
"#1 /var/task/vendor/bref/bref/src/Runtime/Invoker.php(34): Bref\\Runtime\\FileHandlerLocator->App\\Functions\\{closure}()",
"#2 /var/task/vendor/bref/bref/src/Runtime/LambdaRuntime.php(102): Bref\\Runtime\\Invoker->invoke()",
"#3 /opt/bref/bootstrap.php(43): Bref\\Runtime\\LambdaRuntime->processNextEvent()",
"#4 {main}"
]
}
here is my directory structure and the function:
sendTestMail.php
serverless.yml:
service: test
provider:
name: aws
# The AWS region in which to deploy (us-east-1 is the default)
region: ap-southeast-1
# The stage of the application, e.g. dev, production, staging… ('dev' is the default)
stage: dev
runtime: provided.al2
package:
# Directories to exclude from deployment
exclude:
- node_modules/**
- public/storage
- resources/assets/**
- storage/**
- tests/**
functions:
# This function runs the Laravel website/API
web:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-80-fpm}
events:
- httpApi: "*"
# This function lets us run artisan commands in Lambda
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-80} # PHP
- ${bref:layer.console} # The "console" layer
cron:
handler: app/functions/sendTestMail.php
layers:
- ${bref:layer.php-80}
events:
- schedule: rate(5 minutes)
plugins:
# We need to include the Bref plugin
- ./vendor/bref/bref
Anyone know how to resolve this issue? And btw, how can I test a handler function on my local machine before deploying? Thank you
I believe this is due to the issue that in your web function the handler is public/index.php. This properly initializes the Laravel application. Your cron functions handler is app/functions/sendTestMail.php so index.php never gets called and the Laravel kernel never handles the request.
I don't have a great solution at the moment because I feel like it is breaking a lot of best practices and rules in Laravel and want to experiment more with it. But I was able to take the entire index.php content and pasted it above my return function in the file that Lambda was calling.
So in other words I think if you paste this
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
use App\Models\Task;
define('LARAVEL_START', microtime(true));
if (file_exists(__DIR__.'/storage/framework/maintenance.php')) {
require __DIR__.'/storage/framework/maintenance.php';
}
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$response = tap($kernel->handle(
$request = Request::capture()
))->send();
$kernel->terminate($request, $response);
As the first thing in your app/functions/sendTestMail.php file, it will likely work. Depending on what you have coded in your Middleware as that will run first.
This worked for me in my application.
You can try this for the error
php artisan config:cache
php artisan config:clear
php artisan cache:clear
Related
Hello I have a laravel app with serverless architecture. I'm getting an error:
cURL error 28: Failed to connect to fnhxdorrd22l.execute-api.ap-southeast-1.amazonaws.com port 443 after 7502 ms: Connection timed out (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://fnhxdorrdl22.execute-api.ap-southeast-1.amazonaws.com/oauth/token
Is there any configuration need for this or any inbound rules in order to call a function inside a function? BTW, it's working if it's a simple call or request without any call or trigger to other route or third parties.
Serverless.yml
service: laravel
provider:
name: aws
# The AWS region in which to deploy (us-east-1 is the default)
region: ap-southeast-1
# The stage of the application, e.g. dev, production, staging… ('dev' is the default)
stage: dev
profile: serverless
runtime: provided.al2
lambdaHashingVersion: 20201222321
package:
# Directories to exclude from deployment
patterns:
- '!node_modules/**'
- '!public/storage'
- '!resources/assets/**'
- '!storage/**'
- '!tests/**'
- 'storage/oauth-private.key'
- 'storage/oauth-public.key'
functions:
# This function runs the Laravel website/API
web:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
vpc:
securityGroupIds:
- sg-042d6942052649ad59b0bc0
subnetIds:
- subnet-2c1464319824244
- subnet-474851e914424e4
- subnet-4424429f48129d7
layers:
- ${bref:layer.php-80-fpm}
events:
- httpApi: '*'
# This function lets us run artisan commands in Lambda
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-80} # PHP
- ${bref:layer.console} # The "console" layer
A Lambda function configured to run in a VPC does not get a public IP address ever (regardless of the VPC public IP settings). The API Gateway URL is a public URL on the Internet. That API Gateway URL doesn't exist inside the VPC. In order for the Lambda function to make a connection to that URL the function has to be configured to run in a private VPC subnet that has a route to a NAT Gateway.
When using Intervention\Image in laravel on lambda
The following error has occurred.
By the way, it works in the local environment.
I have to add gd.
[2021-08-17 10:37:18] DEV.ERROR: GD Library extension not available with this PHP installation.
{"exception":"[object] (Intervention\Image\Exception\NotSupportedException(code: 0):
GD Library extension not available with this PHP installation.
at /var/task/vendor/intervention/image/src/Intervention/Image/Gd/Driver.php:19)
What I looked up
https://bref.sh/docs/environment/php.html#extensions
https://github.com/brefphp/extra-php-extensions
Deployment method
We are deploying to lambda using the sls command.
sls deploy --stage dev
Based on the investigation, the following is implemented
composer require bref/extra-php-extensions
Added below
serverless.yml
plugins:
- ./vendor/bref/bref
- ./vendor/bref/extra-php-extensions #add
functions:
# This function runs the Laravel website/API
web:
image:
name: laravel
events:
- httpApi: '*'
# This function lets us run artisan commands in Lambda
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-80}
- ${bref:layer.console}
- ${bref-extra:gd-php-80} #add
Even if the above settings are added and deployed, they are not updated. .. why?
enviroment
Laravel Framework 8.33.1
PHP 7.4.3
bref
serverless
I'm sorry if English is strange.
Put the layers into web "tag".
plugins:
- ./vendor/bref/bref
- ./vendor/bref/extra-php-extensions #add
functions:
# This function runs the Laravel website/API
web:
image:
name: laravel
layers:
- ${bref-extra:gd-php-80} #add
events:
- httpApi: '*'
# This function lets us run artisan commands in Lambda
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-80}
- ${bref:layer.console}
Then add the folder php/conf.d inside put a file with extension .ini. For example php.ini. In it just put:
extension=gd
I am investigating on how I can create an AWS lambda in php using the bref library
Therefore, according to documentation I set up the environment with the following command cocktail:
sudo -H npm install -g serverless
composer require bref/bref
Then using the following command created my first php lambda:
vendor/bin/bref init
And I selected the first option PHP Function provided by default. Creating the following creating an index.php file:
declare(strict_types=1);
require __DIR__.'/vendor/autoload.php';
lambda(function ($event) {
return 'Hello ' . ($event['name'] ?? 'world');
});
Then I changed my serverless.yml into that:
service: app
provider:
name: aws
region: eu-central-1
runtime: provided
stage: ${opt:stage,'local'}
package:
exclude:
- '.gitignore'
plugins:
- ./vendor/bref/bref
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- ${bref:layer.php-73}
And I try to launch it via the following command:
sls invoke local --stage=local --docker --function dummy
But I get the following error:
{"errorType":"exitError","errorMessage":"RequestId: 6403ebee-13b6-179f-78cb-41cb2f517460 Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]"}
Therefore, I want to ask why I am unable to run my lambda localy?
Since this question is getting a lot of views, I recommend to have a look at the Bref documentation:
Local development for PHP functions
That involves using the bref local CLI command instead of serverless invoke local:
$ vendor/bin/bref local hello
Hello world
# With JSON event data
$ vendor/bin/bref local hello '{"name": "Jane"}'
Hello Jane
# With JSON in a file
$ vendor/bin/bref local hello --file=event.json
Hello Jane
On my local, clearing cache before invoking lambda worked fine, I'm using linux / ubuntu
docker system prune --all
sudo apt-get autoremove
sudo apt-get clean
sudo apt-get autoclean
sudo rm -rf ~/.cache/
sudo rm -rf /var/cache/
It is a known bug for bref. It can be solved via providing the layer manually on your function in serverless.yml. So the functions section at serverless.yml should change from:
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- ${bref:layer.php-73}
Into:
functions:
dummy:
handler: index.php
name: Dummy-${self:provider.stage}
description: 'Dummy Lambda'
layers:
- 'arn:aws:lambda:eu-central-1:209497400698:layer:php-73:15'
The reason why is that ${bref:layer.php-73} cannot be resolved into a php layer. Therefore, you need to provide manually the arn for the lambda layer.
Keep in mind that the arn comes into various "versions" that is being inidcated from the last number in the arn seperated with :. So in the arn
arn:aws:lambda:eu-central-1:209497400698:layer:php-73:15
Indicated that the layer is in version "15" whitch is thje latest at the moment of the answer. The next one logically should be the:
arn:aws:lambda:eu-central-1:209497400698:layer:php-73:16
I created a new Symfony 4 project via symfony new my_project_name.
Currently when I execute ./bin/console, the output shows
I will create some custom console commands and I want show only my custom commands when I do ./bin/console
Maybe I should create a custom executable 'console' from scratch, but I don't know how do that.
You are creating a complete Symfony application, so all the commands provided by the included packages are available.
Instead of starting from a framework and trying to trim down the parts you do not want, you need to start from further down to have a really barebones project.
Bootstrapping the project:
First, do not use symfony command, no need. Plain old composer will do the trick.
On an empty directory, execute:
composer require symfony/console
This will import the only dependency needed for a console project, and do the basic bootstrapping for your autoloader.
In composer.json, add the following:
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
Command class
You'll need one or more commands to actually add to your application. Let's start with a fully fledged greeting application. Create the file src/Greet.php within your project:
declare(strict_types=1);
namespace App;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Greet extends Symfony\Component\Console\Command\Command
{
protected function configure()
{
$this->addArgument('person', InputArgument::OPTIONAL, 'Name of the Entity being greeted', 'World');
$this->addOption('greeting', 'g', InputOption::VALUE_OPTIONAL, 'How to greet the entity', 'Hello');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$greeting = $input->getOption('greeting');
$entity = $input->getArgument('person');
$output->writeln("<info>$greeting $entity!</info>");
}
}
This is a basic command that will print "Hello World!" if executed without any option or argument, will accept one argument use instead of "World", and one option to set the greeting instead of "Hello".
Console Application
On the project's root, create a file app.php.
require __DIR__ . '/vendor/autoload.php';
$app = new Symfony\Component\Console\Application('Hello World App', '1.0.0');
$app->add((new App\Greet('greet')));
$app->run();
This is be a very short script, so let's go line by line
Require the autoloader. This script is the entry point for the application, so we need to execute the autoloader.
Instantiate the application. This creates a new instance of the Symfony Console application, sets a name and version for the app. This will be used in the "help" printouts for the app.
Add the command. By default, the application has no commands at all. We'll need to add the command we have just created. add() expects a Command instance. We instantiate the command we just created, and we set it to be called by the name "greet".
Run the application
Generate autoloader.
Execute composer dump-autoload so the autoloader for your application is generated.
Execute the script.
If you now execute php app.php you'll get:
Hello World App 1.0.0
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Available commands:
greet
help Displays help for a command
list Lists commands
Note that the only available command is greet. Which you can use like this:
# php app.php greet
Hello World!
# php app.php greet Alice
Hello Alice!
# php app.php greet Bob -g "Good morning"
Good morning Bob!
# php app.php help greet
Usage:
greet [options] [--] [<person>]
Arguments:
person Name of the Entity being greeted [default: "World"]
Options:
-g, --greeting[=GREETING] How to greet the entity [default: "Hello"]
[... default generic options omitted]
I'm a newbie at Symfony and working on it Symfony documentations. At the lucky number sample(https://symfony.com/doc/current/page_creation.html)
My luckycontroller.php is:
<?php
// src/Controller/LuckyController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
class LuckyController
{
public function number()
{
$number = mt_rand(0, 100);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
in my routes.yaml file:
app_lucky_number:
path: /lucky/number
controller: App\Controller\LuckyController::number
I've looked for routes on the console:
it shows app_lucky_number route
Then I'm going http://127.0.0.1/projects/todolist/public/lucky/number it gives 404 error.
I didn't understand what did I do wrong. I installed Symfony by using composer.
From https://symfony.com/doc/current/page_creation.html:
Before continuing, make sure you've read the Setup article and can
access your new Symfony app in the browser.
To quickly test Symfony without configuring Apache you can go to your project directory and run this in your terminal:
php bin/console server:start 0.0.0.0:8000
then you should be able to access your new controller using this URI http://localhost:8000/lucky/number
To configure Apache server use this link https://symfony.com/doc/current/setup/web_server_configuration.html