@@ -12,6 +12,7 @@ import {
12
12
errToStr ,
13
13
} from "./api-helper"
14
14
import { Storage } from "./storage"
15
+ import { getMemoryLogger , MemoryLogger } from "./memoryLogger"
15
16
16
17
export enum WorkspaceQuery {
17
18
Mine = "owner:me" ,
@@ -227,41 +228,80 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
227
228
// agent and registers a watcher that can be disposed to stop the watch and
228
229
// emits an event when the metadata changes.
229
230
function monitorMetadata ( agentId : WorkspaceAgent [ "id" ] , restClient : Api ) : AgentWatcher {
231
+ const logger = getMemoryLogger ( )
232
+ logger . trackResourceCreated ( "AgentMetadataWatcher" , agentId )
233
+
230
234
// TODO: Is there a better way to grab the url and token?
231
235
const url = restClient . getAxiosInstance ( ) . defaults . baseURL
232
236
const metadataUrl = new URL ( `${ url } /api/v2/workspaceagents/${ agentId } /watch-metadata` )
237
+
238
+ logger . info ( `Starting metadata watcher for agent: ${ agentId } at ${ metadataUrl } ` )
239
+
233
240
const eventSource = new EventSource ( metadataUrl . toString ( ) , {
234
241
fetch : createStreamingFetchAdapter ( restClient . getAxiosInstance ( ) ) ,
235
242
} )
236
243
237
244
let disposed = false
245
+ let eventCount = 0
238
246
const onChange = new vscode . EventEmitter < null > ( )
239
247
const watcher : AgentWatcher = {
240
248
onChange : onChange . event ,
241
249
dispose : ( ) => {
242
250
if ( ! disposed ) {
251
+ logger . info ( `Disposing metadata watcher for agent: ${ agentId } after ${ eventCount } events` )
243
252
eventSource . close ( )
253
+ onChange . dispose ( )
244
254
disposed = true
255
+ logger . trackResourceDisposed ( "AgentMetadataWatcher" , agentId )
245
256
}
246
257
} ,
247
258
}
248
259
260
+ eventSource . addEventListener ( "open" , ( ) => {
261
+ logger . info ( `Metadata EventSource connection opened for agent: ${ agentId } ` )
262
+ } )
263
+
249
264
eventSource . addEventListener ( "data" , ( event ) => {
265
+ eventCount ++
266
+
267
+ // Log periodic updates
268
+ if ( eventCount % 50 === 0 ) {
269
+ logger . info ( `Received ${ eventCount } metadata events for agent: ${ agentId } ` )
270
+ logger . logMemoryUsage ( "AGENT_METADATA" )
271
+ }
272
+
250
273
try {
251
274
const dataEvent = JSON . parse ( event . data )
252
275
const metadata = AgentMetadataEventSchemaArray . parse ( dataEvent )
253
276
254
277
// Overwrite metadata if it changed.
255
278
if ( JSON . stringify ( watcher . metadata ) !== JSON . stringify ( metadata ) ) {
279
+ if ( eventCount === 1 ) {
280
+ logger . debug ( `Initial metadata received for agent: ${ agentId } ` )
281
+ }
282
+
256
283
watcher . metadata = metadata
257
284
onChange . fire ( null )
258
285
}
259
286
} catch ( error ) {
287
+ logger . error ( `Error processing metadata for agent: ${ agentId } ` , error )
260
288
watcher . error = error
261
289
onChange . fire ( null )
262
290
}
263
291
} )
264
292
293
+ eventSource . addEventListener ( "error" , ( error ) => {
294
+ logger . error ( `Metadata EventSource error for agent: ${ agentId } ` , error )
295
+
296
+ // If connection closes permanently, clean up resources
297
+ if ( ( error as any ) . readyState === EventSource . CLOSED ) {
298
+ logger . info ( `Metadata EventSource connection closed for agent: ${ agentId } ` )
299
+ if ( ! disposed ) {
300
+ watcher . dispose ( )
301
+ }
302
+ }
303
+ } )
304
+
265
305
return watcher
266
306
}
267
307
0 commit comments