-
Notifications
You must be signed in to change notification settings - Fork 3
/
serverless.yml
205 lines (195 loc) · 9.3 KB
/
serverless.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
service: gcms-tfp-cache
frameworkVersion: "=1.74.0"
plugins:
# - serverless-plugin-epsagon # https://github.com/epsagon/serverless-plugin-epsagon XXX We don't use it because it's not compatible with the basic_auth authorizer, used by /read-cache
- serverless-webpack # https://github.com/serverless-heaven/serverless-webpack
- serverless-offline # See https://github.com/dherault/serverless-offline
- '@unly/serverless-env-copy-plugin' # See https://github.com/UnlyEd/serverless-env-copy-plugin
- serverless-domain-manager # See https://github.com/amplify-education/serverless-domain-manager
- serverless-dotenv-plugin # See https://www.npmjs.com/package/serverless-dotenv-plugin
package:
individually: true
custom:
serverless-offline:
port: 8085 # Update .env.development and .env.test if you ever change this
showDuration: true
environment: ${env:NODE_ENV, 'development'}
envs:
development: # XXX Used by both "development" and "test" environments
profile:
domain:
name: ''
memorySize:
demoStaging:
profile: # TODO AWS profile to use for this environment - Useful if your staging and production apps don't live in the same AWS Account! (which is our case)
domain:
name: '' # TODO Your staging domain name
memorySize: 256
demo:
profile: # TODO AWS profile to use for this environment - Useful if your staging and production apps don't live in the same AWS Account! (which is our case)
domain:
name: '' # TODO Your production domain name
memorySize: 256
webpack:
webpackConfig: 'webpack.config.js'
includeModules:
forceExclude:
- aws-sdk
packager: 'yarn'
packagerOptions: {}
excludeFiles: src/**/*.test.js
keepOutputDirectory: true
customDomain:
enabled: true
domainName: ${self:custom.envs.${self:provider.stage}.domain.name}
stage: ${self:provider.stage}
createRoute53Record: true
provider:
name: aws
runtime: nodejs10.x # AWS keeps up to date with the latest v10 version - See https://forum.serverless.com/t/node-10-lambdas-on-aws/8302/2
versionFunctions: false # See https://serverless.com/framework/docs/providers/aws/guide/functions#versioning-deployed-functions
logRetentionInDays: 60
stage: ${opt:stage, 'development'}
region: eu-west-1
memorySize: ${self:custom.envs.${self:provider.stage}.memorySize, '128'}
timeout: 30 # 30sec timeout, we perform long-running lambda sometimes (such as /refresh-cache)
logs:
restApi: true # Enable logs in other services, such as API GW - See https://serverless.com/blog/framework-release-v142/
deploymentBucket:
serverSideEncryption: AES256
environment:
NODE_ENV: ${self:custom.environment}
REDIS_URL: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.REDIS_URL}
REDIS_PASSWORD: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.REDIS_PASSWORD}
GRAPHCMS_ENDPOINT: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.GRAPHCMS_ENDPOINT}
GRAPHCMS_TOKEN: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.GRAPHCMS_TOKEN}
REFRESH_CACHE_TOKEN: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.REFRESH_CACHE_TOKEN}
BASIC_AUTH_USERNAME: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.BASIC_AUTH_USERNAME}
BASIC_AUTH_PASSWORD: ${file(./secrets-${self:custom.environment}.yml):${self:provider.stage}.BASIC_AUTH_PASSWORD}
EPSAGON_APP_TOKEN: ${file(./secrets-${self:custom.environment}.yml):EPSAGON_APP_TOKEN}
EPSAGON_APP_NAME: ${self:service}-${self:provider.stage}-${self:custom.environment}
CACHE_BASE_URL: https://${self:custom.envs.${self:provider.stage}.domain.name} # Overridden in development/test by .env.X files
profile: ${self:custom.envs.${self:provider.stage}.profile, ''}
stackTags:
env: ${self:custom.environment}
stage: ${self:provider.stage}
region: ${self:provider.region}
service: ${self:service}
service-type: api
runtime: ${self:provider.runtime}
functions:
cache-query:
handler: src/functions/epsagon.cacheQuery
events:
- http:
method: POST
path: /cache-query
cors: # XXX See https://serverless.com/blog/cors-api-gateway-survival-guide/
origin: '*' # Same as "Access-Control-Allow-Origin"
headers: # Same as "Access-Control-Allow-Headers"
# Standard default headers
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
# Additional headers - Specific to this app
- gcms-locale
- gcms-locale-no-default
allowCredentials: false
reset-cache:
handler: src/functions/epsagon.resetCache
# XXX Ensures the lambda always has one slot available, and never use more than one lambda instance at once.
# Avoids GraphCMS webhooks to abuse our lambda (GCMS will trigger the webhook once per create/update/delete operation)
# This makes sure only one instance of that lambda can run at once, to avoid refreshing the cache with parallel runs
# Avoids flushing the redis DB multiple times at the same time
# See https://itnext.io/the-everything-guide-to-lambda-throttling-reserved-concurrency-and-execution-limits-d64f144129e5
reservedConcurrency: 1
events:
- http:
method: POST
path: /reset-cache
cors: true
refresh-cache:
handler: src/functions/refresh-cache.refreshCache # FIXME Don't use epsagon wrapper - creates an infinite loop (see slack)
# XXX Ensures the lambda always has one slot available, and never use more than one lambda instance at once.
# Avoids GraphCMS webhooks to abuse our lambda (GCMS will trigger the webhook once per create/update/delete operation)
# This makes sure only one instance of that lambda can run at once, to avoid refreshing the cache with parallel runs
# Avoids spawning tons of API calls (most of them would timeout anyway, around 80%)
# See https://itnext.io/the-everything-guide-to-lambda-throttling-reserved-concurrency-and-execution-limits-d64f144129e5
reservedConcurrency: 1
events:
- http:
method: POST
path: /refresh-cache
cors: true
status:
handler: src/functions/status.status # Don't trace status route
events:
- http:
method: GET
path: /status
cors: true
read-cache:
handler: src/functions/epsagon.readCache
events:
- http:
method: GET
path: /read-cache
cors: true
authorizer: # See https://medium.com/@Da_vidgf/http-basic-auth-with-api-gateway-and-serverless-5ae14ad0a270
name: authorizer
resultTtlInSeconds: 0
identitySource: method.request.header.Authorization
type: request
authorizer:
handler: src/authorizers/basic-auth.handler # A Basic-Auth authentication is required in non-local environments
resources:
Conditions:
IsProduction:
Fn::Equals:
- ${self:custom.environment}
- "production"
Resources:
GatewayResponse:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.WWW-Authenticate: "'Basic'"
ResponseType: UNAUTHORIZED
RestApiId:
Ref: 'ApiGatewayRestApi'
StatusCode: '401'
# XXX Health check is meant to check if /status endpoint replies properly, it doesn't check internal behaviour.
# Also, it doesn't warm any endpoint but /status. And it won't configure alerts automatically.
# Feel free to enable it if you need it, it will increase your cost, though.
# XXX P.S: We are looking for a better way to perform health checks, AWS is too "heavy", too many useless calls are sent and we couldn't configure alerts automatically to hit our slack channel - If you know of a better way, please share!
# healthCheck:
# Condition: IsProduction # Only deploy HealthCheck in production environment
# Type: "AWS::Route53::HealthCheck"
# Properties:
# HealthCheckConfig:
# EnableSNI: true
# FailureThreshold: "3"
# FullyQualifiedDomainName: ${self:custom.envs.${self:provider.stage}.domain.name}
# ResourcePath: "/status" # XXX Optimize cost by hitting a simple endpoint which doesn't download anything and avoid cost due to data transfer (S3, API Gateway)
# MeasureLatency: false # XXX Cost $1/stage/month ($2/month for staging + production, for a single customer)
# Port: "80"
# Regions: # XXX Only check from UE/US (minimum 3 regions is required), cost much less money and not useful to check from all datacenters in the world
# - 'eu-west-1' # Ireland
# - 'us-west-1' # California
# - 'us-east-1' # Virginia
# RequestInterval: "30" # 30 is the max allowed
# Type: "HTTPS"
# HealthCheckTags:
# - Key: "env"
# Value: ${self:custom.environment}
# - Key: "stage"
# Value: ${self:provider.stage}
# - Key: "region"
# Value: ${self:provider.region}
# - Key: "service"
# Value: ${self:service}
# - Key: "service-type"
# Value: api