forked from wundergraph/cosmo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(router): aws lambda support (wundergraph#446)
Co-authored-by: Suvij Surya <suvijsurya76@gmail.com>
- Loading branch information
1 parent
a6a6322
commit 9c7d386
Showing
94 changed files
with
1,643 additions
and
421 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
name: AWS Lambda Router CI | ||
on: | ||
pull_request: | ||
paths: | ||
- "aws-lambda-router/**/*" | ||
- "router-tests/**/*" | ||
- ".github/workflows/aws-lambda-router-ci.yaml" | ||
|
||
concurrency: | ||
group: ${{github.workflow}}-${{github.head_ref}} | ||
cancel-in-progress: true | ||
|
||
env: | ||
CI: true | ||
|
||
jobs: | ||
build_test: | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 15 | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
|
||
- uses: actions/cache@v3 | ||
with: | ||
path: | | ||
~/.cache/go-build | ||
~/go/pkg/mod | ||
# The go install / version instructions are inside the Makefile, so we need to cache the Makefile. | ||
key: ${{ runner.os }}-go-${{ hashFiles('aws-lambda-router/go.sum') }}-makefile-${{ hashFiles('Makefile') }} | ||
restore-keys: | | ||
${{ runner.os }}-go- | ||
- uses: ./.github/actions/go | ||
with: | ||
cache-dependency-path: router/go.sum | ||
|
||
- name: Install tools | ||
run: make setup-build-tools | ||
|
||
- name: Generate code | ||
run: make generate-go | ||
|
||
- name: Check if git is not dirty after generating files | ||
run: git diff --no-ext-diff --exit-code | ||
|
||
- name: Install dependencies | ||
working-directory: ./aws-lambda-router | ||
run: go mod download | ||
|
||
- name: Run linters on router | ||
uses: ./.github/actions/go-linter | ||
with: | ||
working-directory: ./aws-lambda-router | ||
|
||
- name: Test | ||
working-directory: ./aws-lambda-router | ||
run: make test | ||
|
||
- name: Build | ||
working-directory: ./aws-lambda-router | ||
run: make build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
name: Build and Release AWS Router Binaries | ||
on: | ||
release: | ||
types: [published] | ||
#workflow_dispatch: | ||
|
||
permissions: | ||
contents: write | ||
packages: write | ||
|
||
jobs: | ||
releases-matrix: | ||
if: startsWith(github.event.release.tag_name, 'aws-lambda-router@') | ||
name: Build and Release AWS Router Binaries | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 30 | ||
|
||
strategy: | ||
matrix: | ||
# build and publish in parallel: linux/386, linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 | ||
goos: [linux, darwin] | ||
goarch: ["386", amd64, arm64] | ||
exclude: | ||
- goarch: "386" | ||
goos: darwin | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v3 | ||
|
||
- uses: ./.github/actions/go | ||
with: | ||
cache-dependency-path: router/go.sum | ||
|
||
- uses: winterjung/split@v2 | ||
id: split | ||
with: | ||
separator: "@" | ||
msg: "${{ github.event.release.tag_name }}" | ||
|
||
- uses: wangyoucao577/go-release-action@v1 | ||
name: Build and attach binaries to GitHub Release | ||
with: | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
goos: ${{ matrix.goos }} | ||
goarch: ${{ matrix.goarch }} | ||
# Where to run `go build .` | ||
project_path: "aws-lambda-router/cmd" | ||
# Convention from AWS Lambda | ||
binary_name: "bootstrap" | ||
pre_command: export CGO_ENABLED=0 | ||
build_flags: -trimpath | ||
# -w = omits the DWARF symbol table, effectively removing debugging information. Reduces binary size by ~30%. | ||
ldflags: -w -extldflags -static -X module github.com/wundergraph/cosmo/aws-lambda-router/internal.Version=${{ steps.split.outputs._1 }} | ||
overwrite: true | ||
extra_files: LICENSE | ||
#release_tag: router@0.14.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.aws-sam | ||
bootstrap | ||
lambda.zip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
.PHONY: build | ||
|
||
VERSION?=dev | ||
build: | ||
CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags "-extldflags -static -X github.com/wundergraph/cosmo/aws-lambda-router/internal.Version=$(VERSION)" -a -o bootstrap cmd/main.go | ||
|
||
build-sam: | ||
rm -rf .aws-sam && sam build --parallel && cp router.json .aws-sam/build/Api/router.json | ||
|
||
dev: build-sam | ||
sam local start-api -p 3003 --shutdown | ||
|
||
deploy: build-sam | ||
sam deploy | ||
|
||
lint: | ||
cd adapter && go vet ./... | ||
cd adapter && staticcheck ./... | ||
|
||
test: | ||
go test -v ./... | ||
|
||
fetch-router-config: | ||
wgc router fetch production -o router.json | ||
|
||
sync: | ||
sam sync --watch | ||
|
||
create-lambda-zip: build fetch-router-config | ||
zip -r lambda.zip bootstrap router.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# aws-lambda-router | ||
|
||
<p align="center"> | ||
<img width="550" src="cover.png"/> | ||
</p> | ||
|
||
This is the [AWS Lambda](https://aws.amazon.com/lambda/) version of the WunderGraph Cosmo [Router](https://wundergraph.com/cosmo/features/router). Please [contact](https://wundergraph.com/contact/sales) us if you have any questions or production use case. | ||
Why AWS lambda? Because it's cheap and scales automatically. You only pay for what you use. No need to manage servers or containers. It also integrates well with the rest of the AWS ecosystem. | ||
|
||
Status: **Beta** | ||
|
||
Demo: [https://zqadzbqwsi.execute-api.us-west-1.amazonaws.com/Prod/](https://zqadzbqwsi.execute-api.us-west-1.amazonaws.com/Prod/) (Playground) | ||
|
||
## Features | ||
|
||
- [X] GraphQL Queries | ||
- [X] GraphQL Mutations | ||
- [X] Telemetry Flushing after each request | ||
- [X] Schema Usage Tracking after each request | ||
- [ ] Subscription: Not implemented. Please [talk to us](https://wundergraph.com/contact/sales) if you need this. | ||
|
||
## Requirements | ||
|
||
* AWS CLI already configured with Administrator permission | ||
* [Docker installed](https://www.docker.com/community-edition) | ||
* [Golang](https://golang.org) | ||
* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) | ||
|
||
# Setup process | ||
|
||
## Cosmo Cloud | ||
|
||
First signup For Cosmo Cloud and follow the [onboarding](https://cosmo-docs.wundergraph.com/tutorial/cosmo-cloud-onboarding) process. | ||
|
||
Run `make fetch-router-config` to fetch the latest router configuration from Cosmo Cloud. We assume that you have named your graph `production`. | ||
The file is stored in `router.json` and copied to the Lambda build directory on each build. | ||
|
||
## Local development | ||
|
||
Build the router and start the API Gateway locally: | ||
|
||
```bash | ||
make dev | ||
``` | ||
|
||
Open [http://127.0.0.1:3003/](http://127.0.0.1:3003/) in your browser and you should see the GraphQL Playground. | ||
|
||
### Deploy on code change | ||
|
||
This will upload the code to AWS without performing a CloudFormation deployment. This is useful for development. | ||
|
||
```bash | ||
make sync | ||
``` | ||
|
||
## Deploying application | ||
|
||
Ensure that the following environment variables are set in [template.yaml](template.yaml): | ||
|
||
- `STAGE` - The name of the stage, which API Gateway uses as the first path segment in the invoke Uniform Resource Identifier (URI) e.g. `Prod` for `/Prod`. | ||
- `GRAPH_API_TOKEN` - The API token for your graph. You can find this in the Cosmo Cloud dashboard. | ||
|
||
*For production use cases, we recommend to use [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) to store the `GRAPH_API_TOKEN`.* | ||
|
||
```bash | ||
make deploy | ||
``` | ||
|
||
The command will package and deploy your application with the SAM CLI to AWS. | ||
You can find your API Gateway Endpoint URL in the output values displayed after deployment. | ||
|
||
# User Guide | ||
|
||
You don't have to build the router yourself. You can download the latest release and follow the instructions below. | ||
|
||
1. Download the Lambda Router binary from the official [Router Releases](https://github.com/wundergraph/cosmo/releases?q=aws-lambda-router&expanded=true) page. | ||
2. Create a .zip archive with the binary and the `router.json` file. You can download the latest `router.json` with [`wgc federated-graph fetch`](https://cosmo-docs.wundergraph.com/cli/federated-graph/fetch). | ||
|
||
The .zip archive should look like this: | ||
```bash | ||
. | ||
└── myFunction.zip/ | ||
├── bootstrap # Extracted from the Router release archive | ||
└── router.json # Downloaded with `wgc federated-graph fetch` | ||
``` | ||
3. Deploy the .zip archive to AWS Lambda. You can use SAM CLI or the AWS console. Alternatively, you can use your IaC tool of choice. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"github.com/akrylysov/algnhsa" | ||
"github.com/aws/aws-lambda-go/lambda" | ||
"github.com/wundergraph/cosmo/aws-lambda-router/internal" | ||
"github.com/wundergraph/cosmo/router/core" | ||
"github.com/wundergraph/cosmo/router/pkg/config" | ||
"github.com/wundergraph/cosmo/router/pkg/logging" | ||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
"net/http" | ||
"os" | ||
"time" | ||
) | ||
|
||
const ( | ||
telemetryServiceName = "aws-lambda-router" | ||
routerConfigPath = "router.json" | ||
) | ||
|
||
var ( | ||
defaultSampleRate = 0.2 // 20% of requests will be sampled | ||
enableTelemetry = os.Getenv("DISABLE_TELEMETRY") != "true" | ||
devMode = os.Getenv("DEV_MODE") == "true" | ||
stage = os.Getenv("STAGE") | ||
graphApiToken = os.Getenv("GRAPH_API_TOKEN") | ||
httpPort = os.Getenv("HTTP_PORT") | ||
) | ||
|
||
func main() { | ||
ctx := context.Background() | ||
|
||
logger := logging.New(false, false, zapcore.InfoLevel) | ||
logger = logger.With( | ||
zap.String("service_version", internal.Version), | ||
) | ||
defer func() { | ||
if err := logger.Sync(); err != nil { | ||
fmt.Println("Could not sync logger", err) | ||
} | ||
}() | ||
|
||
r := internal.NewRouter( | ||
internal.WithGraphApiToken(graphApiToken), | ||
internal.WithLogger(logger), | ||
internal.WithRouterConfigPath(routerConfigPath), | ||
internal.WithTelemetryServiceName(telemetryServiceName), | ||
internal.WithStage(stage), | ||
internal.WithTraceSampleRate(defaultSampleRate), | ||
internal.WithEnableTelemetry(enableTelemetry), | ||
internal.WithHttpPort(httpPort), | ||
internal.WithRouterOpts(core.WithDevelopmentMode(devMode)), | ||
internal.WithRouterOpts( | ||
core.WithEngineExecutionConfig(config.EngineExecutionConfiguration{ | ||
EnableSingleFlight: true, | ||
EnableRequestTracing: devMode, | ||
EnableExecutionPlanCacheResponseHeader: devMode, | ||
MaxConcurrentResolvers: 1024, | ||
}), | ||
), | ||
) | ||
|
||
svr, err := r.NewServer(ctx) | ||
if err != nil { | ||
logger.Fatal("Could not create server", zap.Error(err)) | ||
} | ||
|
||
// Set the server to ready | ||
svr.HealthChecks().SetReady(true) | ||
|
||
// If HTTP_PORT is set, we assume we are running the router without lambda | ||
if httpPort != "" { | ||
if err := svr.HttpServer().ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { | ||
logger.Fatal("Could not start server", zap.Error(err)) | ||
} | ||
return | ||
} | ||
|
||
lambdaHandler := algnhsa.New(svr.HttpServer().Handler, nil) | ||
lambda.StartWithOptions(lambdaHandler, | ||
lambda.WithContext(ctx), | ||
// Registered an internal extensions which gives us 500ms to shutdown | ||
// This mechanism does not replace telemetry flushing after a request | ||
// https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html#runtimes-lifecycle-extensions-shutdown | ||
lambda.WithEnableSIGTERM(func() { | ||
logger.Debug("Server shutting down") | ||
sCtx, cancel := context.WithTimeout(context.Background(), 400*time.Millisecond) | ||
defer cancel() | ||
if err := r.Shutdown(sCtx); err != nil { | ||
panic(err) | ||
} | ||
logger.Debug("Server shutdown") | ||
}), | ||
) | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.