@@ -19,6 +19,7 @@ import { CallCredentials } from './call-credentials';
1919import {
2020 Call ,
2121 CallStreamOptions ,
22+ DeadlineInfoProvider ,
2223 InterceptingListener ,
2324 MessageContext ,
2425 StatusObject ,
@@ -27,6 +28,7 @@ import { LogVerbosity, Propagate, Status } from './constants';
2728import {
2829 Deadline ,
2930 deadlineToString ,
31+ formatDateDifference ,
3032 getRelativeTimeout ,
3133 minDeadline ,
3234} from './deadline' ;
@@ -39,7 +41,7 @@ import { restrictControlPlaneStatusCode } from './control-plane-status';
3941const TRACER_NAME = 'resolving_call' ;
4042
4143export class ResolvingCall implements Call {
42- private child : Call | null = null ;
44+ private child : ( Call & DeadlineInfoProvider ) | null = null ;
4345 private readPending = false ;
4446 private pendingMessage : { context : MessageContext ; message : Buffer } | null =
4547 null ;
@@ -56,6 +58,10 @@ export class ResolvingCall implements Call {
5658 private deadlineTimer : NodeJS . Timeout = setTimeout ( ( ) => { } , 0 ) ;
5759 private filterStack : FilterStack | null = null ;
5860
61+ private deadlineStartTime : Date | null = null ;
62+ private configReceivedTime : Date | null = null ;
63+ private childStartTime : Date | null = null ;
64+
5965 constructor (
6066 private readonly channel : InternalChannel ,
6167 private readonly method : string ,
@@ -97,12 +103,37 @@ export class ResolvingCall implements Call {
97103
98104 private runDeadlineTimer ( ) {
99105 clearTimeout ( this . deadlineTimer ) ;
106+ this . deadlineStartTime = new Date ( ) ;
100107 this . trace ( 'Deadline: ' + deadlineToString ( this . deadline ) ) ;
101108 const timeout = getRelativeTimeout ( this . deadline ) ;
102109 if ( timeout !== Infinity ) {
103110 this . trace ( 'Deadline will be reached in ' + timeout + 'ms' ) ;
104111 const handleDeadline = ( ) => {
105- this . cancelWithStatus ( Status . DEADLINE_EXCEEDED , 'Deadline exceeded' ) ;
112+ if ( ! this . deadlineStartTime ) {
113+ this . cancelWithStatus ( Status . DEADLINE_EXCEEDED , 'Deadline exceeded' ) ;
114+ return ;
115+ }
116+ const deadlineInfo : string [ ] = [ ] ;
117+ const deadlineEndTime = new Date ( ) ;
118+ deadlineInfo . push ( `Deadline exceeded after ${ formatDateDifference ( this . deadlineStartTime , deadlineEndTime ) } ` ) ;
119+ if ( this . configReceivedTime ) {
120+ if ( this . configReceivedTime > this . deadlineStartTime ) {
121+ deadlineInfo . push ( `name resolution: ${ formatDateDifference ( this . deadlineStartTime , this . configReceivedTime ) } ` ) ;
122+ }
123+ if ( this . childStartTime ) {
124+ if ( this . childStartTime > this . configReceivedTime ) {
125+ deadlineInfo . push ( `metadata filters: ${ formatDateDifference ( this . configReceivedTime , this . childStartTime ) } ` ) ;
126+ }
127+ } else {
128+ deadlineInfo . push ( 'waiting for metadata filters' ) ;
129+ }
130+ } else {
131+ deadlineInfo . push ( 'waiting for name resolution' ) ;
132+ }
133+ if ( this . child ) {
134+ deadlineInfo . push ( ...this . child . getDeadlineInfo ( ) ) ;
135+ }
136+ this . cancelWithStatus ( Status . DEADLINE_EXCEEDED , deadlineInfo . join ( ',' ) ) ;
106137 } ;
107138 if ( timeout <= 0 ) {
108139 process . nextTick ( handleDeadline ) ;
@@ -176,6 +207,7 @@ export class ResolvingCall implements Call {
176207 return ;
177208 }
178209 // configResult.type === 'SUCCESS'
210+ this . configReceivedTime = new Date ( ) ;
179211 const config = configResult . config ;
180212 if ( config . status !== Status . OK ) {
181213 const { code, details } = restrictControlPlaneStatusCode (
@@ -215,6 +247,7 @@ export class ResolvingCall implements Call {
215247 this . deadline
216248 ) ;
217249 this . trace ( 'Created child [' + this . child . getCallNumber ( ) + ']' ) ;
250+ this . childStartTime = new Date ( ) ;
218251 this . child . start ( filteredMetadata , {
219252 onReceiveMetadata : metadata => {
220253 this . trace ( 'Received metadata' ) ;
0 commit comments