大家好,今天来为大家解答源码分享网站电影文案图片这个问题的一些问题点,包括网页电影源代码怎么查找也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~
我们经常看到下面的日志:
rpcerror:code=DeadlineExceededdesc=contextdeadlineexceeded
我们需要思考两个问题:1,这个错误码来源是哪里?2,超时是如何设置和生效的?
首先我们看下第一个问题:我们可以发现这段错误文案是golang源码里的错误文案:src/context/context.go
varDeadlineExceedederror=deadlineExceededError{}\nfunc(deadlineExceededError)Error()string{return&34;}
什么时候会返回这个错误呢?同样是golang源码的context包里
\n\nfuncWithDeadline(parentContext,dtime.Time)(Context,CancelFunc){\nifcur,ok:=parent.Deadline();ok&&cur.Before(d){\n//Thecurrentdeadlineisalreadysoonerthanthenewone.\nreturnWithCancel(parent)\n}\n\n\ndur:=time.Until(d)\nifdur<=0{\nc.cancel(true,DeadlineExceeded)//deadlinehasalreadypassed\nreturnc,func(){c.cancel(false,Canceled)}\n}\n\n\nifc.err==nil{\nc.timer=time.AfterFunc(dur,func(){\nc.cancel(true,DeadlineExceeded)\n})\n}\n\n\nreturnc,func(){c.cancel(true,Canceled)}\n}
funcWithTimeout(parentContext,timeouttime.Duration)(Context,CancelFunc){\nreturnWithDeadline(parent,time.Now().Add(timeout))\n}
了解了上面的背景后,我们就可以排查grpc-go的client在何时使用了WithTimeout
google.golang.org/grpc@v1.50.1/clientconn.go
typeClientConnstruct{\ndoptsdialOptions\n}
funcDialContext(ctxcontext.Context,targetstring,opts…DialOption)(conn*ClientConn,errerror){\nifcc.dopts.timeout>0{\nvarcancelcontext.CancelFunc\nctx,cancel=context.WithTimeout(ctx,cc.dopts.timeout)\ndefercancel()\n}\n}
可以看到,在发起连接的时候会有,当server超过超时时间没有响应的时候就会报上面的错误。
第二个地方就是我们发送请求的时候,我先会获取一个连接
funcinvoke(ctxcontext.Context,methodstring,req,replyinterface{},cc*ClientConn,opts…CallOption)error{\ncs,err:=newClientStream(ctx,unaryStreamDesc,cc,method,opts…)
funcnewClientStream(ctxcontext.Context,desc*StreamDesc,cc*ClientConn,methodstring,opts…CallOption)(_ClientStream,errerror){\nvarnewStream=func(ctxcontext.Context,donefunc())(iresolver.ClientStream,error){\nreturnnewClientStreamWithParams(ctx,desc,cc,method,mc,onCommit,done,opts…)\n}\nrpcConfig,err:=cc.safeConfigSelector.SelectConfig(rpcInfo)
funcnewClientStreamWithParams(ctxcontext.Context,desc*StreamDesc,cc*ClientConn,methodstring,mcserviceconfig.MethodConfig,onCommit,doneFuncfunc(),opts…CallOption)(_iresolver.ClientStream,errerror){\nifmc.Timeout!=nil&&*mc.Timeout>=0{\nctx,cancel=context.WithTimeout(ctx,*mc.Timeout)\n}else{\nctx,cancel=context.WithCancel(ctx)\n}
可以看到,如果方法配置了超时,在超时时间完成之前,没有响应,也会报错。
还有没有其它地方可以配置超时呢?答案是肯定的,Interceptor里我们也可以定义超时。下面就是我们常用的两种设置的超时的方法,分别是连接维度和请求方法维度。
clientConn,err:=grpc.Dial(serverAddress,grpc.WithTimeout(5*time.Second),grpc.WithInsecure())\niferr!=nil{\nlog.Println(&34;)\nreturnerr\n}
c:=pb.NewGreeterClient(conn)\nc.SayHello(context.Background(),&pb.HelloRequest{Name:&34;},\nWithForcedTimeout(time.Duration(10)*time.Second))
那么上述设置是如何生效的?如何传递到服务端的呢?先看下
grpc.WithTimeout源码位于google.golang.org/grpc@v1.50.1/dialoptions.go
funcWithTimeout(dtime.Duration)DialOption{\nreturnnewFuncDialOption(func(o*dialOptions){\no.timeout=d\n})\n}
它修改了dialOptions的timeout
typedialOptionsstruct{\ntimeouttime.Duration\n}
typeDialOptioninterface{\napply(*dialOptions)\n}
而dialOptions是ClientConn的一个属性
typeClientConnstruct{\ndoptsdialOptions\n}
我们发起连接的时候用的就是这个属性上的timeout
funcDialContext(ctxcontext.Context,targetstring,opts…DialOption)(conn*ClientConn,errerror){\nifcc.dopts.timeout>0{\nvarcancelcontext.CancelFunc\nctx,cancel=context.WithTimeout(ctx,cc.dopts.timeout)\ndefercancel()\n}\n}
Interceptor是如何让超时生效的呢,逻辑更简单,我们看下它的定义,在发起真正调用之前先调用Interceptor,这个时候设置超时时间:
funcTimeoutInterceptor(ttime.Duration)grpc.UnaryClientInterceptor{\nreturnfunc(ctxcontext.Context,methodstring,req,replyinterface{},cc*grpc.ClientConn,\ninvokergrpc.UnaryInvoker,opts…grpc.CallOption)error{\ntimeout:=t\nifv,ok:=getForcedTimeout(opts);ok{\ntimeout=v\n}\niftimeout<=0{\nreturninvoker(ctx,method,req,reply,cc,opts…)\n}\nctx,cancel:=context.WithTimeout(ctx,timeout)\ndefercancel()\nreturninvoker(ctx,method,req,reply,cc,opts…)\n}\n}
funcgetForcedTimeout(callOptions[]grpc.CallOption)(time.Duration,bool){\nfor_,opt:=rangecallOptions{\nifco,ok:=opt.(TimeoutCallOption);ok{\nreturnco.forcedTimeout,true\n}\n}\nreturn0,false\n}
而超时时间是我们发起调用的时候通过option传递下来的
typeTimeoutCallOptionstruct{\ngrpc.EmptyCallOption\nforcedTimeouttime.Duration\n}\nfuncWithForcedTimeout(forceTimeouttime.Duration)TimeoutCallOption{\nreturnTimeoutCallOption{forcedTimeout:forceTimeout}\n}
弄清楚客户端的超时时间是如何设置和生效的以后,服务端怎么保证,客户端超时以后,马上终止当前任务呢?回答这个问题之前,我们看下超时是如何传递的。首先,给出答案:grpc协议将超时时间放置在HTTPHeader请求头里面。客户端设置的超时时间为5秒,http2的header如下
grpc-timeout:4995884u
其中u表示时间单位为纳秒,4995884u约等于5秒。然后服务端接收到该请求后,就可以根据这个时间计算出是否超时,由header超时设置。
那么header是何时由client设置的,以及何时由服务端解析的呢?
google.golang.org/grpc@v1.50.1/internal/transport/http2_client.go
发起客户端请求的时候会调用
func(t*http2Client)NewStream(ctxcontext.Context,callHdr*CallHdr)(*Stream,error){\nheaderFields,err:=t.createHeaderFields(ctx,callHdr)
内部我们可以看到,它从context里面取出超时截止时间,然后写入header&34;里面
func(t*http2Client)createHeaderFields(ctxcontext.Context,callHdr*CallHdr)([]hpack.HeaderField,error){\nifdl,ok:=ctx.Deadline();ok{\n//Sendouttimeoutregardlessitsvalue.Theservercandetecttimeoutcontextbyitself.\n//TODO(mmukhi):Perhapsthisfieldshouldbeupdatedwhenactuallywritingouttothewire.\ntimeout:=time.Until(dl)\nheaderFields=append(headerFields,hpack.HeaderField{Name:&34;,Value:grpcutil.EncodeDuration(timeout)})\n}
解析的过程:
google.golang.org/grpc@v1.50.1/internal/transport/handler_server.go
funcNewServerHandlerTransport(whttp.ResponseWriter,r*http.Request,stats[]stats.Handler)(ServerTransport,error){\nifv:=r.Header.Get(&34;);v!=&34;{\nto,err:=decodeTimeout(v)\niferr!=nil{\nreturnnil,status.Errorf(codes.Internal,&34;,err)\n}\nst.timeoutSet=true\nst.timeout=to\n}\n\niftimeoutSet{\ns.ctx,s.cancel=context.WithTimeout(t.ctx,timeout)\n}else{\ns.ctx,s.cancel=context.WithCancel(t.ctx)\n}
可以看到,首先从header里面取出超时时间,然后设置context.WithTimeout
func(ht*serverHandlerTransport)HandleStreams(startStreamfunc(*Stream),traceCtxfunc(context.Context,string)context.Context){\nifht.timeoutSet{\nctx,cancel=context.WithTimeout(ctx,ht.timeout)\n}else{\nctx,cancel=context.WithCancel(ctx)\n}
google.golang.org/grpc@v1.50.1/internal/transport/http2_server.go
func(t*http2Server)operateHeaders(frame*http2.MetaHeadersFrame,handlefunc(*Stream),traceCtxfunc(context.Context,string)context.Context)(fatalbool){\ncase&34;:\ntimeoutSet=true\nvarerrerror\niftimeout,err=decodeTimeout(hf.Value);err!=nil{\nheaderError=true\n}
源码分享网站电影文案图片的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于网页电影源代码怎么查找、源码分享网站电影文案图片的信息别忘了在本站进行查找哦。