google-app-engine - 应用引擎推送任务在测试中总是返回 404

标签 google-app-engine go google-app-engine-go

我在 Go App Engine 应用程序中有一个推送任务队列。当我们出于任何原因尝试将任务排入测试队列时,任务总是返回 404。

我们的 app.yaml:

runtime: go
api_version: go1.9

handlers:
 - url: /worker/.*
   script: _go_app
   login: admin
 - url: /.*
   script: _go_app

实际的任务调用:

func Handler(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    t := taskqueue.NewPOSTTask("/worker", map[string][]string{"key": {"val"}})
    _, err := taskqueue.Add(ctx, t, "")
    if err != nil {
        log.Errorf(ctx, "Failed to add task");
    }
    fmt.Fprintf(w, "Success");
}

一个仍然不完整的处理程序,但它存在!

func Worker(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    log.Infof(ctx, "Worker succeeded")
}

最后,证明我们确实添加了路由器的路径:

func init() {
    http.HandleFunc("/", Handler)
    http.HandleFunc("/worker", Worker)
}

当我们实际运行测试时,我们总是得到以下日志输出:

INFO     2018-05-03 09:51:11,794 module.py:846] default: "POST /worker HTTP/1.1" 404 19
WARNING  2018-05-03 09:51:11,794 taskqueue_stub.py:2149] Task � failed to execute. This task will retry in 0.100 seconds
INFO     2018-05-03 09:51:11,897 module.py:846] default: "POST /worker HTTP/1.1" 404 19
WARNING  2018-05-03 09:51:11,897 taskqueue_stub.py:2149] Task � failed to execute. This task will retry in 0.200 seconds
INFO     2018-05-03 09:51:12,101 module.py:846] default: "POST /worker HTTP/1.1" 404 19
WARNING  2018-05-03 09:51:12,101 taskqueue_stub.py:2149] Task � failed to execute. This task will retry in 0.400 seconds

请注意,当我尝试通过 Paw 之类的 API 客户端 ping 端点时,/worker 端点返回 302,因此路由似乎已正确配置。 404 仅在我尝试在测试中运行时出现。

为什么返回 404?我已经尝试在他们的 documentation 中围绕示例推送队列运行测试。在那里遇到了同样的问题 - 是否有某种丢失的配置标志我未能传递给 goapp

我已经推送了一个 GitHub 存储库,其中包含一个可复制的最小示例 here

最佳答案

运行 goapp 的顺序是自上而下的,但您需要在 app.yaml 中具体说明。在您的情况下,这将起作用:

package main

import (
    "fmt"
    "net/http"

    "google.golang.org/appengine"
    "google.golang.org/appengine/log"
    "google.golang.org/appengine/taskqueue"
)

func Handler(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    t := taskqueue.NewPOSTTask("/worker", map[string][]string{"key": {"val"}})
    _, err := taskqueue.Add(ctx, t, "")
    if err != nil {
        log.Errorf(ctx, "Failed to add task")
    }
    fmt.Fprintf(w, "Success")
}

func Worker(w http.ResponseWriter, r *http.Request) {
    ctx := appengine.NewContext(r)
    log.Infof(ctx, "Worker succeeded")
}

func init() {
    http.HandleFunc("/", Handler)
    http.HandleFunc("/worker", Worker)
}

为此,您需要映射 url,如:

runtime: go
api_version: go1.9

handlers:
 - url: /worker
   script: _go_app
   login: admin
 - url: /.*
   script: _go_app

结果是:

enter image description here

看到 worker 运行了两次。这是因为 GET/favicon.ico 正在进入 GET/.* 映射。所以这只是给你的细节!

更新(2018 年 5 月 14 日): 在您的测试中,您使用 aetest.NewInstance(),它在 ioutil.TempDir("", "appengine-aetest") 中运行 dev_appserver.py,它编写您自己的 main .go 和 app.yaml。参见上面的 instance_vm.go:

i.appDir, err = ioutil.TempDir("", "appengine-aetest")
if err != nil {
    return err
}
defer func() {
    if err != nil {
        os.RemoveAll(i.appDir)
    }
}()
err = os.Mkdir(filepath.Join(i.appDir, "app"), 0755)
if err != nil {
    return err
}
err = ioutil.WriteFile(filepath.Join(i.appDir, "app", "app.yaml"), []byte(i.appYAML()), 0644)
  if err != nil {
    return err
}
err = ioutil.WriteFile(filepath.Join(i.appDir, "app", "stubapp.go"), []byte(appSource), 0644)
if err != nil {
    return err
}

//... others codes

const appYAMLTemplate = `
application: %s
version: 1
runtime: go
api_version: go1
vm: true
handlers:
- url: /.*
  script: _go_app
`

const appSource = `
package main
import "google.golang.org/appengine"
func main() { appengine.Main() }
`

因此您需要创建自己的服务器实例。这是一种方式:

//out buffer
var out bytes.Buffer
//start server
c := exec.Command("goapp", "serve") //default port=8080, adminPort=8000
c.Stdout = &out
c.Stderr = &out
c.Start()
defer c.Process.Kill()
//delay to wait server is completed
time.Sleep(10 * time.Second)

//... others codes

//quit server
quitReq, err := http.NewRequest("GET", "http://localhost:8000/quit", nil)
_, err := client.Do(quitReq)
if err != nil {
    fmt.Errorf("GET /quit handler error: %v", err)
}

要测试您的 Handler 函数,请执行以下操作:

//create request (testing Handler func)
req, err := http.NewRequest("GET", "http://localhost:8080/", nil)
if err != nil {
    t.Fatal(err.Error())
}
//do GET
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
    t.Error(err)
}
defer resp.Body.Close()
//delay to wait for the worker to execute
time.Sleep(10 * time.Second)

检索结果并进行测试:

//read response
b, _ := ioutil.ReadAll(resp.Body)
resp_content := string(b)
//checking
if !strings.Contains(resp_content, "Handler Success") {
    t.Errorf("Handler not working")
}
//log server content
logserver := out.String()
if !strings.Contains(logserver, "Worker succeeded") {
    t.Errorf("Worker not working")
}
//log response
t.Logf(logserver)

结果是:

screenshot - test result

更新:Github 链接:https://github.com/ag-studies/go-appengine-sample

希望有帮助!!

关于google-app-engine - 应用引擎推送任务在测试中总是返回 404,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50152164/

相关文章:

python - 按年份过滤日期,请帮我找出错误

google-app-engine - Google App Engine .jsp 问题

python - 使用Python访问MySQL时如何检索Google Cloud-SQL中的列名称?

go - 如何在golang中使用gorm通过ssh连接数据库?

database - GoLang Multi-Tenancy 应用程序数据库连接

google-app-engine - 如何配置 Google App Engine 不构建一些 Go 文件?

google-app-engine - 在 App Engine 标准环境中将运行时从 Python 更改为 Go

linux - 我们如何才能灵活地为 Google App Engine 更改操作系统?或者我们可以这样做吗?

binary - 从 stdin 接收二进制数据,发送到 Go 中的 channel

google-app-engine - `go build -mod vendor` 无法使用 vendored 包