serverless-appsync-plugin
serverless-appsync-plugin copied to clipboard
[FEATURE] please support cache eviction
It is possible to evict caches within AWS appsync. https://aws.amazon.com/blogs/mobile/introducing-server-side-caching-item-eviction-for-aws-appsync/
It would be super nice if this plugin supports those evictions.
@bboure thanks a lot for super fast answer!
Just a question. Your link leads to the documentation for flush-cache
.
If I understand the docs right it is similar to the aws cli comman [aws appsync flush-api-cache]( (https://docs.aws.amazon.com/cli/latest/reference/appsync/flush-api-cache.html) which is great out of development perspective.
My feature request refers to request cache eviction which will evict caches for client requests to the appsync api during run time.
To implement this behaviour the underlying request mapping template must be adjusted.
Will this feature also be implemented within v2
(at least I did not find a note within your docs)? would be super nice!
Remark
It is already possible to do this with a combination of substitutions
and request/response
mapping template.
But not super convenient. Built in into this plugin would be awesome. Please get back to me if I can support in any way
Got it!
I have not used that feature yet, but if I'm not mistaken, this is fully controlled on the VTL level as you mentioned.
You already have to write your own VTL templates, so I am not sure what else this plugin could do?
Let me know if you have any idea
We currently use 2 major VTL templates:
- response
- request
For different datasources we use your substitution
feature to inject different variable values used in those templates.
This reduces our amount of code and it is much more easy to test and debug.
(debugging velocity templates is not nice).
For the cache eviction we use smth like:
#set($responseCachingEvictions=${responseCachingEvictions})
#if($responseCachingEvictions.size() > 0)
#foreach($cachingEviction in $responseCachingEvictions)
#set($cachingKeys = {})
#foreach($key in $cachingEviction.keys)
$util.qr($cachingKeys.put("$key.name", "$key.value"))
#end
$extensions.evictFromApiCache("$cachingEviction.graphQlType", "$cachingEviction.functionName", $cachingKeys)
#end
#end
what need an object susbitution with following schema (JSON.stringify
the object):
export interface CachingEvictionVelocity {
keys: {value: string; name: string}[];
graphQlType: GraphQLType;
functionName: string;
}
Thats ugly but working.
It would be much nicer if there would be config parameters within your plugin like
- dataSource: accountsListAccountsDataSource
type: mutation
field: updateNode
caching:
ttl: 200
keys: []
cachingEvictions:
- queryType: Query
function: getNote
cachingKeys:
- context.argumtens.id
- context.identity.sub
- ...
substitutions:
....
which you could use in you velocity template like
...
${cachingEvictions}
...
That would be substituted to smth like
...
#set($cachingKeys = {})
$util.qr($cachingKeys.put("context.arguments.id", $context.arguments.id))
$extensions.evictFromApiCache("Query", "getNote", $cachingKeys)
...
Out of a development perspective this would be much nicer and much more convenient.
Furthermore it would be super if the plugin would in addition provide some sanity checks
- is the function defined
- is the caching key used within the function
That would in addition avoid many runtime errors of the app.
Remark Another idea of for the schema: define the cachingEvictions already within the caching part. Smth like:
- dataSource: accountsListAccountsDataSource
type: mutation
field: getNode
caching:
ttl: 200
keys: [context.argumtens.id, context.identity.sub]
evictions:
- updateNote
- deleteNote
substitutions:
....
That means that the functions updateNote. deleteNote
would evict this cache
Thanks for the insights.
I like the idea. I see several things we could try to do as you suggested.
- try to infer the caching keys from
caching
config
- dataSource: accountsListAccountsDataSource
type: Query
field: getNote
caching:
ttl: 200
keys: [context.argumtens.id, context.identity.sub]
evictions:
- updateNote
- deleteNote
This one can be tricky though because we cannot necessarily predict what part of $ctx.arguments
can be used.
e.g. updateNote
might receive the id from $ctx.arguments.note.id
if the updated note
is passed as an input object (this is a pattern I often use)
Trying to "guess" or use defaults might result in unexpected results.
The other way around sounds like a better approach in my opinion. But we might need a map because of the above-mentioned use-case. e.g.
- dataSource: accountsListAccountsDataSource
type: Mutation
field: updateNode
cachingEvictions:
- queryType: Query
function: getNote
cachingKeys:
context.argumtens.id: $ctx.arguments.note.id
context.identity.sub: $context.identity.sub
This way, we are being explicit about what needs to be edited and how. It's less of a "black box"
I am not sure though we'd need a "substitution" pattern like
${cachingEvictions}
We could inject it at the top or bottom of the response VTL. (but a way to override with an explicit placeholder could be useful)
I have no experience with cache eviction yet (I know what they are, I have just never used them yet).
I am wondering what would happen in case of resolvers errors.
e.g. if a mutation fails due to a DynamoDB update operation conditionExpression
or a Lambda resolver fails.
I would expect not to evict the cache. So maybe here the placeholder might make more sense after all to control that. Conditions will vary depending on use-case
#if($ctx.error && $ctx.error.type == "DynamoDB:ConditionalCheckFailedException")
$util.error(...)
#else
${cachingEvictions}
$util.toJson(...)
#end
Thoughts?
I have no experience with cache eviction yet (I know what they are, I have just never used them yet). I am wondering what would happen in case of resolvers errors. e.g. if a mutation fails due to a DynamoDB update operation
conditionExpression
or a Lambda resolver fails. I would expect not to evict the cache. So maybe here the placeholder might make more sense after all to control that. Conditions will vary depending on use-case
Yes, I also (like you said) think this highly depends on the use case. In some error cases it makes sense to evict the cache (e.q. persistent data changed) to avoid presenting old data to client due to cache, in other cases the underlying data has not changed (e.q. input data or AUTHZ validation failures). In those cases maybe the cache does not need to evicted.
Due to that reason my first idea was to give the developer the decide.
Maybe there is a better (more convenient) solution, but currently I think the substitution
way is the nicest way.
(Ofc the developer must know what she/he is doing :smiling_imp: )