“新样式”谷歌PubSub Golang函数无法正常工作。

huangapple go评论92阅读模式
英文:

"new style" google pubsub golang functions not working right

问题

我正在尝试使用Go pubsub库本地模拟的pubsub服务器进行交互。我发现“旧风格”(已弃用)的函数(例如CreateSubPullWait)可以正常工作,但“新风格”API(例如IteratorsSubscriptionHandles)不按预期工作。

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

操作序列如下:

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

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

使用旧风格API的测试结果符合我的预期:

=== RUN   TestPubSubRereadLegacyForDemo
--- PASS: TestPubSubRereadLegacyForDemo (10.32s)
	pubsubintg_test.go:217: PullWait返回时间为21.64236毫秒(预期为0)
	pubsubintg_test.go:228: PullWait返回时间为10.048119558秒(预期为10秒)
PASS

而使用新风格API的测试结果不可靠。有时候按预期工作:

=== RUN   TestPubSubRereadForDemo
--- PASS: TestPubSubRereadForDemo (11.38s)
	pubsubintg_test.go:149: iter.Next()返回时间为17.686701毫秒(预期为0)
	pubsubintg_test.go:171: iter.Next()返回时间为10.059492646秒(预期为10秒)
PASS

但有时候我发现iter.Stop()没有及时返回(注意第二个iter.Next花费的时间比预期长得多):

=== RUN   TestPubSubRereadForDemo
--- FAIL: TestPubSubRereadForDemo (23.87s)
	pubsubintg_test.go:149: iter.Next()返回时间为7.3284毫秒(预期为0)
	pubsubintg_test.go:171: iter.Next()返回时间为20.074994835秒(预期为10秒)
	pubsubintg_test.go:183: iter.Stop()花费时间过长(2.475055901秒)
FAIL

还有时候,我发现发布消息后的第一次拉取花费的时间太长(应该几乎是即时的):

=== RUN   TestPubSubRereadForDemo
--- FAIL: TestPubSubRereadForDemo (6.32s)
	pubsubintg_test.go:147: 无法从迭代器中拉取消息:上下文超时
FAIL

有什么想法吗?是否有使用新风格API的可行示例?不幸的是,这里的Go入门项目使用的是旧的已弃用API。

英文:

I'm trying to use the Go pubsub library against the local emulated pubsub server. I'm finding that the "old style" (deprecated) functions (e.g. CreateSub and PullWait) work find, but the "new style" API (e.g. Iterators and SubscriptionHandles) does not work as expected.

I've written two different unit tests that both test the same sequence of actions, one using the "new style" API and one using the "old style" API.

The sequence is:

  • create a subscription
  • fail to pull any messages (since none available)
  • publish a message
  • pull that message, but don't ACK it
  • lastly pull it again which should take 10s since the message ACK timeout has to expire first

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

The test using the old-style API works just as I would expect:

=== 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

Whereas the test using the new-style API works unreliably. Sometimes things work as expected:

=== 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

But sometimes I find that iter.Stop() doesn't return promptly as it should (and note how the second iter.Next too way longer than it should):

=== 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

And other times I find that the first Pull after publishing the message takes too long (it should be near instant):

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

Any ideas? Are there any working examples using the new-style API? Unfortunately, the Go starter project here uses the old, deprecated API.

答案1

得分: 0

(注意:你提供的示例输出中的行号与你提供的代码不匹配。)

最近有一些变化,修复了调用iter.Stop时出现的过长延迟问题。如果所有消息都已确认,现在它应该会立即返回。请尝试同步并再次测试。

在你使用新API的代码中,首先使用具有1秒截止时间的上下文从空订阅中进行拉取。让我们称之为“拉取请求A”。尽管底层的HTTP请求被取消了,但似乎连接并没有以服务器尊重的任何方式关闭。因此,就服务器而言,“A”仍然是未决的。在发布消息后,你会发起一个新的拉取请求,我们称之为“B”。在通过拉取请求B返回消息后,你将消息保持未确认状态,并发起另一个拉取请求“C”。

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

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

注意:当你使用旧的API时,你不会看到任何这些情况,因为你没有使用旧的API进行额外的“从空订阅中拉取”的请求(可能是因为它不正确地支持可取消的上下文)。

另外:如果你想将消息保持未确认状态,你应该调用Message.Done(false)。

英文:

(Note: It looks like the line numbers in your example output don't match the code that you've linked.)

> But sometimes I find that iter.Stop() doesn't return promptly as it should

A few changes have landed recently which fix the excessive delay when calling iter.Stop. It should now return promptly if all messages have been acked. Try syncing and testing it out again.

> (and note how the second iter.Next too way longer than it should):

In you code that uses the new API, you first do a pull from an empty subscription, using a context with a 1s deadline. Let's call this "Pull request A". Although the underlying http request is cancelled, it seems that the connection is not being closed in any way that the server respects. So, as far as the server is concerned, "A" is still pending. Immediately after publishing, you make a new pull request, let's call that "B". After a message is returned via pull request B, you leave the message unacked, and make another pull request, "C".

Now, when you publish the message, the server will deliver it to either "A" or "B". If it delivers it to "A" first, you will see the first pull exceeding the 5s context deadline. If it is published to "B" first, you will see the first pull returning quickly, as expected. After the message is published to "B", and left unacked, the server will redeliver it to "A", or "C". If it picks "A" first, then you will end up with the second pull taking longer than expected. If it picks "C", then you will see both first and second pulls taking as long as you expect.

If you don't do that initial pull from the empty subscription, you should see your test behave as you expect.

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).

huangapple
  • 本文由 发表于 2016年4月2日 04:18:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/36365159.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定