KEMBAR78
Lessons from running AppSync in prod | PDF
Lessons from running
AppSync in production
Yan Cui
Yan Cui
http://theburningmonk.com
@theburningmonk
AWS user for 10 years
Yan Cui
http://theburningmonk.com
@theburningmonk
Developer Advocate @
Yan Cui
http://theburningmonk.com
@theburningmonk
Independent Consultant
advise
training delivery
three AppSync projects in the last 18 months
social network healthcare document assembly
B2B & B2C B2B & B2C B2B
multi-tenant multi-tenant multi-tenant
168 resolvers
111 resolvers
195 resolvers
social network healthcare document assembly
B2B & B2C B2B & B2C B2B
multi-tenant multi-tenant multi-tenant
168 resolvers
111 resolvers
195 resolvers
AppSync Lambda DynamoDB AppSync Lambda DynamoDB DynamoDB
Lambda
AppSync
social network healthcare document assembly
B2B & B2C B2B & B2C B2B
multi-tenant multi-tenant multi-tenant
168 resolvers
111 resolvers
195 resolvers
AppSync Lambda DynamoDB AppSync Lambda DynamoDB DynamoDB
Lambda
AppSync
Cognito Algolia Cognito ElasticSearch Algolia
Auth0
social network healthcare document assembly
B2B & B2C B2B & B2C B2B
multi-tenant multi-tenant multi-tenant
168 resolvers
111 resolvers
195 resolvers
AppSync Lambda DynamoDB AppSync Lambda DynamoDB DynamoDB
Lambda
AppSync
Cognito Algolia Cognito ElasticSearch Algolia
Auth0
Lumigo Lumigo Lumigo
Prefer VTL over Lambda
Faster, cheaper, simpler and more scalable
01.
AppSync DynamoDB
AppSync DynamoDB
Lambda
AppSync DynamoDB
Lambda
complex business logic
AppSync DynamoDB
Lambda
complex business logic
call 3rd party services
AppSync DynamoDB
Lambda
complex business logic
call 3rd party services
retries w/ exponential backoff
AppSync DynamoDB
Lambda
complex business logic
call 3rd party services
retries w/ exponential backoff
fallbacks/circuit-breakers
AppSync DynamoDB
Lambda
complex business logic
call 3rd party services
retries w/ exponential backoff
fallbacks/circuit-breakers
do more than one thing
AppSync DynamoDB
Lambda
complex business logic
call 3rd party services
retries w/ exponential backoff
fallbacks/circuit-breakers
do more than one thing
can use pipeline
resolvers instead
AppSync DynamoDB
Lambda
another source of latency
AppSync DynamoDB
Lambda
another source of latency
cold starts
AppSync DynamoDB
Lambda
another source of latency
cold starts
another cost
AppSync DynamoDB
Lambda
another source of latency
cold starts
another cost
concurrent executions limit
For CRUD operations, prefer VTL to Lambda resolver
AppSync DynamoDB Cheaper
Faster
More scalable
Simpler
“But I end up writing a lot of VTL and I don’t like VTL!”
“But I end up writing a lot of VTL and I don’t like VTL!”
- someone who uses single-table design
You don’t need STD*
* STD = single-table design
02.
single-table design
A collection of practices & modelling techniques for
DynamoDB that solves the problem of data joining by
pre-joining data into collections in a single table.
id name
1 Yan Cui
2 theburningmonk
UsersTable OrdersTable
userId orderId
1 007
1 008
id name
1 Yan Cui
2 theburningmonk
UsersTable OrdersTable
userId orderId
1 007
1 008
GetItem
id name
1 Yan Cui
2 theburningmonk
UsersTable OrdersTable
userId orderId
1 007
1 008
GetItem Query
pk sk
user#1 Yan Cui
user#2 theburningmonk
MySingleTable
name orderId
user
user
user#1 order#007 007
user#1 order#008 008
pk sk
user#1 Yan Cui
user#2 theburningmonk
MySingleTable
name orderId
user
user
user#1 order#007 007
user#1 order#008 008
Query
pk sk
user#1 Yan Cui
user#2 theburningmonk
MySingleTable
name orderId
user
user
user#1 order#007 007
user#1 order#008 008
Query
pk sk
user#1 Yan Cui
user#2 theburningmonk
MySingleTable
name orderId
user
user
user#1 order#007 007
user#1 order#008 008
Query
single-table design
Steep learning curve.
single-table design
Steep learning curve.
Difficult to add new access patterns.
single-table design
Steep learning curve.
Difficult to add new access patterns.
Can’t monitor usage cost by entity type.
single-table design
Steep learning curve.
Difficult to add new access patterns.
Can’t monitor usage cost by entity type.
Difficult to use DynamoDB streams.
getMyProfile {
userId
firstName
lastName
orders {
orderId
orderDate
amount
}
}
getMyProfile {
userId
firstName
lastName
orders {
orderId
orderDate
amount
}
}
UsersTable
OrdersTable
You should learn single-table design.
You should learn single-table design.
But don’t make it your religion.
“But I end up writing a lot of VTL and I don’t like VTL!”
- someone who uses single-table design
“But I end up writing a lot of VTL and I don’t like VTL!”
- someone who uses single-table design
to use single-table design with
AppSync, you have to write a
lot of custom logic in VTL…
“But what about all the cost savings from Single-Table Design?!”
“But what about all the cost savings from Single-Table Design?!”
Only matters when running at scale.
“But what about all the cost savings from Single-Table Design?!”
Caching is a far more effective cost-saving strategy.
average 99%
cache hit rate
p99 latency
~200ms
You need to use per-resolver caching
Because full-request caching just won’t do
03.
either
Full request caching
Per-resolver caching
full request caching
full request caching
$context.arguments
& $context.identity
full-request caching won’t get you very far
this profile appears in many
requests
full request caching
this tweet appears in many
requests
full request caching
per-resolver caching
each resolver can
opt-in for caching
per-resolver caching
each resolver can
opt-in for caching
can specify different TTL &
cache key for each
this profile can be cached
across different requests, by
different users
per-resolver caching
Caching seldom changed data for everyone is an
important part of a good caching strategy
You can flush the cache, but not individual items
You may see occassional overhead when AppSync
establishes connections to the cache node
Don’t leave logging on full in production
Great for debugging, even better for going bankrupt
04.
0
1
11
don’t leave resolver log level at ALL in production
https://theburningmonk.com/2020/09/how-to-sample-appsync-resolver-logs
Handle user errors gracefully
Because no one likes to wake up at 3am for a false alarm
05.
HTTP
5xx = our bad
4xx = your bad
HTTP
5xx = our bad
4xx = your bad
Alert on these!
HTTP
5xx = our bad
4xx = your bad
Alert on these!
Keep an eye on
these, but don’t wake
me up at 3am
API Gateway
module.exports.handler = async (event) => {
…. // validation logic
return {
statusCode: 404,
}
}
AppSync (Lambda resolver)
don’t have a way to return 4xx errors
AppSync (Lambda resolver)
module.exports.handler = async (event) => {
…. // validation logic
throw new Error(“not found”)
}
AppSync (Lambda resolver)
module.exports.handler = async (event) => {
…. // validation logic
throw new Error(“not found”)
}
Trips Lambda error alerts
AppSync (Lambda resolver)
module.exports.handler = async (event) => {
…. // validation logic
return {
error: {
message: “blah blah”,
type: “SomeErrorType”
}
}
}
AppSync (Lambda resolver)
if (!$util.isNull($ctx.result.error))
$util.error($ctx.result.error.message, $ctx.result.error.type)
#end
$utils.toJson($ctx.result)
Plan for going beyond 500 CloudFormation resources
Because you will get there, sooner than you think
06.
Use nested stacks.
No need to restructure your project.
!Ref and !GetAtt works as before.
Avoid circular referenes between the root and nested stack(s)
Model multi-tenant with Cognito groups and attributes
Because SaaS is the new black
07.
Users belong to tenants.
Users have roles within the tenant.
Some actions are limited to particular roles.
type Mutation {
addUser(name: String!, email: AWSEmail!, role: Role!): User
@aws_auth(cognito_groups: ["Admin", "SuperUser"])
…
}
type Mutation {
addUser(name: String!, email: AWSEmail!, role: Role!): User
@aws_auth(cognito_groups: ["Admin", "SuperUser"])
…
}
NEVER accept tenant ID as argument.
NEVER accept tenant ID as argument.
Use the identity in the request (resolved by Cognito).
https://theburningmonk.com/hire-me
Advise
Training Delivery
“Fundamentally, Yan has improved our team by increasing our
ability to derive value from AWS and Lambda in particular.”
Nick Blair
Tech Lead
Learn GraphQL and AppSync by building a
Twitter clone with these technologies
appsyncmasterclass.com
“Doing the AppSync Masterclass course has given me the confidence and
skills to start a project I've been wanting to do for 5 years.”
“If you are thinking about starting a new side project, take this course first!”
“This is by far the best course available of AppSync!”
“If you can only afford 1 course, I would suggest you go for this one.”
@theburningmonk
theburningmonk.com
github.com/theburningmonk

Lessons from running AppSync in prod