Go AppEngine 重复执行 http.handler 的部分代码。

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

Go AppEngine repeating partial execution of http.handler

问题

func init() {
http.HandleFunc("/", handler)
}

在handler函数中,有一段代码对数据列表进行迭代处理,并聚合结果。

假设对于给定的查询,有100个需要处理的项目。对于每个项目,我会在Appengine控制台中写入日志,"Item n has been processed"。

问题在于:

请求没有返回。日志消息只打印了前40个左右的项目,然后重复出现。它总是在相同的项目处停止,并重新开始。

我最好的猜测是应用程序达到了内存限制或其他原因,导致Appengine Go运行时重新启动并重新执行处理程序。

对于一个小的项目列表,处理按预期进行,日志中没有显示任何循环。

请求日志中没有错误,但另一个日志显示:

panic: poll_ctl

goroutine 3 [running]:
runtime/eventloop.(*pollServer).ctlfd(0x9035f8, 0x204100000005, 0x3, 0x2041, 0x0, ...)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:428 +0xdf
runtime/eventloop.(*pollServer).loop(0x9035f8, 0x0)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:411 +0x4d8
created by runtime/eventloop.init·1
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:232 +0x40

goroutine 1 [select (no cases)]:
appengine_internal/fd_transport.serveHTTP(0x7fff76502f58, 0x70615f2f00000002, 0x7fff76502f5b, 0x3, 0x7fff76502f6c, ...)
go/src/pkg/appengine_internal/fd_transport/fd_transport.go:44 +0x26b
appengine_internal.Main()
go/src/pkg/appengine_internal/internal.go:184 +0x1a8
main.main()
_go_main.go:16 +0x18

goroutine 2 [select]:
created by _
_.go:568 +0xd2

goroutine 10 [chan receive]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095a60, 0xf84011ac30, 0xb, 0x1, ...)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).ReadFrom(0xf840095a50, 0xf840138000, 0x7d0000007d0, 0xf800000000, 0x0, ...)
go/src/pkg/runtime/eventloop/fd.go:135 +0x1c2
created by _
_.go:144 +0x7a

goroutine 5 [chan receive]:
created by _
_.go:461 +0x3ca

goroutine 6 [semacquire]:
sync.runtime_Semacquire(0xf8408034d8, 0xf8408034d8)
go/src/pkg/runtime/zsema_amd64.c:146 +0x25
sync.(*Cond).Wait(0xf840096bb0, 0x1)
go/src/pkg/sync/cond.go:67 +0xaa
created by _
_.go:462 +0x3e1

goroutine 7 [chan receive]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095c70, 0xf84011ac30, 0xb, 0x1, ...)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Read(0xf840095c60, 0xf84113a000, 0x972a80000000c, 0x2b5800000000, 0xf84011ac30, ...)
go/src/pkg/runtime/eventloop/fd.go:93 +0x18c
io.ReadAtLeast(0xf84012c0c0, 0xf840095c60, 0xf84113a000, 0x972a80000000c, 0x2b580000000c, ...)
go/src/pkg/io/io.go:254 +0xc3
io.ReadFull(0xf84012c0c0, 0xf840095c60, 0xf84113a000, 0x972a80000000c, 0xf840095c60, ...)
go/src/pkg/io/io.go:273 +0x69
created by _
_.go:845 +0x2c6

goroutine 11 [runnable]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095b10, 0xf84011ac30, 0xb, 0x1, ...)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Accept(0xf840095b00, 0x0, 0x0, 0xf84011ac30, 0xb, ...)
go/src/pkg/runtime/eventloop/fd.go:72 +0x185
net/http.(*Server).Serve(0xf840129f00, 0xf8400cfa80, 0xf840095b00, 0x0, 0x0, ...)
go/src/pkg/net/http/server.go:1012 +0x88
net/http.Serve(0xf8400cfa80, 0xf840095b00, 0xf84012c090, 0xf8400e0b10, 0xf8400e0b10, ...)
go/src/pkg/net/http/server.go:977 +0x71
created by _
_.go:145 +0xe9

goroutine 12 [timer goroutine (idle)]:
created by addtimer
go/src/pkg/runtime/ztime_amd64.c:70

