12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
- import { HttpClient } from '@/src/api/http-client' ;
15
+ import { hrTimeMs , HttpClient } from '@/src/api/http-client' ;
16
16
import { AxiosError , AxiosResponse } from 'axios' ;
17
17
import { HTTPClientOptions , HttpMethodStrings } from '@/src/api/types' ;
18
18
import { HTTP1AuthHeaderFactories , HTTP1Strategy } from '@/src/api/http1' ;
19
19
import { DevopsApiResponseError , DevopsApiTimeout , DevopsUnexpectedStateError } from '@/src/devops/errors' ;
20
- import { AdminBlockingOptions , PollBlockingOptions } from '@/src/devops/types' ;
21
- import {
22
- MkTimeoutError , TimeoutManager ,
23
- TimeoutOptions ,
24
- } from '@/src/api/timeout-managers' ;
20
+ import { AdminBlockingOptions } from '@/src/devops/types' ;
21
+ import { MkTimeoutError , TimeoutManager , TimeoutOptions } from '@/src/api/timeout-managers' ;
25
22
import { HttpMethods } from '@/src/api/constants' ;
23
+ import {
24
+ AdminCommandFailedEvent ,
25
+ AdminCommandPollingEvent ,
26
+ AdminCommandStartedEvent ,
27
+ AdminCommandSucceededEvent ,
28
+ } from '@/src/devops' ;
26
29
27
- interface DevopsApiRequestInfo {
30
+ /**
31
+ * @internal
32
+ */
33
+ export interface DevopsApiRequestInfo {
28
34
path : string ,
29
35
method : HttpMethodStrings ,
30
36
data ?: Record < string , any > ,
31
37
params ?: Record < string , any > ,
32
38
}
33
39
34
- interface LongRunningRequestInfo {
40
+ /**
41
+ * @internal
42
+ */
43
+ export interface LongRunningRequestInfo {
35
44
id : string | ( ( resp : AxiosResponse ) => string ) ,
36
45
target : string ,
37
46
legalStates : string [ ] ,
@@ -48,19 +57,41 @@ export class DevopsApiHttpClient extends HttpClient {
48
57
this . requestStrategy = new HTTP1Strategy ( HTTP1AuthHeaderFactories . DevopsApi ) ;
49
58
}
50
59
51
- public async request ( info : DevopsApiRequestInfo , options : TimeoutOptions | undefined ) : Promise < AxiosResponse > {
60
+ public async request ( req : DevopsApiRequestInfo , options : TimeoutOptions | undefined , started : number = 0 ) : Promise < AxiosResponse > {
61
+ const isLongRunning = started !== 0 ;
62
+
52
63
try {
53
64
const timeoutManager = options ?. timeoutManager ?? mkTimeoutManager ( options ?. maxTimeMS ) ;
54
- const url = this . baseUrl + info . path ;
65
+ const url = this . baseUrl + req . path ;
55
66
56
- return await this . _request ( {
67
+ if ( this . monitorCommands && ! isLongRunning ) {
68
+ this . emitter . emit ( 'adminCommandStarted' , new AdminCommandStartedEvent ( req , isLongRunning , timeoutManager . ms ) ) ;
69
+ }
70
+
71
+ started ||= hrTimeMs ( ) ;
72
+
73
+ const resp = await this . _request ( {
57
74
url : url ,
58
- method : info . method ,
59
- params : info . params ,
60
- data : info . data ,
75
+ method : req . method ,
76
+ params : req . params ,
77
+ data : req . data ,
61
78
timeoutManager,
62
- } ) as any ;
79
+ } ) as AxiosResponse ;
80
+
81
+ if ( this . monitorCommands && ! isLongRunning ) {
82
+ this . emitter . emit ( 'adminCommandSucceeded' , new AdminCommandSucceededEvent ( req , false , resp , started ) ) ;
83
+ }
84
+
85
+ return resp ;
63
86
} catch ( e ) {
87
+ if ( ! ( e instanceof Error ) ) {
88
+ throw e ;
89
+ }
90
+
91
+ if ( this . monitorCommands ) {
92
+ this . emitter . emit ( 'adminCommandFailed' , new AdminCommandFailedEvent ( req , isLongRunning , e , started ) ) ;
93
+ }
94
+
64
95
if ( ! ( e instanceof AxiosError ) ) {
65
96
throw e ;
66
97
}
@@ -70,38 +101,72 @@ export class DevopsApiHttpClient extends HttpClient {
70
101
71
102
public async requestLongRunning ( req : DevopsApiRequestInfo , info : LongRunningRequestInfo ) : Promise < AxiosResponse > {
72
103
const timeoutManager = mkTimeoutManager ( info . options ?. maxTimeMS ) ;
73
- const resp = await this . request ( req , { timeoutManager } ) ;
104
+ const isLongRunning = info ?. options ?. blocking !== false ;
105
+
106
+ if ( this . monitorCommands ) {
107
+ this . emitter . emit ( 'adminCommandStarted' , new AdminCommandStartedEvent ( req , isLongRunning , timeoutManager . ms ) ) ;
108
+ }
109
+
110
+ const started = hrTimeMs ( ) ;
111
+ const resp = await this . request ( req , { timeoutManager } , started ) ;
74
112
75
113
const id = ( typeof info . id === 'function' )
76
114
? info . id ( resp )
77
115
: info . id ;
78
116
79
- if ( info ?. options ?. blocking !== false ) {
80
- await this . _awaitStatus ( id , info . target , info . legalStates , info . options , info . defaultPollInterval , timeoutManager ) ;
117
+ await this . _awaitStatus ( id , req , info , timeoutManager , started ) ;
118
+
119
+ if ( this . monitorCommands && isLongRunning ) {
120
+ this . emitter . emit ( 'adminCommandSucceeded' , new AdminCommandSucceededEvent ( req , true , resp , started ) ) ;
81
121
}
82
122
83
123
return resp ;
84
124
}
85
125
86
- private async _awaitStatus ( id : string , target : string , legalStates : string [ ] , options : PollBlockingOptions | undefined , defaultPollInterval : number , timeoutManager : TimeoutManager ) : Promise < void > {
126
+ private async _awaitStatus ( id : string , req : DevopsApiRequestInfo , info : LongRunningRequestInfo , timeoutManager : TimeoutManager , started : number ) : Promise < void > {
127
+ if ( info . options ?. blocking === false ) {
128
+ return ;
129
+ }
130
+
131
+ const pollInterval = info . options ?. pollInterval || info . defaultPollInterval ;
132
+ let waiting = false ;
133
+
87
134
for ( ; ; ) {
135
+ if ( waiting ) {
136
+ continue ;
137
+ }
138
+ waiting = true ;
139
+
140
+ if ( this . monitorCommands ) {
141
+ this . emitter . emit ( 'adminCommandPolling' , new AdminCommandPollingEvent ( req , started , pollInterval ) ) ;
142
+ }
143
+
88
144
const resp = await this . request ( {
89
145
method : HttpMethods . Get ,
90
146
path : `/databases/${ id } ` ,
91
147
} , {
92
148
timeoutManager : timeoutManager ,
93
- } ) ;
149
+ } , started ) ;
94
150
95
- if ( resp . data ?. status === target ) {
151
+ if ( resp . data ?. status === info . target ) {
96
152
break ;
97
153
}
98
154
99
- if ( ! legalStates . includes ( resp . data ?. status ) ) {
100
- throw new DevopsUnexpectedStateError ( `Created database is not in any legal state [${ [ target , ...legalStates ] . join ( ',' ) } ]` , resp )
155
+ if ( ! info . legalStates . includes ( resp . data ?. status ) ) {
156
+ const error = new DevopsUnexpectedStateError ( `Created database is not in any legal state [${ [ info . target , ...info . legalStates ] . join ( ',' ) } ]` , resp ) ;
157
+
158
+ if ( this . monitorCommands ) {
159
+ this . emitter . emit ( 'adminCommandFailed' , new AdminCommandFailedEvent ( req , true , error , started ) ) ;
160
+ }
161
+
162
+ throw error ;
101
163
}
102
164
103
165
await new Promise < void > ( ( resolve ) => {
104
- setTimeout ( resolve , options ?. pollInterval || defaultPollInterval ) ;
166
+ setTimeout ( ( ) => {
167
+ waiting = false ;
168
+ resolve ( ) ;
169
+ } , pollInterval ) ;
105
170
} ) ;
106
171
}
107
172
}
0 commit comments