0

我正在尝试针对本地模拟 pubsub 服务器使用Go pubsub 库。我发现“旧样式”(已弃用)函数(例如and )可以正常工作,但“新样式”API(例如and )无法按预期工作。CreateSubPullWaitIteratorsSubscriptionHandles

我编写了两个不同的单元测试,它们都测试相同的动作序列,一个使用“新风格”API,一个使用“旧风格”API。

顺序是:

  • 创建订阅
  • 无法提取任何消息(因为没有可用的消息)
  • 发布消息
  • 拉该消息,但不要确认它
  • 最后再拉一次,这需要 10 秒,因为消息 ACK 超时必须先过期

https://gist.github.com/ianrose14/db6ecd9ccb6c84c8b36bf49d93b11bfb

使用旧式 API 的测试正如我所期望的那样工作:

=== RUN   TestPubSubRereadLegacyForDemo
--- PASS: TestPubSubRereadLegacyForDemo (10.32s)
    pubsubintg_test.go:217: PullWait returned in 21.64236ms (expected 0)
    pubsubintg_test.go:228: PullWait returned in 10.048119558s (expected 10s)
PASS

而使用新型 API 的测试工作不可靠。有时事情会按预期工作:

=== RUN   TestPubSubRereadForDemo
--- PASS: TestPubSubRereadForDemo (11.38s)
    pubsubintg_test.go:149: iter.Next() returned in 17.686701ms (expected 0)
    pubsubintg_test.go:171: iter.Next() returned in 10.059492646s (expected 10s)
PASS

但有时我发现它iter.Stop()并没有像它应该的那样迅速返回(并注意第二个 iter.Next 比它应该长得多):

=== RUN   TestPubSubRereadForDemo
--- FAIL: TestPubSubRereadForDemo (23.87s)
    pubsubintg_test.go:149: iter.Next() returned in 7.3284ms (expected 0)
    pubsubintg_test.go:171: iter.Next() returned in 20.074994835s (expected 10s)
    pubsubintg_test.go:183: iter.Stop() took too long (2.475055901s)
FAIL

而其他时候我发现发布消息后的第一次拉取时间太长(它应该接近即时):

=== RUN   TestPubSubRereadForDemo
--- FAIL: TestPubSubRereadForDemo (6.32s)
    pubsubintg_test.go:147: failed to pull message from iterator: context deadline exceeded
FAIL

有任何想法吗?是否有任何使用新型 API 的工作示例?不幸的是,这里的 Go 入门项目使用了旧的、已弃用的 API。

4

1 回答 1

0

(注意:您的示例输出中的行号似乎与您链接的代码不匹配。)

但有时我发现 iter.Stop() 并没有像它应该的那样及时返回

最近发生了一些更改,这些更改修复了调用 iter.Stop 时的过度延迟。如果所有消息都已被确认,它现在应该立即返回。尝试同步并再次测试它。

(并注意第二个 iter.Next 比它应该长得多):

在您使用新 API 的代码中,您首先使用具有 1 秒截止日期的上下文从空订阅中拉取。我们称之为“拉取请求 A”。尽管取消了基础 http 请求,但似乎连接并没有以服务器尊重的任何方式关闭。因此,就服务器而言,“A”仍处于未决状态。发布后,您立即提出一个新的拉取请求,我们称之为“B”。在通过拉取请求 B 返回消息后,您不确认该消息,并发出另一个拉取请求“C”。

现在,当您发布消息时,服务器会将其传递给“A”或“B”。如果它首先将其交付给“A”,您将看到第一次拉取超过 5 秒上下文截止日期。如果它首先发布到“B”,您将看到第一个拉取快速返回,正如预期的那样。在消息发布到“B”并且未确认后,服务器会将其重新传递到“A”或“C”。如果它首先选择“A”,那么第二次拉动的时间将比预期的要长。如果它选择“C”,那么您将看到第一次和第二次拉动所花费的时间与您预期的一样长。

如果您没有从空订阅中进行初始拉取,您应该会看到您的测试行为符合您的预期。

Note: You don't see any of this when you use the old API because you're not doing the extra "pull from empty subscription" request with the old API (presumably because it doesn't properly support a cancellable context).

Aside: if you want to leave a message unacked, you should call Message.Done(false).

于 2016-04-04T05:41:28.960 回答