goroutine 13 [runnable]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf8400959b0, 0xf84011ac30, 0xb, 0x1, ...)
go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Read(0xf8400959a0, 0xf840139000, 0x100000001000, 0x0, 0xf84011ac30, ...)
go/src/pkg/runtime/eventloop/fd.go:93 +0x18c
io.(*LimitedReader).Read(0xf840123580, 0xf840139000, 0x100000001000, 0xf8900000000, 0x0, ...)
go/src/pkg/io/io.go:394 +0xc1
bufio.(*Reader).fill(0xf840129f80, 0x2b5853e92000)
go/src/pkg/bufio/bufio.go:77 +0xf0
bufio.(*Reader).Read(0xf840129f80, 0xf84013d000, 0x27100000000c, 0xc, 0x0, ...)
go/src/pkg/bufio/bufio.go:142 +0x188
io.ReadAtLeast(0xf84012c600, 0xf84012c570, 0xf84013d000, 0x27100000000c, 0xc, ...)
go/src/pkg/io/io.go:254 +0xc3
io.ReadFull(0xf84012c600, 0xf84012c570, 0xf84013d000, 0x27100000000c, 0xf84012c570, ...)
go/src/pkg/io/io.go:273 +0x69
net/http.(*conn).serve(0xf8401320c0, 0x0)
go/src/pkg/net/http/server.go:656 +0x621
created by net/http.(*Server).Serve
go/src/pkg/net/http/server.go:1040 +0x430

goroutine 59 [sleep]:
time.Sleep(0x5dfdee1, 0xf8408034d0)
go/src/pkg/runtime/ztime_amd64.c:22 +0x49
created by _
_.go:791 +0xc4

goroutine 15 [chan receive]:

也许我没有记录所有的错误,但即使如此,是什么导致了循环?

更新
无休止的循环迅速耗尽了我的数据存储写入配额,现在我得到了一个无引号错误,这个错误被记录下来。在错误日志之后,处理程序被再次调用,一次又一次...

func handleError(w http.ResponseWriter, c appengine.Context, err error) {
c.Infof("ERROR")
c.Errorf("ERROR datastore: %s", err.Error())
}

...
rk, err := datastore.Put(c, rk, e)
if err != nil {
handleError(w, c, err)
return
}

更新2
切换到f4实例后,代码按预期运行。我仍然认为Appengine Go运行时由于某种原因(内存)默默失败,并重新启动处理程序执行。这是我最好的猜测,我不知道确切原因。

英文:
func init() {
	http.HandleFunc("/", handler)
}

In the handler function there is code iterating over a list of data, processing it, and aggregating a results.

Lets say for a given query there are 100 items that need to be processed. For each item I write log to the Appengine console, "Item n has been processed".

Here is the problem:

The request does not return. The log message for the first 40 or so items, and then it repeats, and repeats. It always stops are the same item, and restarts.

My best guess is that the app is hitting a memory limit or something, and the Appengine Go runtime is just restarting, and re-executing the handler.

For a small list of items, processing goes as expected, and the logs don't show any looping.

There are no errors in the request log, but another log shows:

panic: poll_ctl

goroutine 3 [running]:
runtime/eventloop.(*pollServer).ctlfd(0x9035f8, 0x204100000005, 0x3, 0x2041, 0x0, ...)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:428 +0xdf
runtime/eventloop.(*pollServer).loop(0x9035f8, 0x0)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:411 +0x4d8
created by runtime/eventloop.init·1
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:232 +0x40

goroutine 1 [select (no cases)]:
appengine_internal/fd_transport.serveHTTP(0x7fff76502f58, 0x70615f2f00000002, 0x7fff76502f5b, 0x3, 0x7fff76502f6c, ...)
	go/src/pkg/appengine_internal/fd_transport/fd_transport.go:44 +0x26b
appengine_internal.Main()
	go/src/pkg/appengine_internal/internal.go:184 +0x1a8
main.main()
	_go_main.go:16 +0x18

goroutine 2 [select]:
created by _
	_.go:568 +0xd2

goroutine 10 [chan receive]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095a60, 0xf84011ac30, 0xb, 0x1, ...)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).ReadFrom(0xf840095a50, 0xf840138000, 0x7d0000007d0, 0xf800000000, 0x0, ...)
	go/src/pkg/runtime/eventloop/fd.go:135 +0x1c2
created by _
	_.go:144 +0x7a

goroutine 5 [chan receive]:
created by _
	_.go:461 +0x3ca

goroutine 6 [semacquire]:
sync.runtime_Semacquire(0xf8408034d8, 0xf8408034d8)
	go/src/pkg/runtime/zsema_amd64.c:146 +0x25
sync.(*Cond).Wait(0xf840096bb0, 0x1)
	go/src/pkg/sync/cond.go:67 +0xaa
created by _
	_.go:462 +0x3e1

goroutine 7 [chan receive]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095c70, 0xf84011ac30, 0xb, 0x1, ...)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Read(0xf840095c60, 0xf84113a000, 0x972a80000000c, 0x2b5800000000, 0xf84011ac30, ...)
	go/src/pkg/runtime/eventloop/fd.go:93 +0x18c
