@@ -52,14 +52,23 @@ export class GitpodPublicApi extends Disposable implements IGitpodAPI {
5252
5353 private workspaceStatusStreamMap = new Map < string , { onStatusChanged : vscode . Event < WorkspaceStatus > ; dispose : ( force ?: boolean ) => void ; increment : ( ) => void } > ( ) ;
5454
55- constructor ( accessToken : string , gitpodHost : string , private logger : ILogService ) {
55+ constructor ( private accessToken : string , private gitpodHost : string , private logger : ILogService ) {
5656 super ( ) ;
5757
58- const serviceUrl = new URL ( gitpodHost ) ;
58+ this . createClients ( ) ;
59+
60+ this . metricsReporter = new MetricsReporter ( gitpodHost , logger ) ;
61+ if ( isTelemetryEnabled ( ) ) {
62+ this . metricsReporter . startReporting ( ) ;
63+ }
64+ }
65+
66+ private createClients ( ) {
67+ const serviceUrl = new URL ( this . gitpodHost ) ;
5968 serviceUrl . hostname = `api.${ serviceUrl . hostname } ` ;
6069
6170 const authInterceptor : Interceptor = ( next ) => async ( req ) => {
62- req . header . set ( 'Authorization' , `Bearer ${ accessToken } ` ) ;
71+ req . header . set ( 'Authorization' , `Bearer ${ this . accessToken } ` ) ;
6372 return await next ( req ) ;
6473 } ;
6574 const metricsInterceptor = getConnectMetricsInterceptor ( ) ;
@@ -75,57 +84,54 @@ export class GitpodPublicApi extends Disposable implements IGitpodAPI {
7584 this . workspaceService = createPromiseClient ( WorkspacesService , transport ) ;
7685 this . userService = createPromiseClient ( UserService , transport ) ;
7786 this . ideClientService = createPromiseClient ( IDEClientService , transport ) ;
78-
79- this . metricsReporter = new MetricsReporter ( gitpodHost , logger ) ;
80- if ( isTelemetryEnabled ( ) ) {
81- this . metricsReporter . startReporting ( ) ;
82- }
8387 }
88+
89+
8490 async getWorkspace ( workspaceId : string ) : Promise < Workspace > {
85- return this . _wrapError ( async ( ) => {
91+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
8692 const response = await this . workspaceService . getWorkspace ( { workspaceId } ) ;
8793 return response . result ! ;
88- } ) ;
94+ } ) ) ;
8995 }
9096
9197 async startWorkspace ( workspaceId : string ) : Promise < Workspace > {
92- return this . _wrapError ( async ( ) => {
98+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
9399 const response = await this . workspaceService . startWorkspace ( { workspaceId } ) ;
94100 return response . result ! ;
95- } ) ;
101+ } ) ) ;
96102 }
97103
98104 async getOwnerToken ( workspaceId : string ) : Promise < string > {
99- return this . _wrapError ( async ( ) => {
105+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
100106 const response = await this . workspaceService . getOwnerToken ( { workspaceId } ) ;
101107 return response . token ;
102- } ) ;
108+ } ) ) ;
103109 }
104110
105111 async getSSHKeys ( ) : Promise < SSHKey [ ] > {
106- return this . _wrapError ( async ( ) => {
112+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
107113 const response = await this . userService . listSSHKeys ( { } ) ;
108114 return response . keys ;
109- } ) ;
115+ } ) ) ;
110116 }
111117
112118 async sendHeartbeat ( workspaceId : string ) : Promise < void > {
113- return this . _wrapError ( async ( ) => {
119+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
114120 await this . ideClientService . sendHeartbeat ( { workspaceId } ) ;
115- } ) ;
121+ } ) ) ;
116122 }
117123
118124 async sendDidClose ( workspaceId : string ) : Promise < void > {
119- return this . _wrapError ( async ( ) => {
125+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
120126 await this . ideClientService . sendDidClose ( { workspaceId } ) ;
121- } ) ;
127+ } ) ) ;
122128 }
123129
124130 async getAuthenticatedUser ( ) : Promise < User | undefined > {
125- return this . _wrapError ( async ( ) => {
131+ return this . _wrapError ( this . _workaroundGoAwayBug ( async ( ) => {
126132 const response = await this . userService . getAuthenticatedUser ( { } ) ;
127133 return response . user ;
128- } ) ;
134+ } ) ) ;
129135 }
130136
131137 workspaceStatusStreaming ( workspaceId : string ) {
@@ -141,7 +147,7 @@ export class GitpodPublicApi extends Disposable implements IGitpodAPI {
141147 if ( isDisposed ) { return ; }
142148
143149 try {
144- const resp = await this . workspaceService . getWorkspace ( { workspaceId } ) ;
150+ const resp = await this . _workaroundGoAwayBug ( ( ) => this . workspaceService . getWorkspace ( { workspaceId } ) ) ( ) ;
145151 if ( isDisposed ) { return ; }
146152 emitter . fire ( resp . result ! . status ! ) ;
147153 } catch ( err ) {
@@ -190,6 +196,14 @@ export class GitpodPublicApi extends Disposable implements IGitpodAPI {
190196 return ;
191197 }
192198 this . logger . error ( `Error in streamWorkspaceStatus for ${ workspaceId } ` , e ) ;
199+
200+ // Workaround https://github.com/bufbuild/connect-es/issues/680
201+ // Remove this once it's fixed upstream
202+ const message : string = e . stack || e . message || `${ e } ` ;
203+ if ( message . includes ( 'New streams cannot be created after receiving a GOAWAY' ) ) {
204+ this . logger . error ( 'Got GOAWAY bug, recreating connect client' ) ;
205+ this . createClients ( ) ;
206+ }
193207 }
194208 }
195209
@@ -205,6 +219,26 @@ export class GitpodPublicApi extends Disposable implements IGitpodAPI {
205219 }
206220 }
207221
222+ private _workaroundGoAwayBug < T > ( callback : ( ) => Promise < T > ) : ( ) => Promise < T > {
223+ return async ( ) => {
224+ try {
225+ return await callback ( ) ;
226+ } catch ( e ) {
227+ // Workaround https://github.com/bufbuild/connect-es/issues/680
228+ // Remove this once it's fixed upstream
229+ const message : string = e . stack || e . message || `${ e } ` ;
230+ if ( message . includes ( 'New streams cannot be created after receiving a GOAWAY' ) ) {
231+ this . logger . error ( 'Got GOAWAY bug, recreating connect client' ) ;
232+ this . createClients ( ) ;
233+
234+ return await callback ( ) ;
235+ } else {
236+ throw e ;
237+ }
238+ }
239+ } ;
240+ }
241+
208242 public override dispose ( ) {
209243 super . dispose ( ) ;
210244 for ( const { dispose } of this . workspaceStatusStreamMap . values ( ) ) {
0 commit comments