基于位置的 AWS AppSync 事件订阅

AWS AppSync Event Subscription based on Location

我了解如何通过 AppSync 执行地理空间查询,通过附加链接到 ElasticSesarch 的解析器来查找距 gps 坐标一定距离范围内的事件,如 described here

但是,如果我希望我的客户也订阅在此距离范围内创建的新事件怎么办?

  1. 用户订阅了一个位置
  2. 如果在该位置附近创建了事件,请通知用户

我知道我可以将解析器附加到订阅类型,但当我只想通过检查 gps 坐标之间的距离来过滤订阅时,它似乎强制你提供数据源。

这是一个很好的问题,我认为有几种方法可以解决这个问题。这里最困难的部分是您将找到一种提出问题 "What subscriptions are interested in an event at this location" 的方法。这是一条可能的前进道路。

以下假定这些架构部分:

// Whatever custom object has a location 
type Post {
  id: ID!
  title: String
  location: Location
}
input PublishPostInput {
  id: ID!
  title: String
  location: Location
  subscriptionID: ID
}
type PublishPostOutput {
  id: ID!
  title: String
  location: Location
  subscriptionID: ID
}

type Location {
  lat: Float,
  lon: Float
}
input LocationInput {
  lat: Float,
  lon: Float
}

# A custom type to hold custom tracked subscription information
# for location discover
type OpenSubscription {
  subscriptionID: ID!
  location: Location
  timestamp: String!
}
type OpenSubscriptionConnection {
  items: [OpenSubscription]
  nextToken: String
}

type Query {
  # Query elasticsearch index for relevant subscriptions
  openSubscriptionsNear(location: LocationInput, distance: String): OpenSubscriptionConnection
}
type Mutation {
  # This mutation uses a local resolver (e.g. a resolver with a None data source) and simply returns the input as is.
  publishPostToSubscription(input: PublishPostInput): PublishPostOutput
}
type Subscription {
  # Anytime someone passes an object with the same subscriptionID to the "publishPostToSubscription" mutation field, get updated.
  listenToSubscription(subscriptionID: ID!): PublishPostOutput
    @aws_subscribe(mutations:["publishPostToSubscription"])
}

假设您使用 DynamoDB 作为主要的真实来源,请设置调用 "PublishIfInRange" lambda 函数的 DynamoDB 流。 "PublishIfInRange" 函数看起来像这样

// event - { location: { lat, lon }, id, title, ... }
function lambdaHandler(event) {

  const relevantSubscriptions = await callGraphql(`
    query GetSubscriptions($location: LocationInput) {
      openSubscriptionsNear(location:$location, distance: "10 miles") {
        subscriptionID
      }
    }
  `, { variables: { location: event.location }})

  for (const subscription of relevantSubscriptions) {
    callGraphql(`
      mutation PublishToSubscription($subID: ID!, $obj: PublishPostInput) {
        publishPostToSubscription(input: $obj) {
          id
          title
          location { lat lon }
          subscriptionID
        }
      }
    `, { variables: { input: { ...subscription, ...event }}})
  }
}

您需要维护按位置索引的订阅注册表。一种方法是让您的客户端应用程序调用一个 mutation,该 mutation 创建一个具有位置和 subscriptionID 的订阅对象(例如 mutation { makeSubscription(loc: $loc) { ... } } 假设您正在使用 $util.autoId() 在解析器中生成 subscriptionID ).获得 subscriptionID 后,您可以通过 graphql 进行订阅调用,并将 subscriptionID 作为参数传入(例如 subscription { listenToSubscription(subscriptionID: "my-id") { id title location { lat lon } } })。当您进行上述订阅调用时,AppSync 会创建一个主题并授权当前用户订阅该主题。该主题对于被调用的订阅字段和传递给订阅字段的参数集是唯一的。也就是说topic只接收objects

现在,无论何时创建对象,记录都会通过 DynamoDB 流进入 lambda 函数。 lambda 函数在 elasticsearch 中查询该对象附近的所有开放订阅,然后向每个开放订阅发布一条记录。

我相信这应该会让你走得更远,但如果你在狭小的空间内拥有数百万用户,你可能 运行 会遇到扩展问题。希望这有帮助