io.ReadAtLeast(0xf84012c0c0, 0xf840095c60, 0xf84113a000, 0x972a80000000c, 0x2b580000000c, ...)
	go/src/pkg/io/io.go:254 +0xc3
io.ReadFull(0xf84012c0c0, 0xf840095c60, 0xf84113a000, 0x972a80000000c, 0xf840095c60, ...)
	go/src/pkg/io/io.go:273 +0x69
created by _
	_.go:845 +0x2c6

goroutine 11 [runnable]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf840095b10, 0xf84011ac30, 0xb, 0x1, ...)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Accept(0xf840095b00, 0x0, 0x0, 0xf84011ac30, 0xb, ...)
	go/src/pkg/runtime/eventloop/fd.go:72 +0x185
net/http.(*Server).Serve(0xf840129f00, 0xf8400cfa80, 0xf840095b00, 0x0, 0x0, ...)
	go/src/pkg/net/http/server.go:1012 +0x88
net/http.Serve(0xf8400cfa80, 0xf840095b00, 0xf84012c090, 0xf8400e0b10, 0xf8400e0b10, ...)
	go/src/pkg/net/http/server.go:977 +0x71
created by _
	_.go:145 +0xe9

goroutine 12 [timer goroutine (idle)]:
created by addtimer
	go/src/pkg/runtime/ztime_amd64.c:70

goroutine 13 [runnable]:
runtime/eventloop.(*pollServer).wait(0x9035f8, 0xf8400959b0, 0xf84011ac30, 0xb, 0x1, ...)
	go/src/pkg/runtime/eventloop/poll_linux_amd64.go:472 +0x1a7
runtime/eventloop.(*FD).Read(0xf8400959a0, 0xf840139000, 0x100000001000, 0x0, 0xf84011ac30, ...)
	go/src/pkg/runtime/eventloop/fd.go:93 +0x18c
io.(*LimitedReader).Read(0xf840123580, 0xf840139000, 0x100000001000, 0xf8900000000, 0x0, ...)
	go/src/pkg/io/io.go:394 +0xc1
bufio.(*Reader).fill(0xf840129f80, 0x2b5853e92000)
	go/src/pkg/bufio/bufio.go:77 +0xf0
bufio.(*Reader).Read(0xf840129f80, 0xf84013d000, 0x27100000000c, 0xc, 0x0, ...)
	go/src/pkg/bufio/bufio.go:142 +0x188
io.ReadAtLeast(0xf84012c600, 0xf84012c570, 0xf84013d000, 0x27100000000c, 0xc, ...)
	go/src/pkg/io/io.go:254 +0xc3
io.ReadFull(0xf84012c600, 0xf84012c570, 0xf84013d000, 0x27100000000c, 0xf84012c570, ...)
	go/src/pkg/io/io.go:273 +0x69
net/http.(*conn).serve(0xf8401320c0, 0x0)
	go/src/pkg/net/http/server.go:656 +0x621
created by net/http.(*Server).Serve
	go/src/pkg/net/http/server.go:1040 +0x430

goroutine 59 [sleep]:
time.Sleep(0x5dfdee1, 0xf8408034d0)
	go/src/pkg/runtime/ztime_amd64.c:22 +0x49
created by _
	_.go:791 +0xc4

goroutine 15 [chan receive]:

Maybe I'm not logging all the errors, but even if, what could cause the looping?

Update
The near-endless-looping quickly drained my datastore write quota, now I'm getting a no-quote error, which is being logged. After the Error logs the handler is invoked again. and again....

func handleError(w http.ResponseWriter, c appengine.Context, err error) {
	c.Infof("ERROR")
	c.Errorf("ERROR datastore: %s", err.Error())
}


...
rk, err := datastore.Put(c, rk, e)
if err != nil {
	handleError(w, c, err)
	return
}

UPDATE 2
After switching to an f4 instance the code runs as expected. I still think the Appengine Go run time is silently failing for some reason, (memory), and restarting the handler execution. Thats my best guess, I have no idea.

答案1

得分: 1

有一个30秒的超时时间限制用于http请求。在您切换到更快的实例之前,进程是否需要那么长时间?您可以使用后端进程来进行长时间处理。https://developers.google.com/appengine/docs/go/backends/overview

英文:

There is a 30 second timeout for http requests. Were the processes taking that long before you moved to a faster instance? You could use a backend process to do long-lived processing. https://developers.google.com/appengine/docs/go/backends/overview

huangapple
  • 本文由 发表于 2012年4月16日 03:37:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/10165376.html
匿名

发表评论

匿名网友

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

确定