Graphql Apollo服务器订阅无法识别异步Iterable

Graphql Apollo服务器订阅无法识别异步Iterable,graphql,apollo,publish-subscribe,Graphql,Apollo,Publish Subscribe,我对Apollo GraphQL的订阅有意见。尝试启动订阅时,我得到的回报是: "Subscription field must return Async Iterable. Received: { pubsub: { ee: [EventEmitter], subscriptions: {}, subIdCounter: 0 }, pullQueue: [], pushQueue: [], running: true, allSubscribed: null, eventsArray: [\"

我对Apollo GraphQL的订阅有意见。尝试启动订阅时,我得到的回报是:

"Subscription field must return Async Iterable. Received: { pubsub: { ee: [EventEmitter], subscriptions: {}, subIdCounter: 0 }, pullQueue: [], pushQueue: [], running: true, allSubscribed: null, eventsArray: [\"H-f_mUvS\"], return: [function return] }"
我已经设置了其他订阅,并且完全可以正常工作-因此我可以确认Web服务器的设置是否正确

我只是好奇以前是否有人碰到过这个问题

PR diff中的源代码(这是一个开源项目):


我不认为这是你发布的公关中特有的问题。如果有订阅按原样运行,我会感到惊讶

如错误所述,
subscribe
函数应返回一个AsyncIterable。由于它返回对
createPoller
的调用,
createPoller
应该返回一个AsyncIterable。但这个函数是这样的:

export default function createPoller(
  func,
  pubsub,
  interval = 5000, // Poll every 5 seconds
  timeout = 3600000 // Kill after 1 hour
) {
  // Gernate a random internal topic.
  const topic = shortid.generate();

  // Create an async iterator. This is what a subscription resolver expects to be returned.
  const iterator = pubsub.asyncIterator(topic);

  // Wrap the publish function on the pubsub object, pre-populating the topic.
  const publish = bind(curry(pubsub.publish, 2)(topic), pubsub);

  // Call the function once to get initial dataset.
  func(publish);

  // Then set up a timer to call the passed function. This is the poller.
  const poll = setInterval(partial(func, publish), interval);

  // If we are passed a timeout, kill subscription after that interval has passed.
  const kill = setTimeout(iterator.return, timeout);

  // Create a typical async iterator, but overwrite the return function
  // and cancel the timer. The return function gets called by the apollo server
  // when a subscription is cancelled.
  return {
    ...iterator,
    return: () => {
      log.info(`Disconnecting subscription ${topic}`);
      clearInterval(poll);
      clearTimeout(kill);
      return iterator.return();
    }
  };
}
因此,
createPoller
创建了一个AsyncIterable,但随后创建了它的浅层副本并返回该副本
graphql订阅
使用
iterall
isacynciiterable
检查是否产生了您看到的错误。由于
是可同步的
的方式,浅层拷贝不会飞行。您可以亲自看到这一点:

const { PubSub } = require('graphql-subscriptions')
const { isAsyncIterable } = require('iterall')

const pubSub = new PubSub()
const iterable = pubSub.asyncIterator('test')
const copy = { ...iterable }
console.log(isAsyncIterable(iterable)) // true
console.log(isAsyncIterable(copy)) // false
因此,与其返回浅拷贝,
createPoller
应该直接变异
return
方法:

export default function createPoller(...) {
  ...
  iterator.return = () => { ... }

  return iterator
}

我不认为这是一个特定于你发布的公关的问题。如果有订阅按原样运行,我会感到惊讶

如错误所述,
subscribe
函数应返回一个AsyncIterable。由于它返回对
createPoller
的调用,
createPoller
应该返回一个AsyncIterable。但这个函数是这样的:

export default function createPoller(
  func,
  pubsub,
  interval = 5000, // Poll every 5 seconds
  timeout = 3600000 // Kill after 1 hour
) {
  // Gernate a random internal topic.
  const topic = shortid.generate();

  // Create an async iterator. This is what a subscription resolver expects to be returned.
  const iterator = pubsub.asyncIterator(topic);

  // Wrap the publish function on the pubsub object, pre-populating the topic.
  const publish = bind(curry(pubsub.publish, 2)(topic), pubsub);

  // Call the function once to get initial dataset.
  func(publish);

  // Then set up a timer to call the passed function. This is the poller.
  const poll = setInterval(partial(func, publish), interval);

  // If we are passed a timeout, kill subscription after that interval has passed.
  const kill = setTimeout(iterator.return, timeout);

  // Create a typical async iterator, but overwrite the return function
  // and cancel the timer. The return function gets called by the apollo server
  // when a subscription is cancelled.
  return {
    ...iterator,
    return: () => {
      log.info(`Disconnecting subscription ${topic}`);
      clearInterval(poll);
      clearTimeout(kill);
      return iterator.return();
    }
  };
}
因此,
createPoller
创建了一个AsyncIterable,但随后创建了它的浅层副本并返回该副本
graphql订阅
使用
iterall
isacynciiterable
检查是否产生了您看到的错误。由于
是可同步的
的方式,浅层拷贝不会飞行。您可以亲自看到这一点:

const { PubSub } = require('graphql-subscriptions')
const { isAsyncIterable } = require('iterall')

const pubSub = new PubSub()
const iterable = pubSub.asyncIterator('test')
const copy = { ...iterable }
console.log(isAsyncIterable(iterable)) // true
console.log(isAsyncIterable(copy)) // false
因此,与其返回浅拷贝,
createPoller
应该直接变异
return
方法:

export default function createPoller(...) {
  ...
  iterator.return = () => { ... }

  return iterator
}

你能用相关的解析器代码更新你的问题吗?我添加了一个链接到我打开的PR,显示了导致问题的相关代码。它非常复杂,如果没有完整的上下文,可能没有完全的意义。你能用相关的解析器代码更新你的问题吗?我添加了一个到PR的链接,我有一个开头,显示了导致问题的相关代码。它非常复杂,如果没有完整的背景,它可能不完全有意义。非常好的回答,谢谢你花时间来解决这个问题。非常感谢!!非常好的回答,谢谢你花时间来解决这个问题。非常感谢!!