Search code examples
aws-lambdaamazon-dynamodbgraphqlamazon-dynamodb-streamsaws-appsync

AWS AppSync wait for DynamoDB Streams Lambda function before resolving sub-resource


I have GraphQL schema similar to the following. There are multiple Alphas in a single Bravo, and they each have a reference to each other. (A Bravo can get its Alphas, and an Alpha can get its Bravo.)

type Alpha {
  id: ID!
  value: Int!
  bravo: Bravo!
}

type Bravo {
  value: Int!
  alphas: [Alpha!]!
}

input InputAlpha {
  value: Int!
}

type Mutation {
  putAlpha(alpha: InputAlpha): Alpha!
}

schema {
  mutation: Mutation
}

As you can tell, both types have a value. The value of Alpha is arbitrary, but the value of Bravo is the sum of its associated Alphas. For performance (and cost) reasons, the Bravo's value is cached in the DynamoDB table and modified whenever an Alpha is updated.

Alphas are updated with a simple AppSync DynamoDB PutItem resolver, with the intention being that the value of its Bravo would be updated by a Lambda function watching the table's stream. This works well for the most part; I can put Alphas with random values, and I can get the value of their Bravo.

The problem occurs when I try to request the value of the Bravo in the same request. (The Lambda function takes some time to update it from the stream.)

mutation putAlpha {
  putAlpha(alpha: {
      value: 10
  }) {
    id
    value
    bravo {
      value
    }
  }
}

Naturally this returns the old cached value of bravo, because the Lambda function hasn't been run by the time the Bravo is resolved.

Is there any way to wait until the DynamoDB stream's Lambda function has fired before resolving bravo or perhaps make the PutItem operation synchronous?

The only alternative I can think of is to make the putAlpha resolver a Lambda function instead of a simple resolver and do the Bravo updating logic in there.

Is this kind of Lambda continuously updating a cache value normal, or am I doing something wrong?


Solution

  • I think that your client should be aware that Bravo's value is calculated in the background. If that's not a tradeoff that you can make, consider moving Bravo's update logic to putAlpha mutation. (To avoid race conditions you can use UpdateExpression's ADD action.)

    One way would be to update Bravo's value through you API in your stream and subscribe to Bravo's updates in your client. It is possible to run aws-appsync in Lambda though you need to provide window, xhr etc.

    Couple of other ways:

    1. You can increase Bravo's value in client's cache instead of taking it from putAlpha's response.
    2. You can retrieve Bravo's value once it's updated. (It will probably be updated after some seconds. Perhaps you have a way to verify if this Alpha was applied to Bravo, storing last Alpha's update time to Bravo could work.)