Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

twirp error unknown: failed to write response, 0 of 59 bytes written: http: Handler timeout #5

Closed
andyjia opened this issue Jul 2, 2019 · 24 comments

Comments

@andyjia
Copy link
Contributor

andyjia commented Jul 2, 2019

获取数据并返回Todo的对象的json的代码块

func (s *Server) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
	var ida int64
	var title string
	var desc string
	result, err := todo.Read(1)

	defer result.Close()
	for result.Next() {
		result.Scan(&ida, &title, &desc)
		break
	}
	log.Get(ctx).Infof("%d %s %s", ida, title, desc)

	todo := &pb.ToDo{Id: ida, Title: title, Description: desc}
	resp := &pb.ReadResponse{Api: "1", ToDo: todo}
	log.Get(ctx).Infof("todo=%v", todo)
	log.Get(ctx).Infof("resp=%v", resp)
	return resp, err
}

程序执行结果的部分,todo和resp的结果都OK,write response时提示超时的错误信息。

INFO[0016] todo=id:1 title:"a" description:"b"           app_id=localapp device="<nil>" env=dev instance_id=mac.local mobi_app="<nil>" platform="<nil>" trace_id=bc7f7c4690d3ef5 uid="<nil>" version="<nil>"
INFO[0016] resp=api:"1" toDo:<id:1 title:"a" description:"b" >   app_id=localapp device="<nil>" env=dev instance_id=mac.local mobi_app="<nil>" platform="<nil>" trace_id=bc7f7c4690d3ef5 uid="<nil>" version="<nil>"
ERRO[0176] twirp error unknown: failed to write response, 0 of 59 bytes written: http: Handler timeout  app_id=localapp device="<nil>" env=dev instance_id=mac.local mobi_app="<nil>" platform="<nil>" trace_id=bc7f7c4690d3ef5 uid="<nil>" version="<nil>"

service.twirp.go的代码出现的错误
函数:serveReadForm

	if n, err := resp.Write(respBytes); err != nil {
		msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error())
@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

@lvht 大佬请帮看下

@taoso
Copy link
Member

taoso commented Jul 2, 2019

这个 failed to write response 一般是客户端超时主动断开连接呀。把你的项目上传 github,我看一下。

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

请求这个url
localhost:8080/twirp/todo.v1.ToDoService/Read

@taoso
Copy link
Member

taoso commented Jul 2, 2019

我本地试了一下,没有问题呀。你指定 CONF_PATH 环境变量了吗?

image

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

我没有指定CONF_PATH环境变量
image

@taoso
Copy link
Member

taoso commented Jul 2, 2019

@andyjia 我搞糊涂了。我自己本地设了 CONF_PATH,在你的项目下要重新设置的。sniper 默认为加载项目根目录下的 sniper.toml。
image

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

我连续多次的刷新post,有的时候timeout,有的时候显示出正确的结果。(设置CONF_PATH与否结果相同)
image

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

我用的postman

image

@taoso
Copy link
Member

taoso commented Jul 2, 2019

你的 postman 的请求超时时间是不是设太短了。你先用 curl 直接调试试。

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

curl结果也是有时正常,有时timeout
mac:~ andyjia$ curl http://localhost:8080/twirp/todo.v1.ToDoService/Read -X POST -d '{"id":1}'
timeoutmac:~ andyjia$
mac:~ andyjia$
mac:~ andyjia$ curl http://localhost:8080/twirp/todo.v1.ToDoService/Read -X POST -d '{"id":1}'
timeoutmac:~ andyjia$
mac:~ andyjia$
mac:~ andyjia$ curl http://localhost:8080/twirp/todo.v1.ToDoService/Read -X POST -d '{"id":1}'
{"api":"1","toDo":{"id":"1","title":"a","description":"b"}}mac:~ andyjia$

@taoso
Copy link
Member

taoso commented Jul 2, 2019

默认有个 600ms 的超时。是不是你的 db 很慢?配置里加个一行 OUTER_API_TIMEOUT=3s 试试。

image

@taoso
Copy link
Member

taoso commented Jul 2, 2019

还有就是你的代码要一路传递 ctx 对象

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

大佬真牛!这样设置就好了,我这个是remote的数据库。
OUTER_API_TIMEOUT="3s"

@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

还有就是你的代码要一路传递 ctx 对象

是这样的操作么?(最开始这样搞的,出错了乱试着改了。context没理解透彻。)
func Read(id int) (*sql.Rows, error) {
ctx := context.Background()
dbc := db.Get(ctx, "default")
修改为
func Read(ctx context.Context, id int) (*sql.Rows, error) {
dbc := db.Get(ctx, "default")

@taoso
Copy link
Member

taoso commented Jul 2, 2019

对,ctx 用于超时控制,要一路传递的。

@taoso taoso closed this as completed Jul 2, 2019
@andyjia
Copy link
Contributor Author

andyjia commented Jul 2, 2019

领悟了~谢谢指导~

@andyjia
Copy link
Contributor Author

andyjia commented Jul 3, 2019

@lvht
试了好久,不知道什么原因,下面代码段,post的时候传递的是1,而下面获取req的结果req.GetId()的值为0。请问您知道可能的原因么?万分感谢。

func (s *Server) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
log.Get(ctx).Infof("id=%d", req.GetId())
result, err := todo.Read(ctx, int(req.GetId()))

@andyjia
Copy link
Contributor Author

andyjia commented Jul 3, 2019

解决了。我curl post方法的问题(json内容大小写区分)。抱歉打扰了。
memo下,用下面的方式OK。

  1. curl
    curl http://localhost:8080/twirp/todo.v1.ToDoService/Read -X POST -H "Content-Type:application/json" -d '{"id":"1","api":"1"}'
  2. postman
  • way 1
    raw - JSON(application/json)
    {
    "api":"1",
    "id":"1"
    }

  • way 2
    x-www-form-urlencoded
    id =1
    api=1

@taoso
Copy link
Member

taoso commented Jul 3, 2019

你这个传错了吧。你这里定义的 id 类型是 int64,不是字符串。你可以从官方文档查询 json 和 protobuf 类型的对应关系。

你试试

curl http://localhost:8080/twirp/todo.v1.ToDoService/Read -X POST -H "Content-Type:application/json" -d '{"id":1,"api":"1"}'

@andyjia
Copy link
Contributor Author

andyjia commented Jul 3, 2019

谢谢提供的链接,谢谢大佬指导!
框架写的真好!

@taoso
Copy link
Member

taoso commented Jul 3, 2019

起这么早,少见

@andyjia
Copy link
Contributor Author

andyjia commented Jul 3, 2019

下一步我引入jwt试试

@taoso
Copy link
Member

taoso commented Jul 3, 2019

写个 hook 就好了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants