GAE 推送队列任务不会 运行 在测试中生成孤立的 dev_appserver 进程
GAE push queue tasks don't run in tests, spawn orphaned dev_appserver processes
我注意到我的任务工作人员从未 运行 在测试中,并且 enqueue/dequeue 逻辑在测试中几乎完全解耦,这使我无法验证任务是否正确排队。
考虑以下最小示例:
app.yaml:
runtime: go
api_version: go1
handlers:
- url: /worker/.*
script: _go_app
login: admin
- url: /.*
script: _go_app
worker/settle.go (package worker
)
func SettleWorker(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
log.Infof(ctx, "Worker was successfully invoked")
}
service/main.go (package service
)
func TestHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
t := taskqueue.NewPOSTTask("/worker/wrongpath", map[string][]string{"name": {"BLAH"}})
task, err := taskqueue.Add(ctx, t, "")
if err != nil {
http.Error(w, "Error", http.StatusBadRequest)
return
}
log.Infof(ctx, "Successfully posted task to worker: %+v", task)
}
func init() {
http.HandleFunc("/worker/settle", worker.SettleWorker)
http.HandleFunc("/test", TestHandler)
}
service/main_test.go (package service_test
)
func TestTestHandler(t *testing.T) {
inst, err := aetest.NewInstance(nil)
if err != nil {
t.Fatal(err.Error())
}
req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err.Error())
}
resp := httptest.NewRecorder()
http.HandlerFunc(service.TestHandler).ServeHTTP(resp, req)
}
请注意,传递给 taskqueue.Add ("/worker/wrongpath"
) 的路径实际上并没有注册的处理程序。乍一看,当我使用 goapp test bitwyrm/service -v
对此进行测试时,这似乎不会导致任何问题,但工作人员实际上并没有 运行。我看到了快乐的日志语句,并且从 TestHandler 返回了状态代码 200,但是没有出现来自 SettleWorker 的日志语句。
如果路径正确(即设置为“/worker/settle”),同样的事情也会发生。所以我无法编写测试来断言测试已正确入队。
更糟糕的是,出于某种原因 运行 宁此测试还会留下一个孤立的 dev_appserver.py 进程(无论使用哪条路径)。 运行 这反复最终用孤立的测试进程填满了我的计算机,最终导致通过 goapp test
调用的开发服务器 运行 进入数据库锁定问题,这意味着我不能 运行 我的测试套件没有手动杀死所有孤立的测试进程。典型的堆栈跟踪:
...successful test output...
INFO 2018-05-04 09:02:10,762 stub_util.py:357] Applying all pending transactions and saving the datastore
INFO 2018-05-04 09:02:13,827 stub_util.py:360] Saving search indexes
Exception in thread Thread-1:
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2182, in MainLoop
self._ProcessQueues()
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2127, in _ProcessQueues
response_code = self.task_executor.ExecuteTask(task, queue)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2059, in ExecuteTask
'0.1.0.2')
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/dispatcher.py", line 776, in add_request
inst)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/dispatcher.py", line 862, in _handle_request
request_type=request_type)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/module.py", line 818, in _handle_request
module=self._module_configuration.module_name)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/apiproxy_stub.py", line 186, in WrappedMethod
return method(self, *args, **kwargs)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/logservice/logservice_stub.py", line 181, in start_request
host, start_time, method, resource, http_version, module))
OperationalError: database is locked
请注意,这一切似乎在测试之外工作正常 - 当我使用 Paw 和 dev_appserver.py 在开发中点击此 http 处理程序时,正确的路径确实触发了工作程序,而错误的路径看到了 403 的日志记录一系列重试的响应(您期望的两种行为)。
我已经花了足够多的时间尝试调试它,所以我假设它是 dev_appserver.py
或 aetest
中的一个实际错误,但我坚信要确保它不是在归咎于工具之前应用程序的错误。我在这里做错了什么很明显吗?
我应该知道 "phantom" 进程的创建 - 事实证明我只是忘记在我创建的 aetest.Instance
上调用 Close()
。
实例化错误检查后的以下行为我修复了问题:
defer inst.Close()
我注意到我的任务工作人员从未 运行 在测试中,并且 enqueue/dequeue 逻辑在测试中几乎完全解耦,这使我无法验证任务是否正确排队。
考虑以下最小示例:
app.yaml:
runtime: go
api_version: go1
handlers:
- url: /worker/.*
script: _go_app
login: admin
- url: /.*
script: _go_app
worker/settle.go (package worker
)
func SettleWorker(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
log.Infof(ctx, "Worker was successfully invoked")
}
service/main.go (package service
)
func TestHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
t := taskqueue.NewPOSTTask("/worker/wrongpath", map[string][]string{"name": {"BLAH"}})
task, err := taskqueue.Add(ctx, t, "")
if err != nil {
http.Error(w, "Error", http.StatusBadRequest)
return
}
log.Infof(ctx, "Successfully posted task to worker: %+v", task)
}
func init() {
http.HandleFunc("/worker/settle", worker.SettleWorker)
http.HandleFunc("/test", TestHandler)
}
service/main_test.go (package service_test
)
func TestTestHandler(t *testing.T) {
inst, err := aetest.NewInstance(nil)
if err != nil {
t.Fatal(err.Error())
}
req, err := inst.NewRequest("GET", "/", nil)
if err != nil {
t.Fatal(err.Error())
}
resp := httptest.NewRecorder()
http.HandlerFunc(service.TestHandler).ServeHTTP(resp, req)
}
请注意,传递给 taskqueue.Add ("/worker/wrongpath"
) 的路径实际上并没有注册的处理程序。乍一看,当我使用 goapp test bitwyrm/service -v
对此进行测试时,这似乎不会导致任何问题,但工作人员实际上并没有 运行。我看到了快乐的日志语句,并且从 TestHandler 返回了状态代码 200,但是没有出现来自 SettleWorker 的日志语句。
如果路径正确(即设置为“/worker/settle”),同样的事情也会发生。所以我无法编写测试来断言测试已正确入队。
更糟糕的是,出于某种原因 运行 宁此测试还会留下一个孤立的 dev_appserver.py 进程(无论使用哪条路径)。 运行 这反复最终用孤立的测试进程填满了我的计算机,最终导致通过 goapp test
调用的开发服务器 运行 进入数据库锁定问题,这意味着我不能 运行 我的测试套件没有手动杀死所有孤立的测试进程。典型的堆栈跟踪:
...successful test output...
INFO 2018-05-04 09:02:10,762 stub_util.py:357] Applying all pending transactions and saving the datastore
INFO 2018-05-04 09:02:13,827 stub_util.py:360] Saving search indexes
Exception in thread Thread-1:
Traceback (most recent call last):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2182, in MainLoop
self._ProcessQueues()
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2127, in _ProcessQueues
response_code = self.task_executor.ExecuteTask(task, queue)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/taskqueue/taskqueue_stub.py", line 2059, in ExecuteTask
'0.1.0.2')
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/dispatcher.py", line 776, in add_request
inst)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/dispatcher.py", line 862, in _handle_request
request_type=request_type)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/module.py", line 818, in _handle_request
module=self._module_configuration.module_name)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/apiproxy_stub.py", line 186, in WrappedMethod
return method(self, *args, **kwargs)
File "/Users/ursa/Code/google-cloud-sdk/platform/google_appengine/google/appengine/api/logservice/logservice_stub.py", line 181, in start_request
host, start_time, method, resource, http_version, module))
OperationalError: database is locked
请注意,这一切似乎在测试之外工作正常 - 当我使用 Paw 和 dev_appserver.py 在开发中点击此 http 处理程序时,正确的路径确实触发了工作程序,而错误的路径看到了 403 的日志记录一系列重试的响应(您期望的两种行为)。
我已经花了足够多的时间尝试调试它,所以我假设它是 dev_appserver.py
或 aetest
中的一个实际错误,但我坚信要确保它不是在归咎于工具之前应用程序的错误。我在这里做错了什么很明显吗?
我应该知道 "phantom" 进程的创建 - 事实证明我只是忘记在我创建的 aetest.Instance
上调用 Close()
。
实例化错误检查后的以下行为我修复了问题:
defer inst.Close()