diff --git a/.github/aws/github-role.yml b/.github/aws/github-role.yml
index 6f7be1e06..cd86e9c4e 100644
--- a/.github/aws/github-role.yml
+++ b/.github/aws/github-role.yml
@@ -15,12 +15,12 @@ Resources:
- Effect: Allow
Action: sts:AssumeRoleWithWebIdentity
Principal:
- Federated: arn:aws:iam::534081306603:oidc-provider/token.actions.githubusercontent.com
+ Federated: arn:aws:iam::873528684822:oidc-provider/token.actions.githubusercontent.com
Condition:
StringLike:
token.actions.githubusercontent.com:sub: !Sub repo:${FullRepoName}:*
Policies:
- - PolicyName: RetrieveLayersForLayerJsRole
+ - PolicyName: RetrieveLayersForLayerRole
PolicyDocument:
Statement:
- Effect: Allow
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 35759b8e1..d04ad459e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,7 +2,7 @@ name: CI
on:
push:
- branches: ['master']
+ branches: ['master', 'v3']
pull_request:
branches: ['*']
schedule:
@@ -16,11 +16,11 @@ jobs:
timeout-minutes: 15
strategy:
matrix:
- php: [ '8.4', '8.3', '8.2', '8.1', '8.0' ]
+ php: [ '8.5', '8.4', '8.3', '8.2' ]
dependency-version: [ '' ]
platform-reqs: [ '' ]
include:
- - php: '8.0'
+ - php: '8.2'
dependency-version: '--prefer-lowest'
steps:
- name: Checkout
@@ -40,7 +40,7 @@ jobs:
coverage: none
ini-values: expose_php=1
- name: Install dependencies
- run: 'composer update ${{ matrix.dependency-version }} --no-interaction --prefer-dist --no-progress --no-security-blocking ${{ matrix.platform-reqs }}'
+ run: 'composer update ${{ matrix.dependency-version }} --no-interaction --prefer-dist --no-progress ${{ matrix.platform-reqs }}'
- name: Execute Unit Tests
run: 'vendor/bin/phpunit --testsuite small'
diff --git a/.github/workflows/update-layer-versions.yml b/.github/workflows/update-layer-versions.yml
index eb5ebadcc..a3618df7b 100644
--- a/.github/workflows/update-layer-versions.yml
+++ b/.github/workflows/update-layer-versions.yml
@@ -1,4 +1,4 @@
-name: Update layer versions (Bref v2)
+name: Update layer versions
# Triggered manually or automatically when new Bref layers published
on:
@@ -26,12 +26,12 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
- ref: master
+ ref: v3 # temporary until v3 becomes the main branch
- name: Set AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
- role-to-assume: arn:aws:iam::534081306603:role/bref-github-actions
+ role-to-assume: arn:aws:iam::873528684822:role/bref-github-actions
role-session-name: bref-github-actions
aws-region: us-east-1
@@ -47,10 +47,10 @@ jobs:
- run: make layers.json
- name: Create Pull Request
- uses: peter-evans/create-pull-request@v5
+ uses: peter-evans/create-pull-request@v7
with:
commit-message: Update layer versions
- title: Update Lambda layers [${{ inputs.release_name }}](${{ inputs.release_html_url }})
+ title: Update v3 layers [${{ inputs.release_name }}](${{ inputs.release_html_url }})
body: |
New AWS Lambda layers [have been released](https://github.com/brefphp/aws-lambda-layers/releases):
@@ -60,8 +60,6 @@ jobs:
After merging, a new Bref release needs to be created.
If you are using AWS Lambda layer ARNs, check out [runtimes.bref.sh](https://runtimes.bref.sh/) to see the latest ARNs.
- branch: new-layer-versions
+ branch: new-layer-versions-v3
+ base: v3 # temporary until v3 becomes the main branch
delete-branch: true # delete after merging or closing the PR
- # https://github.com/actions/checkout/issues/13#issuecomment-724415212
- committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
diff --git a/.phpcs.xml b/.phpcs.xml
index 7b6fa93b6..fcb99ca4b 100644
--- a/.phpcs.xml
+++ b/.phpcs.xml
@@ -7,7 +7,6 @@
- brefsrctests
diff --git a/bref b/bref
deleted file mode 100755
index 75a438b55..000000000
--- a/bref
+++ /dev/null
@@ -1,132 +0,0 @@
-#!/usr/bin/env php
- 'vendor/bin/bref',
- 'v' => 2, // Bref version
- 'c' => $argv[1] ?? '',
- 'ci' => $ci,
- // anonymous user ID created by the Serverless Framework
- 'uid' => $userConfig['frameworkId'] ?? '',
- ], JSON_THROW_ON_ERROR);
-
- $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
- // This IP address is the Bref server.
- // If this server is down or unreachable, there should be no difference in overhead
- // or execution time.
- socket_sendto($sock, $message, strlen($message), 0, '108.128.197.71', 8888);
- socket_close($sock);
-}
diff --git a/composer.json b/composer.json
index 492b0ee75..5c497701b 100644
--- a/composer.json
+++ b/composer.json
@@ -16,11 +16,10 @@
}
},
"bin": [
- "bref",
"src/bref-local"
],
"require": {
- "php": ">=8.0",
+ "php": ">=8.2",
"ext-curl": "*",
"ext-json": "*",
"crwlr/query-string": "^1.0.3",
@@ -30,7 +29,7 @@
"psr/http-message": "^1.0|^2.0",
"psr/http-server-handler": "^1.0",
"riverline/multipart-parser": "^2.1.2",
- "symfony/process": "^4.4|^5.0|^6.0|^7.0|^8.0"
+ "symfony/process": "^5.4|^6.4|^7.0|^8.0"
},
"require-dev": {
"async-aws/core": "^1.0",
@@ -42,8 +41,8 @@
"guzzlehttp/guzzle": "^7.5",
"phpstan/phpstan": "^1.10.26",
"phpunit/phpunit": "^9.6.10",
- "symfony/console": "^4.4|^5.0|^6.0|^7.0|^8.0",
- "symfony/yaml": "^4.4|^5.0|^6.0|^7.0|^8.0"
+ "symfony/console": "^5.4|^6.4|^7.0|^8.0",
+ "symfony/yaml": "^5.4|^6.4|^7.0|^8.0"
},
"scripts": {
"test": [
diff --git a/demo/http.php b/demo/http.php
index 8b5c6b9d5..8860885f6 100644
--- a/demo/http.php
+++ b/demo/http.php
@@ -2,6 +2,10 @@
require __DIR__ . '/../vendor/autoload.php';
+if (isset($_GET['crash'])) {
+ throw new \Exception('Crash!');
+}
+
if (isset($_GET['sleep'])) {
error_log('This is a log');
sleep(10);
diff --git a/docs/default/cli-commands.mdx b/docs/default/cli-commands.mdx
index 8fbcc3bab..45a5baf88 100644
--- a/docs/default/cli-commands.mdx
+++ b/docs/default/cli-commands.mdx
@@ -8,7 +8,7 @@ We can run CLI commands and scripts on AWS Lambda by deploying a "console" funct
functions:
cli:
handler: the-php-script-to-run.php
- runtime: php-81-console
+ runtime: php-84-console
```
The function uses the [Console runtime](../runtimes/console.mdx).
diff --git a/docs/default/getting-started.mdx b/docs/default/getting-started.mdx
index 5551e8641..796f1ea8e 100644
--- a/docs/default/getting-started.mdx
+++ b/docs/default/getting-started.mdx
@@ -27,33 +27,29 @@ Next, in an empty directory, install Bref using Composer:
composer require bref/bref
```
-Make sure that the version of Bref that was installed is 1.0 or greater.
+Make sure that the version of Bref that was installed is 3.0 or greater.
-Then let's start by initializing a new project by running:
+Then, create a `serverless.yml` file. This file will describe how to deploy your application.
-```bash
-vendor/bin/bref init
-```
-
-Accept all the defaults by pressing "Enter". The following files will be created in your project:
-
-- `index.php` contains the code of your application
-- `serverless.yml` contains the configuration for deploying on AWS
-
-You are free to edit `index.php`.
+```yml filename="serverless.yml"
+service: app # your application name (lowercase without spaces)
-To deploy an existing application, you can delete `index.php` and edit `serverless.yml` to point to your existing index file (for example it may be another file like `public/index.php`). You can also create the `serverless.yml` file manually:
+bref:
+ # Uncomment and set your team ID if you are using Bref Cloud
+ #team: bref-team-id
-```yml filename="serverless.yml"
-service: app
provider:
name: aws
- region: us-east-1
+ region: us-east-1 # AWS region to deploy to
+ environment: # Environment variables
+ APP_ENV: prod
functions:
web:
+ # `index.php` is the entrypoint of your application
handler: index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
+ timeout: 28 # in seconds (API Gateway has a max timeout of 29 seconds)
events:
- httpApi: '*'
@@ -66,6 +62,21 @@ plugins:
- ./vendor/bref/bref
```
+If your `index.php` entrypoint is in a different folder, feel free to adjust the `handler` key. For example if it is in `public/index.php`:
+
+```yml
+ handler: public/index.php
+```
+
+If this is a new application, you can create a very simple `index.php` file to test things out, for example:
+
+```php
+
Always specify the major version of the Bref image you want to use. That avoids breaking changes when a new major version is released.
- For example `bref/php-81-fpm:2` points to Bref v2.
+ For example `bref/php-84:3` points to Bref v3.
-Bref offers the following base images:
+The `ENV BREF_RUNTIME=fpm` let's us specify which [runtime](../runtimes.mdx) to use. As a reminder, Bref offers the following runtimes:
-- `bref/php-xx-fpm:2`: PHP-FPM to run HTTP applications
-- `bref/php-xx-console:2`: to run PHP CLI commands
-- `bref/php-xx:2`: to run [PHP functions](../runtimes/function.mdx)
+- `fpm`: [uses PHP-FPM to serve web applications](../runtimes/fpm-runtime.mdx)
+- `function`: [to run PHP code](../runtimes/function.mdx)
+- `console`: [to run CLI commands](../runtimes/console.mdx)
The `CMD` instruction in `Dockerfile` must contain a valid JSON array. This is why you must escape any `\` character. This is important for PHP class names, for example when using Laravel Octane:
@@ -65,10 +68,10 @@ Bref offers the following base images:
You can enable additional PHP extensions by pulling them from [Bref Extra Extensions](https://github.com/brefphp/extra-php-extensions):
```dockerfile filename="Dockerfile" {3-4}
-FROM bref/php-81-fpm:2
+FROM bref/php-84:3
-COPY --from=bref/extra-redis-php-81:1 /opt /opt
-COPY --from=bref/extra-gmp-php-81:1 /opt /opt
+COPY --from=bref/extra-redis-php-84:3 /opt /opt
+COPY --from=bref/extra-gmp-php-84:3 /opt /opt
COPY . /var/task
@@ -76,9 +79,9 @@ CMD ["public/index.php"]
```
- Like the Bref images, always specify the major version of the Bref Extra Extensions images: `bref/extra-*:1` points to Bref Extra Extensions v1.
+ Like the Bref images, always specify the major version of the Bref Extra Extensions images: `bref/extra-*:3` points to Bref Extra Extensions v3.
- Note that Bref v2 is compatible with Bref Extra Extensions v1 (yes that's confusing, sorry about that, we will fix that in Bref v3 to have matching versions).
+ Note that Bref v3 is compatible with Bref Extra Extensions v3.
## Deployment
@@ -126,6 +129,6 @@ The `/tmp` folder will always be empty on cold starts. Avoid writing content to
## Docker Registry
-AWS Lambda only support AWS ECR as the source location for Docker images.
+AWS Lambda only supports AWS ECR as the source location for Docker images.
AWS Lambda will use the image digest as the unique identifier. This means that even if you overwrite the exact same tag on ECR, your lambda will still run the previous image code until you actually redeploy using the new image.
diff --git a/docs/environment/php.mdx b/docs/environment/php.mdx
index fabb6b2ad..3c2295656 100644
--- a/docs/environment/php.mdx
+++ b/docs/environment/php.mdx
@@ -73,6 +73,7 @@ The following extensions are installed and enabled by default in Bref runtimes:
@@ -98,14 +99,16 @@ The following extensions are installed in Bref runtimes, but disabled by default
- **[intl](https://www.php.net/manual/en/intro.intl.php)** - Internationalization extension (referred as Intl) is a wrapper for ICU library, enabling PHP programmers to perform various locale-aware operations.
- **[APCu](https://www.php.net/manual/en/intro.apcu.php)** - APCu is APC stripped of opcode caching.
-- **[PostgreSQL PDO Driver](https://www.php.net/manual/en/ref.pdo-pgsql.php)** - PDO_PGSQL is a driver that implements the PHP Data Objects (PDO) interface to enable access from PHP to PostgreSQL databases.
+- **[Redis](https://github.com/phpredis/phpredis)** - A PHP extension for interfacing with Redis.
+- **[soap](https://www.php.net/manual/en/book.soap.php)** - SOAP client and server for PHP
You can enable these extensions by loading them in `php/conf.d/php.ini` (as mentioned in [the section above](#phpini)), for example:
```ini filename="php/conf.d/php.ini"
extension=intl
extension=apcu
-extension=pdo_pgsql
+extension=redis
+extension=soap
```
### Extra extensions
@@ -133,7 +136,7 @@ To create your custom layer, you will need to:
To compile the extension, Bref provides the `bref/build-php-*` Docker images. Here is an example with Blackfire:
```dockerfile
-FROM bref/build-php-80:2
+FROM bref/build-php-84:2
RUN curl -A "Docker" -o /tmp/blackfire.so -L -s "https://packages.blackfire.io/binaries/blackfire-php/1.42.0/blackfire-php-linux_amd64-php-74.so"
diff --git a/docs/environment/serverless-yml.mdx b/docs/environment/serverless-yml.mdx
index 18815399c..35934e5df 100644
--- a/docs/environment/serverless-yml.mdx
+++ b/docs/environment/serverless-yml.mdx
@@ -22,7 +22,7 @@ plugins:
functions:
foo:
handler: index.php
- runtime: php-81
+ runtime: php-84
resources:
Resources:
@@ -65,7 +65,7 @@ The `provider` section also lets us configure global options on all functions:
```yaml
provider:
name: aws
- runtime: php-81
+ runtime: php-84
timeout: 10
functions:
@@ -86,11 +86,11 @@ provider:
functions:
foo:
handler: foo.php
- runtime: php-81
+ runtime: php-84
timeout: 10
bar:
handler: bar.php
- runtime: php-81
+ runtime: php-84
timeout: 10
# ...
@@ -136,10 +136,10 @@ Read more about the `package` configuration [in the serverless.yml documentation
functions:
foo:
handler: foo.php
- runtime: php-81
+ runtime: php-84
bar:
handler: bar.php
- runtime: php-81
+ runtime: php-84
```
Functions are AWS Lambda functions. You can find all options available [in this Serverless documentation page](https://serverless.com/framework/docs/providers/aws/guide/functions/).
diff --git a/docs/laravel/octane.mdx b/docs/laravel/octane.mdx
index 5c83008c5..89e71368d 100644
--- a/docs/laravel/octane.mdx
+++ b/docs/laravel/octane.mdx
@@ -11,7 +11,7 @@ To run the HTTP application with [Laravel Octane](https://laravel.com/docs/10.x/
functions:
web:
handler: Bref\LaravelBridge\Http\OctaneHandler
- runtime: php-81
+ runtime: php-84
environment:
BREF_LOOP_MAX: 250
# ...
@@ -40,7 +40,7 @@ You can keep database connections persistent across requests to make your applic
functions:
web:
handler: Bref\LaravelBridge\Http\OctaneHandler
- runtime: php-81
+ runtime: php-84
environment:
BREF_LOOP_MAX: 250
OCTANE_PERSIST_DATABASE_SESSIONS: 1
diff --git a/docs/laravel/queues.mdx b/docs/laravel/queues.mdx
index 098882689..480fc41fb 100644
--- a/docs/laravel/queues.mdx
+++ b/docs/laravel/queues.mdx
@@ -39,7 +39,7 @@ constructs:
type: queue
worker:
handler: Bref\LaravelBridge\Queue\QueueHandler
- runtime: php-81
+ runtime: php-84
timeout: 60 # seconds
```
diff --git a/docs/local-development.mdx b/docs/local-development.mdx
index ceacbf6a0..aee7bc96a 100644
--- a/docs/local-development.mdx
+++ b/docs/local-development.mdx
@@ -42,7 +42,7 @@ version: "3.5"
services:
app:
- image: bref/php-81-fpm-dev:2
+ image: bref/php-84-dev:3
ports: [ '8000:8000' ]
volumes:
- .:/var/task
@@ -62,7 +62,7 @@ The application will be available at [http://localhost:8000/](http://localhost:8
The `HANDLER` environment variable lets you define which PHP file will be handling all HTTP requests. This should be the same handler that you have defined in `serverless.yml` for your HTTP function.
-> Currently, the Docker image support only one PHP handler. If you have multiple HTTP functions in `serverless.yml`, you can duplicate the service in `docker-compose.yml` to have one container per lambda function.
+> Currently, the Docker image supports only one PHP handler. If you have multiple HTTP functions in `serverless.yml`, you can duplicate the service in `docker-compose.yml` to have one container per lambda function.
### Read-only filesystem
diff --git a/docs/local-development/event-driven-functions.mdx b/docs/local-development/event-driven-functions.mdx
index d7464c3ef..58e4249b1 100644
--- a/docs/local-development/event-driven-functions.mdx
+++ b/docs/local-development/event-driven-functions.mdx
@@ -30,7 +30,7 @@ return function (array $event) {
functions:
hello:
handler: my-function.php
- runtime: php-81
+ runtime: php-84
```
You can invoke it with or without event data:
@@ -86,10 +86,10 @@ Hello Alex
If you want to run your function in Docker:
```bash
-$ docker run --rm -it --entrypoint= -v $(PWD):/var/task:ro bref/php-81:2 vendor/bin/bref-local my-function.php
+$ docker run --rm -it --entrypoint= -v $(PWD):/var/task:ro bref/php-84:3 vendor/bin/bref-local my-function.php
-# You can also use the `dev` images for a simpler command (and Xdebug and Blackfire in the image):
-$ docker run --rm -it -v $(PWD):/var/task:ro bref/php-81-fpm-dev:2 vendor/bin/bref-local my-function.php
+# You can also use the `dev` images for a simpler command (and Xdebug in the image):
+$ docker run --rm -it -v $(PWD):/var/task:ro bref/php-84-dev:3 vendor/bin/bref-local my-function.php
```
You can also use Docker Compose, like described in [Local development for HTTP applications](../local-development.mdx):
@@ -98,7 +98,7 @@ You can also use Docker Compose, like described in [Local development for HTTP a
version: "3.5"
services:
app:
- image: bref/php-81-fpm-dev:2
+ image: bref/php-84-dev:3
volumes:
- .:/var/task
```
diff --git a/docs/monitoring.md b/docs/monitoring.md
index 1c4614b83..641bed766 100644
--- a/docs/monitoring.md
+++ b/docs/monitoring.md
@@ -97,9 +97,9 @@ functions:
my-function:
handler: index.php
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
# Add this line:
- - ${bref-extra:tideways-php-81}
+ - ${bref-extra:tideways-php-84}
```
> Make sure to use the same PHP version as the one for the PHP layer.
diff --git a/docs/runtimes.mdx b/docs/runtimes.mdx
index 095b2ea3c..59fdae1c8 100644
--- a/docs/runtimes.mdx
+++ b/docs/runtimes.mdx
@@ -23,7 +23,7 @@ The runtimes are available as AWS Lambda layers that you can use (explained belo
### PHP-FPM runtime for web apps
-Name: `php-84-fpm`, `php-83-fpm`, `php-82-fpm`, `php-81-fpm`, and `php-80-fpm`.
+Name: `php-85-fpm`, `php-84-fpm`, `php-83-fpm`, and `php-82-fpm`.
This runtime uses PHP-FPM to run **web applications** on AWS Lambda, like on a traditional server.
@@ -33,7 +33,7 @@ It's **the easiest to start with**: it works like traditional PHP hosting and is
### Event-driven functions
-Name: `php-84`, `php-83`, `php-82`, `php-81`, and `php-80`.
+Name: `php-85`, `php-84`, `php-83`, and `php-82`.
AWS Lambda was initially created to run _functions_ (yes, functions of code) in the cloud.
@@ -49,7 +49,7 @@ This runtime works great to create **event-driven micro-services**.
### Console
-Name: `php-84-console`, `php-83-console`, `php-82-console`, `php-81-console`, and `php-80-console`.
+Name: `php-85-console`, `php-84-console`, `php-83-console`, and `php-82-console`.
This runtime lets you run CLI console commands on Lambda.
@@ -70,33 +70,30 @@ plugins:
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
# or:
- runtime: php-81-fpm
+ runtime: php-84-fpm
# or:
- runtime: php-81-console
+ runtime: php-84-console
```
-Bref currently provides runtimes for PHP 8.0, 8.1, 8.2, 8.3 and 8.4:
+Bref currently provides runtimes for PHP 8.2, 8.3, 8.4, and 8.5:
+- `php-85`
- `php-84`
- `php-83`
- `php-82`
-- `php-81`
-- `php-80`
+- `php-85-fpm`
- `php-84-fpm`
- `php-83-fpm`
- `php-82-fpm`
-- `php-81-fpm`
-- `php-80-fpm`
+- `php-85-console`
- `php-84-console`
- `php-83-console`
- `php-82-console`
-- `php-81-console`
-- `php-80-console`
- `php-80` means PHP 8.0.\*. It is not possible to require a specific "patch" version. The latest Bref versions always aim to support the latest PHP versions, so upgrade via Composer frequently to keep PHP up to date.
+ `php-84` means PHP 8.4.\*. It is not possible to require a specific "patch" version. The latest Bref versions always aim to support the latest PHP versions, so upgrade via Composer frequently to keep PHP up to date.
### The Bref plugin for serverless.yml
@@ -108,7 +105,7 @@ plugins:
- ./vendor/bref/bref
```
-This plugin is what makes `runtime: php-81` work (as well as other utilities). It is explained in more details in the section below.
+This plugin is what makes `runtime: php-84` work (as well as other utilities). It is explained in more details in the section below.
### ARM runtimes
@@ -120,7 +117,7 @@ You can deploy to ARM by using the `arm64` architecture:
functions:
api:
handler: public/index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
+ architecture: arm64
```
@@ -140,7 +137,7 @@ What the Bref plugin for `serverless.yml` (the one we include with `./vendor/bre
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
```
into this:
@@ -149,45 +146,43 @@ into this:
functions:
hello:
# ...
- runtime: provided.al2
+ runtime: provided.al2023
layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-81:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
-☝️ `provided.al2` [is the generic Linux environment for custom runtimes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-use), and the `layers` config points to Bref's AWS Lambda layers.
+☝️ `provided.al2023` [is the generic Linux environment for custom runtimes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-use), and the `layers` config points to Bref's AWS Lambda layers.
Thanks to the Bref plugin, our `serverless.yml` is simpler. It also automatically adapts to the AWS region in use, and automatically points to the correct layer version. You can learn more about "layers" [in this page](./runtimes/runtimes-details.mdx).
-If you want to reference AWS Lambda layers directly (instead of using the simpler `runtime: php-81` syntax), the Bref plugin also provides simple `serverless.yml` variables. These were the default in Bref v1.x, so you may find this older syntax on tutorials and blog posts:
+If you want to reference AWS Lambda layers directly (instead of using the simpler `runtime: php-84` syntax), the Bref plugin also provides simple `serverless.yml` variables. These were the default in Bref v1.x, so you may find this older syntax on tutorials and blog posts:
```yaml
service: app
provider:
name: aws
- runtime: provided.al2
+ runtime: provided.al2023
plugins:
- ./vendor/bref/bref
functions:
hello:
# ...
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
# or:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
```
The `${...}` notation is the [syntax to use variables](https://serverless.com/framework/docs/providers/aws/guide/variables/) in `serverless.yml`. The Bref plugin provides the following variables:
+- `${bref:layer.php-85}`
- `${bref:layer.php-84}`
- `${bref:layer.php-83}`
- `${bref:layer.php-82}`
-- `${bref:layer.php-81}`
-- `${bref:layer.php-80}`
+- `${bref:layer.php-85-fpm}`
- `${bref:layer.php-84-fpm}`
- `${bref:layer.php-83-fpm}`
- `${bref:layer.php-82-fpm}`
-- `${bref:layer.php-81-fpm}`
-- `${bref:layer.php-80-fpm}`
- `${bref:layer.console}`
Bref ARM layers are the same as the x86 layers, but with the `arm-` prefix in their name, for example `${bref:layer.arm-php-82}`. The only exception is `${bref:layer.console}` (this is the same layer for both x86 and ARM).
diff --git a/docs/runtimes/console.mdx b/docs/runtimes/console.mdx
index 26cafb7a6..4b6f4240e 100644
--- a/docs/runtimes/console.mdx
+++ b/docs/runtimes/console.mdx
@@ -35,10 +35,10 @@ plugins:
functions:
hello:
handler: the-php-script-to-run.php
- runtime: php-81-console
+ runtime: php-84-console
```
-Behind the scenes, the `php-xx-console` runtime will deploy a Lambda function configured to use Bref's `php-81` AWS Lambda layer plus Bref's `console` layer (read more about these in the [runtimes documentation](../runtimes.mdx)).
+Behind the scenes, the `php-xx-console` runtime will deploy a Lambda function configured to use Bref's `php-84` AWS Lambda layer plus Bref's `console` layer (read more about these in the [runtimes documentation](../runtimes.mdx)).
## Running commands
@@ -48,7 +48,7 @@ When invoked, the "Console" runtime executes the `handler` script in a sub-proce
functions:
hello:
handler: the-php-script-to-run.php
- runtime: php-81-console
+ runtime: php-84-console
```
Then the following command would run in Lambda every time the function is invoked:
diff --git a/docs/runtimes/fpm-runtime.mdx b/docs/runtimes/fpm-runtime.mdx
index 9765f30b7..c17a7a039 100644
--- a/docs/runtimes/fpm-runtime.mdx
+++ b/docs/runtimes/fpm-runtime.mdx
@@ -38,7 +38,7 @@ plugins:
functions:
app:
handler: index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
events:
- httpApi: '*'
```
diff --git a/docs/runtimes/function.mdx b/docs/runtimes/function.mdx
index 087c306c8..7139f7d37 100644
--- a/docs/runtimes/function.mdx
+++ b/docs/runtimes/function.mdx
@@ -49,7 +49,7 @@ plugins:
functions:
hello:
handler: my-function.php
- runtime: php-81
+ runtime: php-84
```
## PHP functions
diff --git a/docs/runtimes/runtimes-details.mdx b/docs/runtimes/runtimes-details.mdx
index 3aef0a18f..3ecdecf57 100644
--- a/docs/runtimes/runtimes-details.mdx
+++ b/docs/runtimes/runtimes-details.mdx
@@ -15,12 +15,12 @@ Bref runtimes are distributed as [AWS Lambda layers](https://docs.aws.amazon.com
The layer names (aka "[ARN](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html)") follow this pattern:
```
-arn:aws:lambda::534081306603:layer::
+arn:aws:lambda::873528684822:layer::
```
For example:
```
-arn:aws:lambda:us-east-1:534081306603:layer:php-80:21
+arn:aws:lambda:us-east-1:873528684822:layer:php-84:21
```
You can use layers via their full ARN, for example in `serverless.yml`:
@@ -32,9 +32,9 @@ provider:
functions:
hello:
# ...
- runtime: provided.al2
+ runtime: provided.al2023
layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-80:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
Or if you are using [SAM's `template.yaml`](https://aws.amazon.com/serverless/sam/):
@@ -47,9 +47,9 @@ Resources:
Type: AWS::Serverless::Function
Properties:
# ...
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-80:21'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-84:21'
```
Bref layers work with AWS Lambda regardless of the tool you use to deploy your application: Serverless, SAM, CloudFormation, Terraform, AWS CDK, etc.
diff --git a/docs/setup.mdx b/docs/setup.mdx
index 6ff9b38f3..dc2ead96f 100644
--- a/docs/setup.mdx
+++ b/docs/setup.mdx
@@ -125,3 +125,8 @@ That's it, you're ready to use Bref with the Serverless CLI!
} title="Get started with Symfony" arrow="true" href="/docs/symfony/getting-started" />
+
+
+ Bref is compatible with PHP 8.2 or greater.
+ If you are using PHP 8.0 or 8.1, Bref v2 (previous major version) will be installed instead.
+
diff --git a/docs/symfony/getting-started.mdx b/docs/symfony/getting-started.mdx
index e47ecb0c4..8dd8e15d8 100644
--- a/docs/symfony/getting-started.mdx
+++ b/docs/symfony/getting-started.mdx
@@ -21,13 +21,54 @@ Next, in an existing Symfony project, install Bref and the [Symfony Bridge packa
composer require bref/bref bref/symfony-bridge --update-with-dependencies
```
-Next, create a `serverless.yml` configuration file at the root of your project by running:
-
-```bash
-vendor/bin/bref init symfony
+Next, create a `serverless.yml` configuration file at the root of your project:
+
+```yml filename="serverless.yml"
+service: app # your application name (lowercase without spaces)
+
+bref:
+ # Uncomment and set your team ID if you are using Bref Cloud
+ #team: bref-team-id
+
+provider:
+ name: aws
+ region: us-east-1 # AWS region to deploy to
+ environment: # Environment variables
+ APP_ENV: prod
+
+functions:
+ # This function runs the Symfony website/API
+ web:
+ handler: public/index.php
+ runtime: php-84-fpm
+ timeout: 28 # in seconds (API Gateway has a max timeout of 29 seconds)
+ events:
+ - httpApi: '*'
+ # This function let us run console commands in Lambda
+ console:
+ handler: bin/console
+ runtime: php-84-console
+ timeout: 120 # in seconds
+
+package:
+ patterns:
+ # Excluded files and folders for deployment
+ - '!assets/**'
+ - '!node_modules/**'
+ - '!public/build/**'
+ - '!tests/**'
+ - '!var/**'
+ # If you want to include files and folders that are part of excluded folders,
+ # add them at the end
+ - 'var/cache/prod/**'
+ - 'public/build/entrypoints.json'
+ - 'public/build/manifest.json'
+
+plugins:
+ - ./vendor/bref/bref
```
-(you can preview that file [here](https://github.com/brefphp/bref/blob/master/template/http/serverless.yml))
+You will also want to add `.serverless` to your `.gitignore`.
You still have a few modifications to do on the application to make it compatible with AWS Lambda.
diff --git a/docs/symfony/keep-alive.mdx b/docs/symfony/keep-alive.mdx
index 0de6636b2..9e2fed588 100644
--- a/docs/symfony/keep-alive.mdx
+++ b/docs/symfony/keep-alive.mdx
@@ -19,8 +19,8 @@ functions:
+ handler: App\Kernel
layers:
# Switch from PHP-FPM to the "function" runtime:
-- - ${bref:layer.php-81-fpm}
-+ - ${bref:layer.php-81}
+- - ${bref:layer.php-84-fpm}
++ - ${bref:layer.php-84}
environment:
+ # The Symfony process will restart every 100 requests
+ BREF_LOOP_MAX: 100
diff --git a/docs/symfony/messenger.mdx b/docs/symfony/messenger.mdx
index dbbf87972..11675f9f6 100644
--- a/docs/symfony/messenger.mdx
+++ b/docs/symfony/messenger.mdx
@@ -84,7 +84,7 @@ constructs:
type: queue
worker:
handler: bin/consumer.php
- runtime: php-81
+ runtime: php-84
timeout: 60 # in seconds
```
@@ -193,7 +193,7 @@ functions:
worker:
handler: bin/consumer.php
timeout: 20 # in seconds
- runtime: php-81
+ runtime: php-84
events:
# Read more at https://www.serverless.com/framework/docs/providers/aws/events/sns/
- sns:
@@ -269,7 +269,7 @@ functions:
worker:
handler: bin/consumer.php
timeout: 20 # in seconds
- runtime: php-81
+ runtime: php-84
events:
# Read more at https://www.serverless.com/framework/docs/providers/aws/events/event-bridge/
- eventBridge:
diff --git a/docs/upgrading/_meta.json b/docs/upgrading/_meta.json
index 1a03b074b..94f4120a7 100644
--- a/docs/upgrading/_meta.json
+++ b/docs/upgrading/_meta.json
@@ -1,3 +1,4 @@
{
- "v2": "From 1.x to 2.0"
+ "v2": "From 1.x to 2.0",
+ "v3": "From 2.x to 3.0"
}
\ No newline at end of file
diff --git a/docs/upgrading/v2.md b/docs/upgrading/v2.md
index 042394853..34acf9c7f 100644
--- a/docs/upgrading/v2.md
+++ b/docs/upgrading/v2.md
@@ -43,15 +43,15 @@ There is a new (simpler) syntax to use Bref's PHP runtimes in `serverless.yml`:
functions:
hello:
# ...
- runtime: php-81
+ runtime: php-84
# instead of:
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
```
-The [bref.sh](https://bref.sh) documentation now uses the simpler `runtime: php-81` syntax, but `${bref:layer.php-xxx}` variables still work! These variables are not deprecated. There are no breaking changes here.
+The [bref.sh](https://bref.sh) documentation now uses the simpler `runtime: php-84` syntax, but `${bref:layer.php-xxx}` variables still work! These variables are not deprecated. There are no breaking changes here.
## Bref CLI
diff --git a/docs/upgrading/v3.mdx b/docs/upgrading/v3.mdx
new file mode 100644
index 000000000..1ad1998b3
--- /dev/null
+++ b/docs/upgrading/v3.mdx
@@ -0,0 +1,388 @@
+---
+introduction: Upgrading guide to go from Bref 2.x to Bref 3.0.
+---
+
+import { Callout } from 'nextra/components';
+
+# Upgrading to Bref 3.0
+
+Read the [Bref 3.0 release announcement](/news/03-bref-3.0) to learn about all the new features and improvements.
+
+## Updating dependencies
+
+### PHP 8.2 required
+
+Bref 3.0 now requires PHP 8.2 or greater.
+
+### Composer Dependencies
+
+Update all Bref packages in your `composer.json` file from `^2` to `^3`, for example:
+
+```json filename="composer.json"
+"require": {
+ "bref/bref": "^3",
+ "bref/laravel-bridge": "^3", // if you use Laravel
+ "bref/symfony-bridge": "^3", // if you use Symfony
+ "bref/extra-php-extensions": "^3" // if you use extra extensions
+}
+```
+
+
+ Only update the versions for the packages you actually have in your project.
+
+
+Then run:
+
+```bash
+composer update --with-all-dependencies
+```
+
+## PHP extension changes
+
+The following improvements in Bref 3.0 let you clean up old configurations.
+
+### PostgreSQL extension is enabled by default
+
+The PostgreSQL PDO extension (`pdo_pgsql`) is now enabled by default in Bref layers.
+
+If you had enabled it manually via a `php.ini` file, you can remove that line:
+
+```diff filename="php/conf.d/php.ini"
+-extension=pdo_pgsql
+```
+
+### Redis extension is now built-in
+
+The Redis PHP extension is now included in Bref layers by default.
+
+If you were using the Redis extension from [bref/extra-php-extensions](https://github.com/brefphp/extra-php-extensions), remove the layer from your `serverless.yml`:
+
+```diff filename="serverless.yml"
+functions:
+ api:
+ # ...
+ layers:
+- - ${bref-extra:redis-php-84}
+```
+
+And enable the extension via a `php.ini` file in your project (`php/conf.d/php.ini`):
+
+```diff filename="php/conf.d/php.ini"
+extension=redis
+```
+
+If Redis was the only `bref/extra-php-extensions` extension you were using, you can uninstall the package:
+
+```bash
+composer remove bref/extra-php-extensions
+```
+
+## Container image changes
+
+If you deploy using [container images](../deploy/docker.mdx), you must update your `Dockerfile`.
+
+**If you don't have a `Dockerfile` in your project, you can skip this section.**
+
+Since Bref container images have been merged into a single `bref/php-xx` image, the following images don't exist anymore: `bref/php-xx-fpm` and `bref/php-xx-console`.
+
+### Option 1: Set BREF_RUNTIME in the Dockerfile
+
+The simplest upgrade path is to update your Dockerfile to use the unified image and set the runtime:
+
+```diff filename="Dockerfile"
+- FROM bref/php-84-fpm:2
++ FROM bref/php-84:3
++ ENV BREF_RUNTIME=fpm
+
+# ...
+```
+
+Replace `fpm` with `function` or `console` depending on your use case.
+
+### Option 2: Use one image for all function types (recommended)
+
+A major benefit of v3 is that you can now use **a single Docker image** for all your functions (web, console, queues, etc.) and set `BREF_RUNTIME` per function in `serverless.yml`.
+
+**Dockerfile** (single image for everything):
+
+```dockerfile filename="Dockerfile"
+FROM bref/php-84:3
+
+# Your application code
+COPY . /var/task
+
+# No BREF_RUNTIME set here!
+```
+
+**serverless.yml** (set runtime per function):
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: fpm # Web/HTTP function
+ events:
+ - httpApi: '*'
+
+ console:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: console # Console commands
+
+ worker:
+ image:
+ name: my-app-image
+ environment:
+ BREF_RUNTIME: function # Queue worker
+ events:
+ - sqs:
+ arn: !GetAtt MyQueue.Arn
+```
+
+This approach lets you build and deploy a single Docker image for all function types, simplifying your deployment pipeline.
+
+### Local development images
+
+If you use the `bref/php-84-fpm-dev` image for local development, update it to:
+
+```diff filename="docker-compose.yml"
+- FROM bref/php-84-fpm-dev:2
++ FROM bref/php-84-dev:3
+```
+
+You can then set `BREF_RUNTIME` environment variable in your `docker-compose.yml` file or in the `Dockerfile` directly.
+
+## Smaller breaking changes that might impact you
+
+The changes below should not impact the majority of users. However, if you are using any of these features, you might need to update your code.
+
+### Changed the AWS account ID for AWS Lambda layers
+
+The AWS account ID where Bref layers are published is different for v3. That lets us keep releasing Bref v2 layers without mixing up layer numbers. If you reference the layers via their full ARN, you must update the Bref AWS account number to `873528684822` (instead of `534081306603`).
+
+```bash
+# Bref v2 layer
+arn:aws:lambda:us-east-1:534081306603:layer:php-84:xxx
+
+# Bref v3 layer
+arn:aws:lambda:us-east-1:873528684822:layer:php-84:xxx
+```
+
+**If you don't know what that means**, you're likely not concerned by this change.
+
+If you're not sure, search for `534081306603` in your codebase and replace it with the new account ID.
+
+### AWS Lambda layers have been merged into a single layer
+
+If you configure the `runtime` in your functions using the following syntax:
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ # ...
+ runtime: php-84-fpm # or `php-xx` or `php-xx-console`
+```
+
+✅ **you have nothing to do**, your configuration is valid for Bref v3.
+
+However, if you specify AWS Lambda layers explicitly in `serverless.yml` (or through any other deployment method), for example:
+
+```yml filename="serverless.yml"
+functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ layers:
+ - 'arn:aws:lambda:us-east-1:534081306603:layer:php-84:21'
+```
+
+Then you must update your configuration.
+
+Under the hood, **all layers have been merged into one**, i.e. `php-xx-fpm` and `php-xx-console` have been merged into `php-xx` to make Bref layers simpler. The runtime is now defined via an environment variable that is automatically injected by Bref when using the `runtime:` syntax.
+
+- **Option 1**: switch to using the simpler `runtime:` syntax.
+
+ Before:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ - ${bref:layer.php-84-console}
+ ```
+
+ After:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: php-84
+ # or:
+ runtime: php-84-fpm
+ # or:
+ runtime: php-84-console
+ ```
+
+ The examples above assume you are using PHP 8.4 (`php-84`) but you can replace `84` with another PHP version.
+
+ If you include additional layers, you can keep them without issues, for example:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: php-84-fpm
+ layers:
+ - ${bref-extra:imagick-php-84}
+ ```
+
+- **Option 2**: change the layer names and define the `BREF_RUNTIME` environment variable.
+
+ Before:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ # or:
+ - ${bref:layer.php-84-fpm}
+ # or:
+ - ${bref:layer.php-84-console}
+ ```
+
+ After:
+
+ ```yml filename="serverless.yml"
+ functions:
+ web:
+ # ...
+ runtime: provided.al2
+ layers:
+ - ${bref:layer.php-84}
+ environment:
+ # ...
+ BREF_RUNTIME: function # for ${bref:layer.php-xx}
+ # or
+ BREF_RUNTIME: fpm # for ${bref:layer.php-xx-fpm}
+ # or
+ BREF_RUNTIME: console # ${bref:layer.php-xx-console}
+ ```
+
+ The examples above assume you are using PHP 8.4 (`php-84`) but you can replace `84` with another PHP version.
+
+### The `vendor/bin/bref` CLI has been removed
+
+The `vendor/bin/bref` CLI has been completely removed in Bref 3.0. This is a minor change since the CLI was already 90% removed in Bref 2.0 - only the `bref init` command remained for bootstrapping new projects.
+
+We now have better onboarding with improved documentation. Here are the alternatives:
+
+- **Scaffolding new projects**: Follow the [getting started guide](/docs/setup) to create your `serverless.yml` manually.
+- **Layer versions**: Visit [runtimes.bref.sh](https://runtimes.bref.sh/) or run `serverless bref:layers`.
+- **Running console commands**: Use `serverless bref:cli` (unchanged from v2).
+- **Local development**: Use [Docker-based local development](/docs/local-development).
+
+### The hooks system has been removed
+
+The deprecated hooks system has been removed. This change affects very few users (less than 1%) as it was a low-level API used primarily by framework integrations.
+
+If you were using `Bref::beforeStartup()` or `Bref::beforeInvoke()`, you must migrate to the `BrefEventSubscriber` pattern:
+
+Before:
+
+```php
+use Bref\Bref;
+
+Bref::beforeStartup(function () {
+ // Setup code
+});
+```
+
+After:
+
+```php
+use Bref\Bref;
+use Bref\Listener\BrefEventSubscriber;
+
+class MyEventSubscriber extends BrefEventSubscriber
+{
+ public function beforeStartup(): void
+ {
+ // Setup code
+ }
+}
+
+Bref::events()->subscribe(new MyEventSubscriber());
+```
+
+The `BrefEventSubscriber` class provides additional hooks: `afterStartup()`, `beforeInvoke()`, and `afterInvoke()`. This refactor powers better integrations like the [Laravel bridge](https://github.com/brefphp/laravel-bridge), [X-Ray integration](https://bref.sh/xray), and [Sentry integration](https://bref.sh/sentry).
+
+### SOAP extension is now disabled by default
+
+The SOAP PHP extension is now disabled by default. It had very little usage, and disabling it helped reduce layer sizes to make room for more commonly used extensions.
+
+If you need the SOAP extension, you can enable it by creating a `php.ini` file in your project:
+
+```ini filename="php/conf.d/soap.ini"
+extension=soap
+```
+
+And reference it in your `serverless.yml`:
+
+```yml filename="serverless.yml"
+provider:
+ environment:
+ BREF_AUTOLOAD_PATH: php/conf.d
+```
+
+### Laravel version compatibility
+
+If you are using Laravel with Bref, note that:
+
+- **Laravel 10, 11, or 12 is required** (Laravel 8 and 9 are no longer supported).
+- Update `bref/laravel-bridge` to the latest version.
+
+The Laravel bridge has been updated to use the new `BrefEventSubscriber` pattern internally, but this change is transparent to users.
+
+### CloudWatch log formatter enabled by default
+
+The [Bref Monolog formatter](https://github.com/brefphp/monolog-bridge) is now enabled by default in the Laravel and Symfony bridges.
+
+**This changes how your logs will look.** Logs now use a hybrid format that combines human-readable text with structured JSON:
+
+Before (plain text):
+```
+[2025-12-05 10:30:45] production.ERROR: Database connection failed
+```
+
+After (structured format):
+```
+ERROR Database connection failed {"message":"Database connection failed","level":"ERROR","context":{...}}
+```
+
+This format makes logs easier to read in CloudWatch and enables powerful filtering with CloudWatch Logs Insights (e.g., filter by log level or exception class).
+
+**Exception handling is greatly improved:** Previously, exception stack traces were split across multiple CloudWatch log records (one per line), making them difficult to read and browse. Now, the entire exception (including stack trace) is grouped in a single JSON object, making debugging much easier.
+
+If you prefer the old format, you can disable the formatter in your Laravel or Symfony configuration. See the [Bref Monolog documentation](https://github.com/brefphp/monolog-bridge) for details.
+
+---
+
+That's it! Read the [Bref 3.0 release announcement](/news/03-bref-3.0) to learn more about all the new features and improvements in this release.
diff --git a/docs/use-cases/cron.mdx b/docs/use-cases/cron.mdx
index 4eda71636..44750bebd 100644
--- a/docs/use-cases/cron.mdx
+++ b/docs/use-cases/cron.mdx
@@ -22,7 +22,7 @@ functions:
Cron events can be used to run CLI commands with the [Console runtime](../runtimes/console.md).
-In that case, use the `php-xx-console` runtime (for example `php-81-console`).
+In that case, use the `php-xx-console` runtime (for example `php-84-console`).
This is usually best when coupled with a framework like Laravel or Symfony, or when porting an existing cron task to AWS Lambda.
@@ -33,7 +33,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: artisan
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -51,7 +51,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
artisan:
handler: artisan
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 minute)
@@ -64,7 +64,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: bin/console
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -81,7 +81,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: my-script.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -96,7 +96,7 @@ This is usually best when coupled with a framework like Laravel or Symfony, or w
# ...
cron:
handler: my-script.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
@@ -122,7 +122,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: App\MyCronHandler
- runtime: php-81
+ runtime: php-84
events:
- schedule:
rate: rate(1 hour)
@@ -165,7 +165,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: App\MyCronHandler
- runtime: php-81
+ runtime: php-84
events:
- schedule:
rate: rate(1 hour)
@@ -208,7 +208,7 @@ On top of running CLI cron tasks with the `php-xx-console` runtime, we can also
# ...
cron:
handler: function.php
- runtime: php-81-console
+ runtime: php-84-console
events:
- schedule:
rate: rate(1 hour)
diff --git a/docs/use-cases/http.mdx b/docs/use-cases/http.mdx
index 152285db3..27edf4d92 100644
--- a/docs/use-cases/http.mdx
+++ b/docs/use-cases/http.mdx
@@ -37,14 +37,14 @@ Bref sets up API Gateway with AWS Lambda and the [PHP-FPM runtime](../runtimes/f
functions:
web:
handler: public/index.php
- runtime: php-81-fpm
+ runtime: php-84-fpm
events:
- httpApi: '*'
```
This configuration deploys an API Gateway that forwards all routes (`*` is a wildcard) to AWS Lambda.
-On Lambda, the `php-81-fpm` runtime starts PHP-FPM and forwards all requests to it. PHP-FPM then runs the PHP code.
+On Lambda, the `php-84-fpm` runtime starts PHP-FPM and forwards all requests to it. PHP-FPM then runs the PHP code.
This is perfect for most use-cases: **PHP works like on any server** with PHP-FPM. HTTP routing based on the URL is done by the application/the framework.
diff --git a/docs/use-cases/http/advanced-use-cases.mdx b/docs/use-cases/http/advanced-use-cases.mdx
index cc7333931..f567620fe 100644
--- a/docs/use-cases/http/advanced-use-cases.mdx
+++ b/docs/use-cases/http/advanced-use-cases.mdx
@@ -189,7 +189,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: App\MyHttpHandler
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -207,7 +207,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: App\MyHttpHandler
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -225,7 +225,7 @@ Then, create a Lambda function that listens to HTTP events with the handler you
functions:
# ...
handler: handler.php
- runtime: php-81
+ runtime: php-84
# Lambda Function URL
url: true
# Or API Gateway
@@ -254,12 +254,12 @@ Since a handler is a controller for a specific route, we can use the API Gateway
functions:
create-article:
handler: App\CreateArticleController
- runtime: php-81
+ runtime: php-84
events:
- httpApi: 'POST /articles'
get-article:
handler: App\GetArticleController
- runtime: php-81
+ runtime: php-84
events:
- httpApi: 'GET /articles/{id}'
```
diff --git a/index.js b/index.js
index c8bd15f39..61fe23994 100644
--- a/index.js
+++ b/index.js
@@ -43,15 +43,22 @@ class ServerlessPlugin {
/** @type {Record>} */
this.layers = JSON.parse(fs.readFileSync(filename).toString());
- this.runtimes = Object.keys(this.layers)
- .filter(name => !name.startsWith('arm-'));
- // Console runtimes must have a PHP version provided
- this.runtimes = this.runtimes.filter(name => name !== 'console');
- this.runtimes.push('php-80-console', 'php-81-console', 'php-82-console', 'php-83-console', 'php-84-console');
-
this.checkCompatibleRuntime();
- serverless.configSchemaHandler.schema.definitions.awsLambdaRuntime.enum.push(...this.runtimes);
+ serverless.configSchemaHandler.schema.definitions.awsLambdaRuntime.enum.push(...[
+ 'php-82',
+ 'php-83',
+ 'php-84',
+ 'php-85',
+ 'php-82-fpm',
+ 'php-83-fpm',
+ 'php-84-fpm',
+ 'php-85-fpm',
+ 'php-82-console',
+ 'php-83-console',
+ 'php-84-console',
+ 'php-85-console',
+ ]);
serverless.configSchemaHandler.defineTopLevelProperty('bref', {
type: 'object',
});
@@ -170,77 +177,104 @@ class ServerlessPlugin {
}
/**
- * Process the `php-xx` runtimes to turn them into `provided.al2` runtimes + Bref layers.
+ * Process the `php-xx` runtimes to turn them into `provided.al2023` runtimes + Bref layers.
*/
processPhpRuntimes() {
- const includeBrefLayers = (runtime, existingLayers, isArm) => {
- let layerName = runtime;
+ const includeBrefLayers = (existingLayers, phpVersion, isArm) => {
+ let layerName = 'php-' + phpVersion;
// Automatically use ARM layers if the function is deployed to an ARM architecture
if (isArm) {
layerName = 'arm-' + layerName;
}
- if (layerName.endsWith('-console')) {
- layerName = layerName.substring(0, layerName.length - '-console'.length);
- existingLayers.unshift(this.getLayerArn('console', this.provider.getRegion()));
- existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
- } else {
- existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
- }
+ existingLayers.unshift(this.getLayerArn(layerName, this.provider.getRegion()));
return existingLayers;
}
+ /**
+ * @param {string} runtime
+ * @return {string|undefined}
+ */
+ const runtimeStringToRuntimeClass = (runtime) => {
+ if (! runtime.startsWith('php-')) {
+ return undefined;
+ }
+ if (runtime.endsWith('-console')) {
+ return 'Bref\\ConsoleRuntime\\Main';
+ }
+ if (runtime.endsWith('-fpm')) {
+ return 'Bref\\FpmRuntime\\Main';
+ }
+ return 'Bref\\FunctionRuntime\\Main';
+ };
+ const configureFunctionRuntime = (f) => {
+ // `php-\d\d(-fpm|console)?`
+ const fullRuntimeString = f.runtime || config.provider.runtime;
+ if (! fullRuntimeString || ! fullRuntimeString.startsWith('php-')) {
+ return;
+ }
+ const phpVersion = fullRuntimeString.substring('php-'.length).split('-')[0];
+ const runtimeClass = runtimeStringToRuntimeClass(fullRuntimeString);
+ if (! runtimeClass) return;
+
+ // The logic here is a bit custom:
+ // If there are layers on the function, we preserve them
+ let existingLayers = f.layers || []; // make sure it's an array
+ // Else, we merge with the layers defined at the root.
+ // Indeed, SF overrides the layers defined at the root with the ones defined on the function.
+ if (existingLayers.length === 0) {
+ // for some reason it's not always an array
+ existingLayers = Array.from(config.provider.layers || []);
+ }
+
+ f.layers = includeBrefLayers(
+ existingLayers,
+ phpVersion,
+ f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
+ );
+ f.runtime = 'provided.al2023';
+ // Add the `BREF_RUNTIME` environment variable
+ // to let the function know which runtime it is using
+ // (this is used by the Bref runtime)
+ if (!f.environment) {
+ f.environment = {};
+ }
+ if (!f.environment.BREF_RUNTIME) {
+ f.environment.BREF_RUNTIME = runtimeClass;
+ }
+ }
const config = this.serverless.service;
const isArmGlobally = config.provider.architecture === 'arm64';
- const isBrefRuntimeGlobally = this.runtimes.includes(config.provider.runtime || '');
// Check functions config
for (const f of Object.values(config.functions || {})) {
- if (
- (f.runtime && this.runtimes.includes(f.runtime)) ||
- (!f.runtime && isBrefRuntimeGlobally)
- ) {
- // The logic here is a bit custom:
- // If there are layers on the function, we preserve them
- let existingLayers = f.layers || []; // make sure it's an array
- // Else, we merge with the layers defined at the root.
- // Indeed, SF overrides the layers defined at the root with the ones defined on the function.
- if (existingLayers.length === 0) {
- // for some reason it's not always an array
- existingLayers = Array.from(config.provider.layers || []);
- }
-
- f.layers = includeBrefLayers(
- f.runtime || config.provider.runtime,
- existingLayers,
- f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
- );
- f.runtime = 'provided.al2';
- }
+ configureFunctionRuntime(f);
}
// Check Lift constructs config
for (const construct of Object.values(this.serverless.configurationInput.constructs || {})) {
if (construct.type !== 'queue' && construct.type !== 'webhook') continue;
const f = construct.type === 'queue' ? construct.worker : construct.authorizer;
- if (f && (f.runtime && this.runtimes.includes(f.runtime) || !f.runtime && isBrefRuntimeGlobally) ) {
- f.layers = includeBrefLayers(
- f.runtime || config.provider.runtime,
- f.layers || [], // make sure it's an array
- f.architecture === 'arm64' || (isArmGlobally && !f.architecture),
- );
- f.runtime = 'provided.al2';
+ if (f) {
+ configureFunctionRuntime(f);
}
}
}
checkCompatibleRuntime() {
- const errorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
+ const providedErrorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2023" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
+ const providdeAl2ErrorMessage = 'Bref layers are not compatible with the "provided" runtime.\nYou have to use the "provided.al2023" runtime instead in serverless.yml.\nMore details here: https://bref.sh/docs/news/01-bref-1.0.html#amazon-linux-2';
if (this.serverless.service.provider.runtime === 'provided') {
- throw new this.serverless.classes.Error(errorMessage);
+ throw new this.serverless.classes.Error(providedErrorMessage);
+ }
+ if (this.serverless.service.provider.runtime === 'provided.al2') {
+ throw new this.serverless.classes.Error(providdeAl2ErrorMessage);
}
for (const [, f] of Object.entries(this.serverless.service.functions || {})) {
if (f.runtime === 'provided') {
- throw new this.serverless.classes.Error(errorMessage);
+ throw new this.serverless.classes.Error(providedErrorMessage);
+ }
+ if (f.runtime === 'provided.al2') {
+ throw new this.serverless.classes.Error(providdeAl2ErrorMessage);
}
}
}
@@ -258,7 +292,7 @@ class ServerlessPlugin {
throw new this.serverless.classes.Error(`There is no Bref layer named "${layerName}" in region "${region}".\nThat region may not be supported yet. Check out https://runtimes.bref.sh to see the list of supported regions.\nOpen an issue to ask for that region to be supported: https://github.com/brefphp/bref/issues`);
}
const version = this.layers[layerName][region];
- return `arn:aws:lambda:${region}:534081306603:layer:${layerName}:${version}`;
+ return `arn:aws:lambda:${region}:873528684822:layer:${layerName}:${version}`;
}
/**
@@ -299,7 +333,7 @@ class ServerlessPlugin {
const payload = {
cli: 'sls',
- v: 2, // Bref version
+ v: 3, // Bref version
c: command,
ci: ci.isCI,
install: userConfig.get('meta.created_at'),
diff --git a/layers.json b/layers.json
index 71633ec1d..24bdbfb4f 100644
--- a/layers.json
+++ b/layers.json
@@ -1,506 +1,210 @@
{
- "php-84": {
- "ca-central-1": "35",
- "eu-central-1": "35",
- "eu-north-1": "35",
- "eu-west-1": "35",
- "eu-west-2": "35",
- "eu-west-3": "35",
- "sa-east-1": "35",
- "us-east-1": "35",
- "us-east-2": "35",
- "us-west-1": "35",
- "us-west-2": "35",
- "ap-east-1": "35",
- "ap-south-1": "35",
- "ap-northeast-1": "35",
- "ap-northeast-2": "35",
- "ap-northeast-3": "35",
- "ap-southeast-1": "35",
- "ap-southeast-2": "35",
- "eu-south-1": "35",
- "eu-south-2": "35",
- "af-south-1": "35",
- "me-south-1": "35"
+ "php-85": {
+ "ca-central-1": "10",
+ "eu-central-1": "10",
+ "eu-north-1": "10",
+ "eu-west-1": "10",
+ "eu-west-2": "10",
+ "eu-west-3": "10",
+ "sa-east-1": "10",
+ "us-east-1": "10",
+ "us-east-2": "10",
+ "us-west-1": "10",
+ "us-west-2": "10",
+ "ap-east-1": "10",
+ "ap-south-1": "10",
+ "ap-northeast-1": "10",
+ "ap-northeast-2": "10",
+ "ap-northeast-3": "10",
+ "ap-southeast-1": "10",
+ "ap-southeast-2": "10",
+ "ap-southeast-3": "10",
+ "eu-south-1": "10",
+ "eu-south-2": "10",
+ "af-south-1": "10",
+ "me-south-1": "10",
+ "me-central-1": "10"
},
- "php-84-fpm": {
- "ca-central-1": "35",
- "eu-central-1": "35",
- "eu-north-1": "35",
- "eu-west-1": "35",
- "eu-west-2": "35",
- "eu-west-3": "35",
- "sa-east-1": "35",
- "us-east-1": "35",
- "us-east-2": "35",
- "us-west-1": "35",
- "us-west-2": "35",
- "ap-east-1": "35",
- "ap-south-1": "35",
- "ap-northeast-1": "35",
- "ap-northeast-2": "35",
- "ap-northeast-3": "35",
- "ap-southeast-1": "35",
- "ap-southeast-2": "35",
- "eu-south-1": "35",
- "eu-south-2": "35",
- "af-south-1": "35",
- "me-south-1": "35"
+ "php-84": {
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
},
"php-83": {
- "ca-central-1": "63",
- "eu-central-1": "63",
- "eu-north-1": "63",
- "eu-west-1": "63",
- "eu-west-2": "63",
- "eu-west-3": "63",
- "sa-east-1": "63",
- "us-east-1": "63",
- "us-east-2": "63",
- "us-west-1": "63",
- "us-west-2": "63",
- "ap-east-1": "63",
- "ap-south-1": "63",
- "ap-northeast-1": "63",
- "ap-northeast-2": "63",
- "ap-northeast-3": "63",
- "ap-southeast-1": "63",
- "ap-southeast-2": "63",
- "eu-south-1": "63",
- "eu-south-2": "63",
- "af-south-1": "63",
- "me-south-1": "63"
- },
- "php-83-fpm": {
- "ca-central-1": "63",
- "eu-central-1": "63",
- "eu-north-1": "63",
- "eu-west-1": "63",
- "eu-west-2": "63",
- "eu-west-3": "63",
- "sa-east-1": "63",
- "us-east-1": "63",
- "us-east-2": "63",
- "us-west-1": "63",
- "us-west-2": "63",
- "ap-east-1": "63",
- "ap-south-1": "63",
- "ap-northeast-1": "63",
- "ap-northeast-2": "63",
- "ap-northeast-3": "63",
- "ap-southeast-1": "63",
- "ap-southeast-2": "63",
- "eu-south-1": "63",
- "eu-south-2": "63",
- "af-south-1": "63",
- "me-south-1": "63"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
},
"php-82": {
- "ca-central-1": "107",
- "eu-central-1": "107",
- "eu-north-1": "107",
- "eu-west-1": "107",
- "eu-west-2": "107",
- "eu-west-3": "107",
- "sa-east-1": "107",
- "us-east-1": "107",
- "us-east-2": "107",
- "us-west-1": "107",
- "us-west-2": "107",
- "ap-east-1": "107",
- "ap-south-1": "107",
- "ap-northeast-1": "107",
- "ap-northeast-2": "107",
- "ap-northeast-3": "107",
- "ap-southeast-1": "107",
- "ap-southeast-2": "107",
- "eu-south-1": "107",
- "eu-south-2": "106",
- "af-south-1": "107",
- "me-south-1": "107"
- },
- "php-82-fpm": {
- "ca-central-1": "107",
- "eu-central-1": "107",
- "eu-north-1": "107",
- "eu-west-1": "107",
- "eu-west-2": "107",
- "eu-west-3": "107",
- "sa-east-1": "107",
- "us-east-1": "107",
- "us-east-2": "107",
- "us-west-1": "107",
- "us-west-2": "107",
- "ap-east-1": "107",
- "ap-south-1": "107",
- "ap-northeast-1": "107",
- "ap-northeast-2": "107",
- "ap-northeast-3": "107",
- "ap-southeast-1": "107",
- "ap-southeast-2": "107",
- "eu-south-1": "107",
- "eu-south-2": "106",
- "af-south-1": "107",
- "me-south-1": "107"
- },
- "php-81": {
- "ca-central-1": "118",
- "eu-central-1": "118",
- "eu-north-1": "118",
- "eu-west-1": "118",
- "eu-west-2": "118",
- "eu-west-3": "118",
- "sa-east-1": "118",
- "us-east-1": "118",
- "us-east-2": "118",
- "us-west-1": "118",
- "us-west-2": "118",
- "ap-east-1": "110",
- "ap-south-1": "117",
- "ap-northeast-1": "117",
- "ap-northeast-2": "117",
- "ap-northeast-3": "117",
- "ap-southeast-1": "117",
- "ap-southeast-2": "117",
- "eu-south-1": "110",
- "eu-south-2": "107",
- "af-south-1": "110",
- "me-south-1": "110"
- },
- "php-81-fpm": {
- "ca-central-1": "117",
- "eu-central-1": "117",
- "eu-north-1": "118",
- "eu-west-1": "118",
- "eu-west-2": "117",
- "eu-west-3": "117",
- "sa-east-1": "117",
- "us-east-1": "118",
- "us-east-2": "117",
- "us-west-1": "117",
- "us-west-2": "118",
- "ap-east-1": "110",
- "ap-south-1": "116",
- "ap-northeast-1": "117",
- "ap-northeast-2": "116",
- "ap-northeast-3": "116",
- "ap-southeast-1": "116",
- "ap-southeast-2": "116",
- "eu-south-1": "109",
- "eu-south-2": "106",
- "af-south-1": "109",
- "me-south-1": "109"
- },
- "php-80": {
- "ca-central-1": "121",
- "eu-central-1": "120",
- "eu-north-1": "121",
- "eu-west-1": "121",
- "eu-west-2": "121",
- "eu-west-3": "121",
- "sa-east-1": "121",
- "us-east-1": "121",
- "us-east-2": "121",
- "us-west-1": "121",
- "us-west-2": "121",
- "ap-east-1": "111",
- "ap-south-1": "120",
- "ap-northeast-1": "118",
- "ap-northeast-2": "117",
- "ap-northeast-3": "118",
- "ap-southeast-1": "117",
- "ap-southeast-2": "119",
- "eu-south-1": "111",
- "eu-south-2": "107",
- "af-south-1": "111",
- "me-south-1": "111"
- },
- "php-80-fpm": {
- "ca-central-1": "118",
- "eu-central-1": "118",
- "eu-north-1": "118",
- "eu-west-1": "118",
- "eu-west-2": "118",
- "eu-west-3": "118",
- "sa-east-1": "118",
- "us-east-1": "118",
- "us-east-2": "118",
- "us-west-1": "118",
- "us-west-2": "118",
- "ap-east-1": "110",
- "ap-south-1": "117",
- "ap-northeast-1": "117",
- "ap-northeast-2": "117",
- "ap-northeast-3": "117",
- "ap-southeast-1": "117",
- "ap-southeast-2": "117",
- "eu-south-1": "110",
- "eu-south-2": "107",
- "af-south-1": "110",
- "me-south-1": "110"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
+ },
+ "arm-php-85": {
+ "ca-central-1": "10",
+ "eu-central-1": "10",
+ "eu-north-1": "10",
+ "eu-west-1": "10",
+ "eu-west-2": "10",
+ "eu-west-3": "10",
+ "sa-east-1": "10",
+ "us-east-1": "10",
+ "us-east-2": "10",
+ "us-west-1": "10",
+ "us-west-2": "10",
+ "ap-east-1": "10",
+ "ap-south-1": "10",
+ "ap-northeast-1": "10",
+ "ap-northeast-2": "10",
+ "ap-northeast-3": "10",
+ "ap-southeast-1": "10",
+ "ap-southeast-2": "10",
+ "ap-southeast-3": "10",
+ "eu-south-1": "10",
+ "eu-south-2": "10",
+ "af-south-1": "10",
+ "me-south-1": "10",
+ "me-central-1": "10"
},
"arm-php-84": {
- "ca-central-1": "35",
- "eu-central-1": "35",
- "eu-north-1": "35",
- "eu-west-1": "35",
- "eu-west-2": "35",
- "eu-west-3": "35",
- "sa-east-1": "35",
- "us-east-1": "35",
- "us-east-2": "35",
- "us-west-1": "35",
- "us-west-2": "35",
- "ap-east-1": "35",
- "ap-south-1": "35",
- "ap-northeast-1": "35",
- "ap-northeast-2": "35",
- "ap-northeast-3": "35",
- "ap-southeast-1": "35",
- "ap-southeast-2": "35",
- "eu-south-1": "35",
- "eu-south-2": "35",
- "af-south-1": "35",
- "me-south-1": "35"
- },
- "arm-php-84-fpm": {
- "ca-central-1": "35",
- "eu-central-1": "35",
- "eu-north-1": "35",
- "eu-west-1": "35",
- "eu-west-2": "35",
- "eu-west-3": "35",
- "sa-east-1": "35",
- "us-east-1": "35",
- "us-east-2": "35",
- "us-west-1": "35",
- "us-west-2": "35",
- "ap-east-1": "35",
- "ap-south-1": "35",
- "ap-northeast-1": "35",
- "ap-northeast-2": "35",
- "ap-northeast-3": "35",
- "ap-southeast-1": "35",
- "ap-southeast-2": "35",
- "eu-south-1": "35",
- "eu-south-2": "35",
- "af-south-1": "35",
- "me-south-1": "35"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
},
"arm-php-83": {
- "ca-central-1": "63",
- "eu-central-1": "63",
- "eu-north-1": "63",
- "eu-west-1": "63",
- "eu-west-2": "63",
- "eu-west-3": "63",
- "sa-east-1": "63",
- "us-east-1": "63",
- "us-east-2": "63",
- "us-west-1": "63",
- "us-west-2": "63",
- "ap-east-1": "63",
- "ap-south-1": "63",
- "ap-northeast-1": "63",
- "ap-northeast-2": "63",
- "ap-northeast-3": "63",
- "ap-southeast-1": "63",
- "ap-southeast-2": "63",
- "eu-south-1": "63",
- "eu-south-2": "63",
- "af-south-1": "63",
- "me-south-1": "63"
- },
- "arm-php-83-fpm": {
- "ca-central-1": "62",
- "eu-central-1": "62",
- "eu-north-1": "62",
- "eu-west-1": "62",
- "eu-west-2": "62",
- "eu-west-3": "62",
- "sa-east-1": "62",
- "us-east-1": "63",
- "us-east-2": "62",
- "us-west-1": "62",
- "us-west-2": "62",
- "ap-east-1": "62",
- "ap-south-1": "62",
- "ap-northeast-1": "62",
- "ap-northeast-2": "62",
- "ap-northeast-3": "62",
- "ap-southeast-1": "62",
- "ap-southeast-2": "62",
- "eu-south-1": "62",
- "eu-south-2": "62",
- "af-south-1": "62",
- "me-south-1": "62"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
},
"arm-php-82": {
- "ca-central-1": "95",
- "eu-central-1": "95",
- "eu-north-1": "95",
- "eu-west-1": "95",
- "eu-west-2": "95",
- "eu-west-3": "95",
- "sa-east-1": "95",
- "us-east-1": "95",
- "us-east-2": "95",
- "us-west-1": "95",
- "us-west-2": "95",
- "ap-east-1": "95",
- "ap-south-1": "95",
- "ap-northeast-1": "95",
- "ap-northeast-2": "95",
- "ap-northeast-3": "95",
- "ap-southeast-1": "95",
- "ap-southeast-2": "95",
- "eu-south-1": "95",
- "eu-south-2": "95",
- "af-south-1": "95",
- "me-south-1": "95"
- },
- "arm-php-82-fpm": {
- "ca-central-1": "95",
- "eu-central-1": "95",
- "eu-north-1": "95",
- "eu-west-1": "95",
- "eu-west-2": "95",
- "eu-west-3": "95",
- "sa-east-1": "95",
- "us-east-1": "95",
- "us-east-2": "95",
- "us-west-1": "95",
- "us-west-2": "95",
- "ap-east-1": "95",
- "ap-south-1": "95",
- "ap-northeast-1": "95",
- "ap-northeast-2": "95",
- "ap-northeast-3": "95",
- "ap-southeast-1": "95",
- "ap-southeast-2": "95",
- "eu-south-1": "95",
- "eu-south-2": "95",
- "af-south-1": "95",
- "me-south-1": "95"
- },
- "arm-php-81": {
- "ca-central-1": "98",
- "eu-central-1": "98",
- "eu-north-1": "98",
- "eu-west-1": "98",
- "eu-west-2": "98",
- "eu-west-3": "98",
- "sa-east-1": "98",
- "us-east-1": "98",
- "us-east-2": "98",
- "us-west-1": "98",
- "us-west-2": "98",
- "ap-east-1": "98",
- "ap-south-1": "98",
- "ap-northeast-1": "98",
- "ap-northeast-2": "98",
- "ap-northeast-3": "98",
- "ap-southeast-1": "98",
- "ap-southeast-2": "98",
- "eu-south-1": "98",
- "eu-south-2": "98",
- "af-south-1": "98",
- "me-south-1": "98"
- },
- "arm-php-81-fpm": {
- "ca-central-1": "98",
- "eu-central-1": "98",
- "eu-north-1": "98",
- "eu-west-1": "98",
- "eu-west-2": "98",
- "eu-west-3": "98",
- "sa-east-1": "98",
- "us-east-1": "98",
- "us-east-2": "98",
- "us-west-1": "98",
- "us-west-2": "98",
- "ap-east-1": "98",
- "ap-south-1": "98",
- "ap-northeast-1": "98",
- "ap-northeast-2": "98",
- "ap-northeast-3": "98",
- "ap-southeast-1": "98",
- "ap-southeast-2": "98",
- "eu-south-1": "98",
- "eu-south-2": "98",
- "af-south-1": "98",
- "me-south-1": "98"
- },
- "arm-php-80": {
- "ca-central-1": "120",
- "eu-central-1": "119",
- "eu-north-1": "120",
- "eu-west-1": "120",
- "eu-west-2": "120",
- "eu-west-3": "120",
- "sa-east-1": "120",
- "us-east-1": "120",
- "us-east-2": "120",
- "us-west-1": "120",
- "us-west-2": "120",
- "ap-east-1": "112",
- "ap-south-1": "119",
- "ap-northeast-1": "119",
- "ap-northeast-2": "119",
- "ap-northeast-3": "119",
- "ap-southeast-1": "119",
- "ap-southeast-2": "119",
- "eu-south-1": "112",
- "eu-south-2": "108",
- "af-south-1": "112",
- "me-south-1": "112"
- },
- "arm-php-80-fpm": {
- "ca-central-1": "119",
- "eu-central-1": "118",
- "eu-north-1": "119",
- "eu-west-1": "119",
- "eu-west-2": "118",
- "eu-west-3": "118",
- "sa-east-1": "118",
- "us-east-1": "119",
- "us-east-2": "119",
- "us-west-1": "118",
- "us-west-2": "119",
- "ap-east-1": "111",
- "ap-south-1": "117",
- "ap-northeast-1": "118",
- "ap-northeast-2": "117",
- "ap-northeast-3": "117",
- "ap-southeast-1": "117",
- "ap-southeast-2": "117",
- "eu-south-1": "110",
- "eu-south-2": "107",
- "af-south-1": "111",
- "me-south-1": "110"
- },
- "console": {
- "ca-central-1": "116",
- "eu-central-1": "116",
- "eu-north-1": "116",
- "eu-west-1": "116",
- "eu-west-2": "116",
- "eu-west-3": "116",
- "sa-east-1": "116",
- "us-east-1": "116",
- "us-east-2": "116",
- "us-west-1": "116",
- "us-west-2": "116",
- "ap-east-1": "108",
- "ap-south-1": "115",
- "ap-northeast-1": "115",
- "ap-northeast-2": "115",
- "ap-northeast-3": "115",
- "ap-southeast-1": "115",
- "ap-southeast-2": "115",
- "eu-south-1": "108",
- "eu-south-2": "105",
- "af-south-1": "108",
- "me-south-1": "108"
+ "ca-central-1": "13",
+ "eu-central-1": "13",
+ "eu-north-1": "13",
+ "eu-west-1": "13",
+ "eu-west-2": "13",
+ "eu-west-3": "13",
+ "sa-east-1": "13",
+ "us-east-1": "13",
+ "us-east-2": "13",
+ "us-west-1": "13",
+ "us-west-2": "13",
+ "ap-east-1": "13",
+ "ap-south-1": "13",
+ "ap-northeast-1": "13",
+ "ap-northeast-2": "13",
+ "ap-northeast-3": "13",
+ "ap-southeast-1": "13",
+ "ap-southeast-2": "13",
+ "ap-southeast-3": "13",
+ "eu-south-1": "13",
+ "eu-south-2": "13",
+ "af-south-1": "13",
+ "me-south-1": "13",
+ "me-central-1": "13"
}
}
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
index bcea319ff..337d37e45 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,7 +1,6 @@
parameters:
level: 5
paths:
- - bref
- src
- tests
excludePaths:
diff --git a/plugin/layers.js b/plugin/layers.js
index fd1307476..f0d9c45c8 100644
--- a/plugin/layers.js
+++ b/plugin/layers.js
@@ -17,7 +17,7 @@ function listLayers(serverless, log) {
log('----------------------------------------------------------------------------------');
for (const [layer, versions] of Object.entries(layers)) {
const version = versions[region];
- const arn = `arn:aws:lambda:${region}:534081306603:layer:${layer}:${version}`;
+ const arn = `arn:aws:lambda:${region}:873528684822:layer:${layer}:${version}`;
log(`${padString(layer, 12)} ${padString(version, 9)} ${arn}`);
}
}
diff --git a/plugin/run-console.js b/plugin/run-console.js
index 1e8775689..009af4fc9 100644
--- a/plugin/run-console.js
+++ b/plugin/run-console.js
@@ -1,14 +1,10 @@
-const fs = require('fs');
-const path = require('path');
-
/**
* @param {import('./serverless').Serverless} serverless
* @param {import('./serverless').CliOptions} options
*/
async function runConsole(serverless, options) {
- const region = serverless.getProvider('aws').getRegion();
// Override CLI options for `sls invoke`
- options.function = options.function || getConsoleFunction(serverless, region);
+ options.function = options.function || getConsoleFunction(serverless);
options.type = 'RequestResponse';
options.data = options.args;
options.log = true;
@@ -18,36 +14,24 @@ async function runConsole(serverless, options) {
/**
* @param {import('./serverless').Serverless} serverless
- * @param {string} region
*/
-function getConsoleFunction(serverless, region) {
- const consoleLayerArn = getConsoleLayerArn(region);
-
+function getConsoleFunction(serverless) {
const functions = serverless.service.functions;
const consoleFunctions = [];
for (const [functionName, functionDetails] of Object.entries(functions || {})) {
- if (functionDetails.layers && functionDetails.layers.includes(consoleLayerArn)) {
+ // Check for BREF_RUNTIME environment variable (set by Bref plugin for php-XX-console runtimes)
+ const brefRuntime = functionDetails.environment && functionDetails.environment.BREF_RUNTIME;
+ if (brefRuntime === 'Bref\\ConsoleRuntime\\Main' || brefRuntime === 'console') {
consoleFunctions.push(functionName);
}
}
if (consoleFunctions.length === 0) {
- throw new serverless.classes.Error('This command invokes the Lambda "console" function, but no function was found with the "console" layer');
+ throw new serverless.classes.Error('This command invokes a Lambda console function, but no function was found using the console runtime (e.g. php-84-console)');
}
if (consoleFunctions.length > 1) {
- throw new serverless.classes.Error('More than one function contains the console layer: cannot automatically run it. Please provide a function name using the --function option.');
+ throw new serverless.classes.Error('More than one function uses the console runtime: cannot automatically run it. Please provide a function name using the --function option.');
}
return consoleFunctions[0];
}
-/**
- * @param {string} region
- * @returns {string}
- */
-function getConsoleLayerArn(region) {
- const json = fs.readFileSync(path.join(__dirname, '../layers.json'));
- const layers = JSON.parse(json.toString());
- const version = layers.console[region];
- return `arn:aws:lambda:${region}:534081306603:layer:console:${version}`;
-}
-
module.exports = {runConsole};
diff --git a/src/Bref.php b/src/Bref.php
index d5d6c5fe7..38b705c52 100644
--- a/src/Bref.php
+++ b/src/Bref.php
@@ -12,11 +12,6 @@ class Bref
{
private static ?Closure $containerProvider = null;
private static ?ContainerInterface $container = null;
- /** @deprecated Use Bref::events()->subscribe() instead */
- private static array $hooks = [
- 'beforeStartup' => [],
- 'beforeInvoke' => [],
- ];
private static EventDispatcher $eventDispatcher;
/**
@@ -37,46 +32,6 @@ public static function events(): EventDispatcher
return self::$eventDispatcher;
}
- /**
- * Register a hook to be executed before the runtime starts.
- *
- * Warning: hooks are low-level extension points to be used by framework
- * integrations. For user code, it is not recommended to use them. Use your
- * framework's extension points instead.
- *
- * @deprecated Use Bref::events()->subscribe() instead.
- */
- public static function beforeStartup(Closure $hook): void
- {
- self::$hooks['beforeStartup'][] = $hook;
- }
-
- /**
- * Register a hook to be executed before any Lambda invocation.
- *
- * Warning: hooks are low-level extension points to be used by framework
- * integrations. For user code, it is not recommended to use them. Use your
- * framework's extension points instead.
- *
- * @deprecated Use Bref::events()->subscribe() instead.
- */
- public static function beforeInvoke(Closure $hook): void
- {
- self::$hooks['beforeInvoke'][] = $hook;
- }
-
- /**
- * @param 'beforeStartup'|'beforeInvoke' $hookName
- *
- * @internal Used by the Bref runtime
- */
- public static function triggerHooks(string $hookName): void
- {
- foreach (self::$hooks[$hookName] as $hook) {
- $hook();
- }
- }
-
/**
* @internal Used by the Bref runtime
*/
@@ -103,10 +58,6 @@ public static function reset(): void
{
self::$containerProvider = null;
self::$container = null;
- self::$hooks = [
- 'beforeStartup' => [],
- 'beforeInvoke' => [],
- ];
self::$eventDispatcher = new EventDispatcher;
}
}
diff --git a/src/Cli/init.php b/src/Cli/init.php
deleted file mode 100644
index b91fc53f9..000000000
--- a/src/Cli/init.php
+++ /dev/null
@@ -1,100 +0,0 @@
-find('serverless')) {
- warning(
- 'The `serverless` command is not installed.' . PHP_EOL .
- 'You will not be able to deploy your application unless it is installed' . PHP_EOL .
- 'Please follow the instructions at https://bref.sh/docs/installation.html' . PHP_EOL .
- 'If you have the `serverless` command available elsewhere (eg in a Docker container) you can ignore this warning.' . PHP_EOL
- );
- }
-
- if (! $template) {
- $intro = green('What kind of application are you building?');
- echo << ') ?: '0';
- echo PHP_EOL;
- if (! in_array($choice, ['0', '1', '2'], true)) {
- error('Invalid response (must be "0", "1" or "2"), aborting');
- }
-
- $template = [
- '0' => 'http',
- '1' => 'function',
- '2' => 'symfony',
- ][$choice];
- }
-
- $rootPath = dirname(__DIR__, 2) . "/template/$template";
-
- if (file_exists($rootPath . '/index.php')) {
- createFile($rootPath, 'index.php');
- }
- createFile($rootPath, 'serverless.yml');
-
- // If these is a `.gitignore` file in the current directory, let's add `.serverless` to it
- if (file_exists('.gitignore')) {
- $gitignore = file_get_contents('.gitignore');
- if (! str_contains($gitignore, '.serverless')) {
- file_put_contents('.gitignore', PHP_EOL . '.serverless' . PHP_EOL, FILE_APPEND);
- success('Added `.serverless` to your `.gitignore` file.');
- }
- }
-
- success('Project initialized and ready to test or deploy.');
-}
-
-/**
- * Creates files from the template directory and automatically adds them to git
- */
-function createFile(string $templatePath, string $file): void
-{
- echo "Creating $file\n";
-
- if (file_exists($file)) {
- $overwrite = false;
- echo "A file named $file already exists, do you want to overwrite it? [y/N]\n";
- $choice = strtolower(readline('> ') ?: 'n');
- echo PHP_EOL;
- if ($choice === 'y') {
- $overwrite = true;
- } elseif (! in_array($choice, ['y', 'n'], true)) {
- error('Invalid response (must be "y" or "n"), aborting');
- }
- if (! $overwrite) {
- echo "Skipping $file\n";
- return;
- }
- }
-
- $template = file_get_contents("$templatePath/$file");
- if (! $template) {
- error("Could not read file $templatePath/$file");
- }
- $template = str_replace('PHP_VERSION', PHP_MAJOR_VERSION . PHP_MINOR_VERSION, $template);
- file_put_contents($file, $template);
-
- /*
- * We check if this is a git repository to automatically add file to git.
- */
- $message = "$file successfully created";
- if ((new Process(['git', 'rev-parse', '--is-inside-work-tree']))->run() === 0) {
- (new Process(['git', 'add', $file]))->run();
- $message .= ' and added to git automatically';
- }
-
- echo PHP_EOL;
- success("$message.");
-}
diff --git a/src/ConsoleRuntime/Main.php b/src/ConsoleRuntime/Main.php
index 5e51639e3..9e9a31c1f 100755
--- a/src/ConsoleRuntime/Main.php
+++ b/src/ConsoleRuntime/Main.php
@@ -20,7 +20,6 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('console');
diff --git a/src/FpmRuntime/FpmHandler.php b/src/FpmRuntime/FpmHandler.php
index caa1ef145..1f91d1387 100644
--- a/src/FpmRuntime/FpmHandler.php
+++ b/src/FpmRuntime/FpmHandler.php
@@ -76,8 +76,20 @@ public function start(): void
/**
* --nodaemonize: we want to keep control of the process
* --force-stderr: force logs to be sent to stderr, which will allow us to send them to CloudWatch
+ * TODO set `max_execution_time` to the timeout of the Lambda function?
*/
- $resource = @proc_open(['php-fpm', '--nodaemonize', '--force-stderr', '--fpm-config', $this->configFile], [], $pipes);
+ $resource = @proc_open([
+ 'php-fpm',
+ '--nodaemonize',
+ '--force-stderr',
+ '--fpm-config',
+ $this->configFile,
+ // This setting is enabled by default for CLI invocations because it
+ // improves performance. We disable if it for PHP-FPM manually
+ // because it tanks performance by essentially disabling opcache
+ '-d',
+ 'opcache.file_cache_only=0',
+ ], [], $pipes);
if (! is_resource($resource)) {
throw new RuntimeException('PHP-FPM failed to start');
diff --git a/src/FpmRuntime/Main.php b/src/FpmRuntime/Main.php
index 2eb7c6a0c..8ec401ea3 100755
--- a/src/FpmRuntime/Main.php
+++ b/src/FpmRuntime/Main.php
@@ -16,15 +16,10 @@ class Main
{
public static function run(): void
{
- // In the FPM runtime process (our process) we want to log all errors and warnings
- ini_set('display_errors', '1');
- error_reporting(E_ALL);
-
ColdStartTracker::init();
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('fpm');
diff --git a/src/FunctionRuntime/Main.php b/src/FunctionRuntime/Main.php
index 7a4dda0de..823293f03 100644
--- a/src/FunctionRuntime/Main.php
+++ b/src/FunctionRuntime/Main.php
@@ -19,7 +19,6 @@ public static function run(): void
LazySecretsLoader::loadSecretEnvironmentVariables();
- Bref::triggerHooks('beforeStartup');
Bref::events()->beforeStartup();
$lambdaRuntime = LambdaRuntime::fromEnvironmentVariable('function');
diff --git a/src/Runtime/LambdaRuntime.php b/src/Runtime/LambdaRuntime.php
index 17fa52e65..e08219809 100755
--- a/src/Runtime/LambdaRuntime.php
+++ b/src/Runtime/LambdaRuntime.php
@@ -88,7 +88,6 @@ public function processNextEvent(Handler | RequestHandlerInterface | callable $h
try {
ColdStartTracker::invocationStarted();
- Bref::triggerHooks('beforeInvoke');
Bref::events()->beforeInvoke($handler, $event, $context);
$this->ping();
@@ -337,7 +336,6 @@ private function postJson(string $url, mixed $data, array $headers = []): void
private function closeCurlHandleNext(): void
{
if ($this->curlHandleNext !== null) {
- curl_close($this->curlHandleNext);
$this->curlHandleNext = null;
}
}
@@ -345,7 +343,6 @@ private function closeCurlHandleNext(): void
private function closeCurlHandleResult(): void
{
if ($this->curlHandleResult !== null) {
- curl_close($this->curlHandleResult);
$this->curlHandleResult = null;
}
}
diff --git a/src/bref-local b/src/bref-local
index 63e77d5ac..b66882e3b 100755
--- a/src/bref-local
+++ b/src/bref-local
@@ -22,13 +22,19 @@ $opts = getopt('', ['path:']);
if (isset($opts['path'])) {
if (! file_exists($opts['path'])) {
- throw new Exception('The file ' . $opts['path'] . ' could not be found.');
+ error_log('The file ' . $opts['path'] . ' could not be found.');
+ exit(1);
}
$handler = $argv[array_key_last($argv)];
$data = file_get_contents($opts['path']);
}
+if (!$handler) {
+ error_log('You must provide the handler to invoke as the first argument.');
+ exit(1);
+}
+
try {
$handler = Bref::getContainer()->get($handler);
} catch (NotFoundExceptionInterface $e) {
@@ -38,7 +44,8 @@ try {
try {
$event = $data ? json_decode($data, true, 512, JSON_THROW_ON_ERROR) : null;
} catch (JsonException $e) {
- throw new Exception('The JSON provided for the event data is invalid JSON.');
+ error_log('The JSON provided for the event data is invalid JSON.');
+ exit(1);
}
// Same configuration as the Bref runtime on Lambda
diff --git a/template/function/index.php b/template/function/index.php
deleted file mode 100644
index 346496cb7..000000000
--- a/template/function/index.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
- Welcome!
-
-
-
-
-
-
Hello there,
-
-
-
-
-
-
-
diff --git a/template/http/serverless.yml b/template/http/serverless.yml
deleted file mode 100644
index 65f86f77e..000000000
--- a/template/http/serverless.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-service: app
-
-# Set your team ID if you are using Bref Cloud
-#bref:
-# team: my-team-id
-
-provider:
- name: aws
- region: us-east-1
-
-plugins:
- - ./vendor/bref/bref
-
-functions:
- api:
- handler: index.php
- description: ''
- runtime: php-PHP_VERSION-fpm
- timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
- events:
- - httpApi: '*'
-
-# Exclude files from deployment
-package:
- patterns:
- - '!node_modules/**'
- - '!tests/**'
diff --git a/template/symfony/serverless.yml b/template/symfony/serverless.yml
deleted file mode 100644
index 48c49adb6..000000000
--- a/template/symfony/serverless.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-# Read the documentation at https://bref.sh/docs/symfony/getting-started
-service: symfony
-
-# Set your team ID if you are using Bref Cloud
-#bref:
-# team: my-team-id
-
-provider:
- name: aws
- # The AWS region in which to deploy (us-east-1 is the default)
- region: us-east-1
- environment:
- # Symfony environment variables
- APP_ENV: prod
-
-plugins:
- - ./vendor/bref/bref
-
-functions:
-
- # This function runs the Symfony website/API
- web:
- handler: public/index.php
- runtime: php-82-fpm
- timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
- events:
- - httpApi: '*'
-
- # This function let us run console commands in Lambda
- console:
- handler: bin/console
- runtime: php-82-console
- timeout: 120 # in seconds
-
-package:
- patterns:
- # Excluded files and folders for deployment
- - '!assets/**'
- - '!node_modules/**'
- - '!public/build/**'
- - '!tests/**'
- - '!var/**'
- # If you want to include files and folders that are part of excluded folders,
- # add them at the end
- - 'var/cache/prod/**'
- - 'public/build/entrypoints.json'
- - 'public/build/manifest.json'
diff --git a/tests/BrefTest.php b/tests/BrefTest.php
index 4ebbd05cd..8be54f30a 100644
--- a/tests/BrefTest.php
+++ b/tests/BrefTest.php
@@ -30,34 +30,4 @@ public function test override the container(): void
$this->assertSame($container, Bref::getContainer());
}
-
- public function test hooks(): void
- {
- $beforeStartup1 = false;
- $beforeStartup2 = false;
- $beforeInvoke = false;
-
- // Check that we can set multiple handlers
- Bref::beforeStartup(function () use (&$beforeStartup1) {
- return $beforeStartup1 = true;
- });
- Bref::beforeStartup(function () use (&$beforeStartup2) {
- return $beforeStartup2 = true;
- });
- Bref::beforeInvoke(function () use (&$beforeInvoke) {
- return $beforeInvoke = true;
- });
-
- $this->assertFalse($beforeStartup1);
- $this->assertFalse($beforeStartup2);
- $this->assertFalse($beforeInvoke);
-
- Bref::triggerHooks('beforeStartup');
- $this->assertTrue($beforeStartup1);
- $this->assertTrue($beforeStartup2);
- $this->assertFalse($beforeInvoke);
-
- Bref::triggerHooks('beforeInvoke');
- $this->assertTrue($beforeInvoke);
- }
}
diff --git a/tests/CliTest.php b/tests/CliTest.php
deleted file mode 100644
index 09b03afc0..000000000
--- a/tests/CliTest.php
+++ /dev/null
@@ -1,16 +0,0 @@
-mustRun();
- self::assertNotEmpty($process->getOutput());
- }
-}
diff --git a/tests/ConsoleRuntime/MainTest.php b/tests/ConsoleRuntime/MainTest.php
index 37785ae50..0b3f1946a 100644
--- a/tests/ConsoleRuntime/MainTest.php
+++ b/tests/ConsoleRuntime/MainTest.php
@@ -2,12 +2,10 @@
namespace Bref\Test\ConsoleRuntime;
-use Bref\Bref;
use Bref\ConsoleRuntime\CommandFailed;
use Bref\ConsoleRuntime\Main;
use Bref\Test\RuntimeTestCase;
use Bref\Test\Server;
-use Exception;
class MainTest extends RuntimeTestCase
{
@@ -19,16 +17,6 @@ public function setUp(): void
putenv('_HANDLER=console.php');
}
- public function test startup hook is called()
- {
- Bref::beforeStartup(function () {
- throw new Exception('This should be called');
- });
-
- $this->expectExceptionMessage('This should be called');
- Main::run();
- }
-
public function test happy path()
{
$this->givenAnEvent('');
diff --git a/tests/FpmRuntime/FpmHandlerTest.php b/tests/FpmRuntime/FpmHandlerTest.php
index 9ae4e7ce0..b332a4bc0 100644
--- a/tests/FpmRuntime/FpmHandlerTest.php
+++ b/tests/FpmRuntime/FpmHandlerTest.php
@@ -883,12 +883,6 @@ public function test POST request with multipart file uploads(int $version
'HTTP_RAW_BODY' => '',
];
- if (\PHP_VERSION_ID < 80100) {
- // full_path was introduced in PHP 8.1, remove it for lower versions
- unset($expectedGlobalVariables['$_FILES']['foo']['full_path']);
- unset($expectedGlobalVariables['$_FILES']['bar']['full_path']);
- }
-
$this->assertGlobalVariables($event, $expectedGlobalVariables);
}
diff --git a/tests/FpmRuntime/Functional/serverless.yml b/tests/FpmRuntime/Functional/serverless.yml
index 07c108f43..66bf3ea41 100644
--- a/tests/FpmRuntime/Functional/serverless.yml
+++ b/tests/FpmRuntime/Functional/serverless.yml
@@ -2,7 +2,7 @@ service: bref-tests
provider:
name: aws
- runtime: provided.al2
+ runtime: provided.al2023
region: eu-west-1
profile: bref-tests
apiGateway:
diff --git a/tests/FpmRuntime/MainTest.php b/tests/FpmRuntime/MainTest.php
deleted file mode 100644
index 7c0aa5c16..000000000
--- a/tests/FpmRuntime/MainTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-expectExceptionMessage('This should be called');
- Main::run();
- }
-}
diff --git a/tests/FunctionRuntime/MainTest.php b/tests/FunctionRuntime/MainTest.php
deleted file mode 100644
index 97fe60eaf..000000000
--- a/tests/FunctionRuntime/MainTest.php
+++ /dev/null
@@ -1,21 +0,0 @@
-expectExceptionMessage('This should be called');
- Main::run();
- }
-}
diff --git a/tests/PluginTest.php b/tests/PluginTest.php
index afc00d6d6..22684ff5d 100644
--- a/tests/PluginTest.php
+++ b/tests/PluginTest.php
@@ -2,6 +2,9 @@
namespace Bref\Test;
+use Bref\ConsoleRuntime\Main as ConsoleMain;
+use Bref\FpmRuntime\Main as FpmMain;
+use Bref\FunctionRuntime\Main as FunctionMain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Process;
use Symfony\Component\Yaml\Yaml;
@@ -12,26 +15,24 @@ public function test the plugin adds the layers(): void
{
$output = $this->slsPrint('serverless.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['fpm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83-fpm:',
+ self::assertFunction($output['functions']['fpm'], FpmMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['console'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
- 'arn:aws:lambda:us-east-1:534081306603:layer:console:',
+ self::assertFunction($output['functions']['console'], ConsoleMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
- self::assertFunction($output['functions']['fpm-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83-fpm:',
+ self::assertFunction($output['functions']['fpm-arm'], FpmMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
- self::assertFunction($output['functions']['console-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
- 'arn:aws:lambda:us-east-1:534081306603:layer:console:',
+ self::assertFunction($output['functions']['console-arm'], ConsoleMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
}
@@ -39,11 +40,11 @@ public function test the plugin adds the layers when the runtime is se
{
$output = $this->slsPrint('serverless-runtime-root.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
]);
}
@@ -51,22 +52,22 @@ public function test the plugin doesnt break layers added separately(): v
{
$output = $this->slsPrint('serverless-with-layers.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
]);
- self::assertFunction($output['functions']['function-arm-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
@@ -77,22 +78,22 @@ public function test the plugin doesnt break layers added separately wit
{
$output = $this->slsPrint('serverless-runtime-root-with-layers.yml');
- self::assertFunction($output['functions']['function'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-arm'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
'arn:aws:lambda:us-east-1:1234567890:layer:foo:1',
]);
- self::assertFunction($output['functions']['function-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:',
+ self::assertFunction($output['functions']['function-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
]);
- self::assertFunction($output['functions']['function-arm-with-layers'], [
- 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:',
+ self::assertFunction($output['functions']['function-arm-with-layers'], FunctionMain::class, [
+ 'arn:aws:lambda:us-east-1:873528684822:layer:arm-php-83:',
// This function doesn't have the `foo` layer because that's how SF works:
// layers in the function completely override the layers in the root
'arn:aws:lambda:us-east-1:1234567890:layer:bar:1',
@@ -111,9 +112,10 @@ private function slsPrint(string $configFile): array
return Yaml::parse($process->getOutput());
}
- private static function assertFunction(array $config, array $layers): void
+ private static function assertFunction(array $config, string $brefRuntime, array $layers): void
{
- self::assertEquals('provided.al2', $config['runtime']);
+ self::assertEquals('provided.al2023', $config['runtime']);
+ self::assertEquals($brefRuntime, $config['environment']['BREF_RUNTIME']);
self::assertCount(count($layers), $config['layers'], sprintf('Expected %d layers, got %d: %s', count($layers), count($config['layers']), json_encode($config['layers'], JSON_THROW_ON_ERROR)));
foreach ($layers as $index => $layer) {
self::assertStringStartsWith($layer, $config['layers'][$index]);
diff --git a/tests/Sam/template.yaml b/tests/Sam/template.yaml
index 7e262270f..05ca94f6b 100644
--- a/tests/Sam/template.yaml
+++ b/tests/Sam/template.yaml
@@ -8,9 +8,9 @@ Resources:
FunctionName: 'bref-tests-function'
CodeUri: ../..
Handler: tests/Sam/Php/function.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74:18'
Environment:
Variables:
FOO: bar
@@ -21,9 +21,9 @@ Resources:
FunctionName: 'bref-tests-http'
CodeUri: ../..
Handler: tests/Sam/PhpFpm/index.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74-fpm:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74-fpm:18'
Events:
HttpRoot:
Type: Api
@@ -40,9 +40,9 @@ Resources:
FunctionName: 'bref-tests-http-missing-handler'
CodeUri: ../..
Handler: tests/Sam/PhpFpm/UNKNOWN.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74-fpm:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74-fpm:18'
Events:
HttpRoot:
Type: Api
@@ -56,9 +56,9 @@ Resources:
FunctionName: 'bref-tests-psr7'
CodeUri: ../..
Handler: tests/Sam/Php/psr7.php
- Runtime: provided.al2
+ Runtime: provided.al2023
Layers:
- - 'arn:aws:lambda:us-east-1:534081306603:layer:php-74:18'
+ - 'arn:aws:lambda:us-east-1:873528684822:layer:php-74:18'
Events:
HttpRoot:
Type: Api
diff --git a/utils/layers.json/regions.json b/utils/layers.json/regions.json
index 5940d586c..0d0d125b3 100644
--- a/utils/layers.json/regions.json
+++ b/utils/layers.json/regions.json
@@ -17,8 +17,10 @@
"ap-northeast-3",
"ap-southeast-1",
"ap-southeast-2",
+ "ap-southeast-3",
"eu-south-1",
"eu-south-2",
"af-south-1",
- "me-south-1"
+ "me-south-1",
+ "me-central-1"
]
diff --git a/utils/layers.json/update.php b/utils/layers.json/update.php
index 3d2412119..0897e8abf 100644
--- a/utils/layers.json/update.php
+++ b/utils/layers.json/update.php
@@ -13,27 +13,14 @@
require_once __DIR__ . '/../../vendor/autoload.php';
const LAYER_NAMES = [
+ 'php-85',
'php-84',
- 'php-84-fpm',
'php-83',
- 'php-83-fpm',
'php-82',
- 'php-82-fpm',
- 'php-81',
- 'php-81-fpm',
- 'php-80',
- 'php-80-fpm',
+ 'arm-php-85',
'arm-php-84',
- 'arm-php-84-fpm',
'arm-php-83',
- 'arm-php-83-fpm',
'arm-php-82',
- 'arm-php-82-fpm',
- 'arm-php-81',
- 'arm-php-81-fpm',
- 'arm-php-80',
- 'arm-php-80-fpm',
- 'console',
];
$regions = json_decode(file_get_contents(__DIR__ . '/regions.json'), true);
@@ -66,7 +53,7 @@ function lambdaClient(string $region): LambdaClient
]);
$credentials = $stsClient->AssumeRole([
- 'RoleArn' => 'arn:aws:iam::534081306603:role/bref-layer-publisher',
+ 'RoleArn' => 'arn:aws:iam::873528684822:role/bref-layer-publisher',
'RoleSessionName' => 'bref-layer-builder',
]);
@@ -90,7 +77,7 @@ function listLayers(LambdaClient $lambda, string $selectedRegion): array
foreach (LAYER_NAMES as $layerName) {
$results[$layerName] = $lambda->listLayerVersions([
- 'LayerName' => sprintf('arn:aws:lambda:%s:534081306603:layer:%s', $selectedRegion, $layerName),
+ 'LayerName' => sprintf('arn:aws:lambda:%s:873528684822:layer:%s', $selectedRegion, $layerName),
'MaxItems' => 1,
]);
}
diff --git a/website/src/pages/news.mdx b/website/src/pages/news.mdx
index 471b4ecb0..a0ca257c5 100644
--- a/website/src/pages/news.mdx
+++ b/website/src/pages/news.mdx
@@ -9,6 +9,14 @@ import { NextSeo } from 'next-seo';
+## [Bref 3.0 is released 🎉](./news/03-bref-3.0.mdx)
+
+Bref 3.0 is here! Since Bref 2.0, we've grown from 10 billion to **40 billion Lambda executions** every month. The package has been installed more than **8 million times**, and we've crossed **4,000 commits** across all Bref repositories.
+
+Today, we celebrate these achievements and **the release of Bref 3.0** 🎉
+
+[▶ Read more](./news/03-bref-3.0.mdx)
+
## [Bref 2.0 is released 🎉](./news/02-bref-2.0.md)
The work on what would be Bref 2.0 started in October 2021, about 1.5 year ago. We went through many different strategies, experiments, rewrites, over **700 commits** to finally land with the stable release.
diff --git a/website/src/pages/news/02-bref-2.0.mdx b/website/src/pages/news/02-bref-2.0.mdx
index 1f2d919f1..f624319ff 100644
--- a/website/src/pages/news/02-bref-2.0.mdx
+++ b/website/src/pages/news/02-bref-2.0.mdx
@@ -70,7 +70,7 @@ functions:
handler: public/index.php
# ...
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
```
After (Bref v2 syntax):
@@ -82,10 +82,10 @@ functions:
api:
handler: public/index.php
# ...
- runtime: php-81-fpm
+ runtime: php-84-fpm
```
-As you can see, we no longer have to set `runtime: provided.al2` and add the Bref layers. We can now directly set a PHP runtime (`php-81`, `php-81-fpm`, `php-81-console`) and Bref will transform this into the proper runtime + layers configuration.
+As you can see, we no longer have to set `runtime: provided.al2` and add the Bref layers. We can now directly set a PHP runtime (`php-84`, `php-84-fpm`, `php-84-console`) and Bref will transform this into the proper runtime + layers configuration.
This works for all the Bref runtimes ([FPM](https://bref.sh/docs/runtimes/http.html), [function](https://bref.sh/docs/runtimes/function.html) and [console](https://bref.sh/docs/runtimes/console.html)) and all supported PHP versions (`80`, `81`, and `82` at the moment). Here's a recap:
@@ -93,24 +93,24 @@ This works for all the Bref runtimes ([FPM](https://bref.sh/docs/runtimes/http.h
# PHP-FPM runtime (web apps)
runtime: provided.al2
layers:
- - ${bref:layer.php-81-fpm}
+ - ${bref:layer.php-84-fpm}
# becomes:
-runtime: php-81-fpm
+runtime: php-84-fpm
# Function runtime
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
# becomes:
-runtime: php-81
+runtime: php-84
# Console runtime
runtime: provided.al2
layers:
- - ${bref:layer.php-81}
+ - ${bref:layer.php-84}
- ${bref:layer.console}
# becomes:
-runtime: php-81-console
+runtime: php-84-console
```
The Bref documentation has been updated to reflect these changes.
@@ -174,7 +174,7 @@ functions:
# ...
layers:
# Add the `-arm` prefix in layers 👇
- - ${bref:layer.arm-php-81-fpm}
+ - ${bref:layer.arm-php-84-fpm}
```
## Faster deployments
diff --git a/website/src/pages/news/03-bref-3.0.mdx b/website/src/pages/news/03-bref-3.0.mdx
new file mode 100644
index 000000000..c0f127a6b
--- /dev/null
+++ b/website/src/pages/news/03-bref-3.0.mdx
@@ -0,0 +1,228 @@
+import ArticleHeader from '../../components/news/ArticleHeader';
+import { NextSeo } from 'next-seo';
+import Image from 'next/image';
+import cloudScreenshot from './03/cloud-screenshot.png';
+
+
+
+# Bref 3.0 is released 🎉
+
+
+
+Bref 3.0 is here! Since Bref 2.0, we've grown from 10 billion to **40 billion Lambda executions** (aka requests) every month. The package has been installed more than **8 million times**, and we've crossed **4,000 commits** across all Bref repositories.
+
+Today, we celebrate these achievements and **the release of Bref 3.0** 🎉
+
+Let's check out what's new in v3.
+
+## Bref 3.0
+
+Here's a summary, we'll dive into the details below:
+
+- **24% smaller layers** for faster cold starts.
+- **Runtimes rebuilt on Amazon Linux 2023**: upgrade from deprecated Amazon Linux 2.
+- **PHP 8.5 support**
+- **PostgreSQL extension** is now enabled by default.
+- **Redis extension** is now built-in.
+- **Unified PHP runtime**: one layer and one container image instead of three.
+- **New regions**: `ap-southeast-3` and `me-central-1`.
+- **Better CloudWatch logs** with the new Monolog formatter enabled by default.
+- **[Bref Cloud](https://bref.sh/cloud)**: a simpler way to deploy Bref applications.
+
+What did we break? **Almost nothing**, the upgrade should be smooth. Here are the details:
+
+- PHP 8.2+ is now required (PHP 8.0 and 8.1 support is dropped).
+- The `vendor/bin/bref` CLI is removed (it was already 90% removed in v2).
+- The SOAP extension is now opt-in (it had very little usage).
+- If you deploy using container images, you'll need to update your Dockerfile.
+
+For a complete list of changes and instructions, check out the [**v3 upgrade guide**](../docs/upgrading/v3.mdx).
+
+## Faster Lambda cold starts
+
+The Bref layers for AWS Lambda have been optimized and their size reduced. It leaves more room for your code and should improve cold start times.
+
+- PHP 8.4: 69MB → 53MB
+- PHP 8.3: 65MB → 46MB
+
+This was achieved through several optimizations:
+
+- Stripping debug symbols from all libraries and PHP extensions.
+- Compiling PHP with size-optimization flags.
+- Disabling the rarely-used SOAP extension by default.
+- Bundling some PHP extensions directly into the PHP binary.
+
+## Amazon Linux 2023
+
+Bref 3.0 is built on **[Amazon Linux 2023](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html)** (AL2023), the latest version of Amazon's Linux distribution for AWS.
+
+The previous Bref versions were built on **Amazon Linux 2** (AL2), which has been deprecated by AWS. AWS Lambda will continue to support AL2 for some time, but it's recommended to migrate to AL2023 as soon as possible.
+
+This upgrade brings several benefits:
+
+- **Performance**: AL2023 is leaner than AL2, with more recent kernel and system libraries.
+- **Modern packages**: AL2023 ships with more recent package versions, simplifying the Bref build process.
+- **Long-term support**: AL2 will be deprecated in June 2026, while AL2023 will be supported at least until 2029.
+
+The migration happens automatically when you upgrade to Bref 3.0, no changes are needed on your end.
+
+## PHP 8.5 support
+
+Bref 3.0 adds support for **PHP 8.5** (which depended on an AL2023 system upgrade). You can start using it by setting the runtime in your `serverless.yml`:
+
+```yaml
+functions:
+ api:
+ handler: public/index.php
+ runtime: php-85-fpm
+```
+
+## Redis extension built-in
+
+The **Redis extension** is now included in Bref layers by default. Redis is one of the most used extensions by Bref users for caching and session storage.
+
+If you were using the Redis extension from [bref/extra-php-extensions](https://github.com/brefphp/extra-php-extensions), remove the layer from your `serverless.yml`:
+
+```diff filename="serverless.yml"
+functions:
+ api:
+ # ...
+ layers:
+- - ${bref-extra:redis-php-84}
+```
+
+And enable the extension via a `php.ini` file in your project (`php/conf.d/php.ini`):
+
+```diff filename="php/conf.d/php.ini"
+extension=redis
+```
+
+If Redis was the only `bref/extra-php-extensions` extension you were using, you can uninstall the package:
+
+```bash
+composer remove bref/extra-php-extensions
+```
+
+## PostgreSQL enabled by default
+
+The **PostgreSQL PDO extension** is now enabled by default. If you're using PostgreSQL, you no longer need any additional configuration.
+
+If you had enabled it manually via a `php.ini` file, you can remove that line:
+
+```diff filename="php/conf.d/php.ini"
+-extension=pdo_pgsql
+```
+
+## Unified PHP runtime
+
+Bref 3.0 consolidates the three separate layer types (function, FPM, console) into a **single unified layer** per PHP version. This simplification makes maintenance easier and provides a simpler mental model for users.
+
+**Do you need to change anything?**
+
+- **If you use `runtime: php-84-fpm` in your `serverless.yml`**: nothing changes, you're all set!
+- **If you deploy using container images**: you need to update your `Dockerfile`, ⚠️ read the [upgrade guide](../docs/upgrading/v3.mdx#updating-your-dockerfile-for-bref-30).
+- **If you specify layers explicitly**: ⚠️ read the [upgrade guide](../docs/upgrading/v3.mdx#aws-lambda-layers-have-been-merged-into-a-single-layer).
+
+A single layer/image is how it should have been from the start, and I'm really glad we're getting there now!
+
+## Better CloudWatch logs
+
+The [Bref Monolog formatter](https://github.com/brefphp/monolog-bridge) is now **enabled by default** in the Laravel and Symfony bridges. This formatter outputs logs in a format optimized for CloudWatch, making them easier to read and filter.
+
+Before (plain text):
+```
+[2025-12-05 10:30:45] production.ERROR: Database connection failed
+```
+
+After (structured format):
+```json
+ERROR Database connection failed {"message":"Database connection failed","level":"ERROR","context":{...}}
+```
+
+This format makes logs easier to read in CloudWatch and enables powerful filtering with CloudWatch Logs Insights (e.g., filter by log level or exception class).
+
+**Exception handling is also greatly improved:** Previously, exception stack traces were split across multiple CloudWatch log records (one per line), making them difficult to read and browse. Now, the entire exception (including stack trace) is grouped in a single JSON object, making debugging much easier.
+
+That new logging approach also allows reading all the logs of a single request, by filtering via the AWS request ID.
+
+## New regions
+
+Bref layers are now available in two additional regions:
+
+- `ap-southeast-3` (Asia Pacific - Jakarta)
+- `me-central-1` (Middle East - UAE)
+
+## The `vendor/bin/bref` CLI is removed
+
+The `vendor/bin/bref` CLI has been completely removed in Bref 3.0. This is a minor change since the CLI was already 90% removed in Bref 2.0 - only the `bref init` command remained for bootstrapping new projects.
+
+We now have better onboarding with improved documentation and the `serverless` CLI commands. Here are the alternatives:
+
+- **Scaffolding new projects**: Follow the [getting started guide](https://bref.sh/docs/setup) to create your `serverless.yml` manually.
+- **Layer versions**: Visit [runtimes.bref.sh](https://runtimes.bref.sh/) or run `serverless bref:layers`.
+- **Running console commands**: Use `serverless bref:cli` (this existed in v2).
+- **Local development**: Use [Docker-based local development](https://bref.sh/docs/local-development).
+
+## Upgrading
+
+Check out the [**v3 Upgrade Guide**](../docs/upgrading/v3.mdx) for a complete list of changes and instructions to upgrade your projects.
+
+## Thanks
+
+A huge thanks to the [Bref contributors](https://github.com/brefphp/bref/graphs/contributors), to the community for supporting the project, and to the open-source sponsors:
+
+**Premium sponsors:**
+
+- [Craft CMS](https://craftcms.com/?ref=bref.sh)
+- [Voxie](https://voxie.com/?ref=bref)
+- [MyBuilder](https://www.mybuilder.com/?ref=bref.sh)
+
+**Gold sponsors:**
+
+- [Depot](https://depot.dev/?ref=bref.sh)
+- [SecuMailer](https://secumailer.com/?ref=bref.sh)
+- [Ecomail](https://ecomail.cz/?ref=bref.sh)
+- [Spreaker](https://www.spreaker.com/?ref=bref)
+- [Runs On](https://runs-on.com/?ref=bref)
+- [Playable](https://playable.com/?ref=bref)
+
+And [many other personal sponsors](https://github.com/sponsors/mnapoli#sponsors)!
+
+Thank you all!
+
+## One more thing
+
+Check out **[Bref Cloud](https://bref.sh/cloud)** for a simpler way to deploy and monitor your Bref applications!
+
+
+
+
+
+
+## That's it!
+
+Hope you enjoy Bref v3!
+
+There is a complete [**v3 Upgrade Guide**](../docs/upgrading/v3.mdx) that you can follow.
+
+Head to the docs to [**get started with Bref**](../), or check out the documentation for [Laravel](../docs/laravel/getting-started.mdx) or [Symfony](../docs/symfony/getting-started.mdx).
+
+You can also join the community [in Slack](/docs/community.md), post details about your project in [Built with Bref](https://github.com/brefphp/bref/issues/267), or share your experience online and mention [@brefphp](https://twitter.com/brefphp) on Twitter.
+
+