taist 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/trace-collector.js +95 -27
- package/lib/trace-reporter.js +13 -3
- package/package.json +1 -1
package/lib/trace-collector.js
CHANGED
|
@@ -72,9 +72,15 @@ export class TraceCollector extends EventEmitter {
|
|
|
72
72
|
_handleConnection(socket) {
|
|
73
73
|
this.connections.add(socket);
|
|
74
74
|
let buffer = "";
|
|
75
|
+
const lifecycleDebug = process.env.TAIST_TRACE_LIFECYCLE === 'true';
|
|
75
76
|
|
|
76
77
|
socket.on("data", (chunk) => {
|
|
77
|
-
|
|
78
|
+
const data = chunk.toString();
|
|
79
|
+
buffer += data;
|
|
80
|
+
|
|
81
|
+
if (lifecycleDebug) {
|
|
82
|
+
console.log(`[LIFECYCLE collector] [${Date.now()}] RAW DATA received, length:`, data.length, 'buffer now:', buffer.length);
|
|
83
|
+
}
|
|
78
84
|
|
|
79
85
|
// Process complete NDJSON lines
|
|
80
86
|
const lines = buffer.split("\n");
|
|
@@ -88,6 +94,9 @@ export class TraceCollector extends EventEmitter {
|
|
|
88
94
|
});
|
|
89
95
|
|
|
90
96
|
socket.on("close", () => {
|
|
97
|
+
if (lifecycleDebug) {
|
|
98
|
+
console.log('[LIFECYCLE collector] Socket closed, remaining buffer:', buffer.length, 'chars');
|
|
99
|
+
}
|
|
91
100
|
// Process any remaining data in buffer
|
|
92
101
|
if (buffer.trim()) {
|
|
93
102
|
this._processMessage(buffer);
|
|
@@ -96,18 +105,26 @@ export class TraceCollector extends EventEmitter {
|
|
|
96
105
|
});
|
|
97
106
|
|
|
98
107
|
socket.on("error", (err) => {
|
|
108
|
+
if (lifecycleDebug) {
|
|
109
|
+
console.log('[LIFECYCLE collector] Socket error:', err.message);
|
|
110
|
+
}
|
|
99
111
|
this.emit("connectionError", err);
|
|
100
112
|
this.connections.delete(socket);
|
|
101
113
|
});
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
_processMessage(line) {
|
|
117
|
+
const lifecycleDebug = process.env.TAIST_TRACE_LIFECYCLE === 'true';
|
|
118
|
+
|
|
105
119
|
try {
|
|
106
120
|
const message = JSON.parse(line);
|
|
107
121
|
|
|
108
122
|
if (message.type === "trace") {
|
|
109
123
|
this._addTrace(message.data);
|
|
110
124
|
} else if (message.type === "batch") {
|
|
125
|
+
if (lifecycleDebug) {
|
|
126
|
+
console.log('[LIFECYCLE collector] Processing batch of', message.data?.length, 'traces');
|
|
127
|
+
}
|
|
111
128
|
for (const trace of message.data) {
|
|
112
129
|
this._addTrace(trace);
|
|
113
130
|
}
|
|
@@ -115,6 +132,9 @@ export class TraceCollector extends EventEmitter {
|
|
|
115
132
|
this.emit("flush", { workerId: message.workerId });
|
|
116
133
|
}
|
|
117
134
|
} catch (err) {
|
|
135
|
+
if (lifecycleDebug) {
|
|
136
|
+
console.log('[LIFECYCLE collector] PARSE ERROR:', err.message, 'line:', line.slice(0, 100));
|
|
137
|
+
}
|
|
118
138
|
this.emit("parseError", { error: err, line });
|
|
119
139
|
}
|
|
120
140
|
}
|
|
@@ -143,7 +163,7 @@ export class TraceCollector extends EventEmitter {
|
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
if (lifecycleDebug) {
|
|
146
|
-
console.log(
|
|
166
|
+
console.log(`[LIFECYCLE collector] [${Date.now()}] RECEIVED:`, trace.name, 'depth:', trace.depth, 'correlationId:', trace.correlationId);
|
|
147
167
|
} else if (debug) {
|
|
148
168
|
console.log('[collector] RECEIVED:', trace.name, 'depth:', trace.depth, 'correlationId:', trace.correlationId);
|
|
149
169
|
}
|
|
@@ -182,6 +202,12 @@ export class TraceCollector extends EventEmitter {
|
|
|
182
202
|
return;
|
|
183
203
|
}
|
|
184
204
|
|
|
205
|
+
const lifecycleDebug = process.env.TAIST_TRACE_LIFECYCLE === 'true';
|
|
206
|
+
|
|
207
|
+
if (lifecycleDebug) {
|
|
208
|
+
console.log(`[LIFECYCLE collector] [${Date.now()}] stop() called, connections:`, this.connections.size);
|
|
209
|
+
}
|
|
210
|
+
|
|
185
211
|
// Send shutdown signal to all connected workers
|
|
186
212
|
const shutdownMessage = JSON.stringify({ type: 'shutdown' }) + '\n';
|
|
187
213
|
for (const socket of this.connections) {
|
|
@@ -198,45 +224,87 @@ export class TraceCollector extends EventEmitter {
|
|
|
198
224
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
199
225
|
}
|
|
200
226
|
|
|
227
|
+
if (lifecycleDebug) {
|
|
228
|
+
console.log('[LIFECYCLE collector] After wait, remaining connections:', this.connections.size);
|
|
229
|
+
}
|
|
230
|
+
|
|
201
231
|
return new Promise((resolve) => {
|
|
202
|
-
//
|
|
203
|
-
|
|
232
|
+
// If all connections closed gracefully, we're done
|
|
233
|
+
if (this.connections.size === 0) {
|
|
234
|
+
this._finishStop(resolve);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Track sockets that need closing
|
|
239
|
+
const socketsToClose = new Set(this.connections);
|
|
240
|
+
let closedCount = 0;
|
|
241
|
+
|
|
242
|
+
const onSocketClosed = (socket) => {
|
|
243
|
+
socketsToClose.delete(socket);
|
|
244
|
+
closedCount++;
|
|
245
|
+
if (lifecycleDebug) {
|
|
246
|
+
console.log('[LIFECYCLE collector] Socket closed during shutdown, remaining:', socketsToClose.size);
|
|
247
|
+
}
|
|
248
|
+
if (socketsToClose.size === 0) {
|
|
249
|
+
clearTimeout(forceCloseTimeout);
|
|
250
|
+
this._finishStop(resolve);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Set up close handlers for remaining sockets
|
|
255
|
+
for (const socket of socketsToClose) {
|
|
256
|
+
socket.once('close', () => onSocketClosed(socket));
|
|
204
257
|
try {
|
|
258
|
+
// socket.end() sends FIN but allows pending data to be read
|
|
205
259
|
socket.end();
|
|
206
260
|
} catch {
|
|
207
|
-
|
|
261
|
+
// Socket already closed
|
|
262
|
+
onSocketClosed(socket);
|
|
208
263
|
}
|
|
209
264
|
}
|
|
210
265
|
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
266
|
+
// Force close after extended grace period (500ms instead of 100ms)
|
|
267
|
+
// This gives more time for in-flight data to be received
|
|
268
|
+
const forceCloseTimeout = setTimeout(() => {
|
|
269
|
+
if (lifecycleDebug) {
|
|
270
|
+
console.log('[LIFECYCLE collector] Force closing', socketsToClose.size, 'remaining sockets');
|
|
271
|
+
}
|
|
272
|
+
for (const socket of socketsToClose) {
|
|
215
273
|
try {
|
|
216
274
|
socket.destroy();
|
|
217
275
|
} catch {
|
|
218
276
|
// Ignore
|
|
219
277
|
}
|
|
220
278
|
}
|
|
221
|
-
this.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
279
|
+
this._finishStop(resolve);
|
|
280
|
+
}, 500);
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
_finishStop(resolve) {
|
|
285
|
+
const lifecycleDebug = process.env.TAIST_TRACE_LIFECYCLE === 'true';
|
|
286
|
+
|
|
287
|
+
this.connections.clear();
|
|
288
|
+
|
|
289
|
+
// Close server
|
|
290
|
+
this.server.close(() => {
|
|
291
|
+
this.started = false;
|
|
292
|
+
|
|
293
|
+
// Clean up socket file
|
|
294
|
+
if (process.platform !== "win32") {
|
|
295
|
+
try {
|
|
296
|
+
fs.unlinkSync(this.socketPath);
|
|
297
|
+
} catch {
|
|
298
|
+
// Ignore
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (lifecycleDebug) {
|
|
303
|
+
console.log('[LIFECYCLE collector] Stopped, total traces collected:', this.traces.length);
|
|
304
|
+
}
|
|
235
305
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
239
|
-
}, 100); // 100ms grace period for data to be read
|
|
306
|
+
this.emit("stopped");
|
|
307
|
+
resolve();
|
|
240
308
|
});
|
|
241
309
|
}
|
|
242
310
|
|
package/lib/trace-reporter.js
CHANGED
|
@@ -317,10 +317,16 @@ export class TraceReporter extends EventEmitter {
|
|
|
317
317
|
const traces = this.buffer.splice(0, this.buffer.length);
|
|
318
318
|
|
|
319
319
|
if (lifecycleDebug) {
|
|
320
|
-
|
|
320
|
+
const now = Date.now();
|
|
321
|
+
console.log(`[LIFECYCLE reporter] [${now}] SENDING`, traces.length, 'traces to collector');
|
|
321
322
|
for (const t of traces) {
|
|
322
323
|
console.log('[LIFECYCLE reporter] -', t.name, 'depth:', t.depth);
|
|
323
324
|
}
|
|
325
|
+
// Log socket state to diagnose connection issues
|
|
326
|
+
console.log(`[LIFECYCLE reporter] [${now}] Socket state: destroyed=`, this.socket.destroyed,
|
|
327
|
+
'writableEnded=', this.socket.writableEnded,
|
|
328
|
+
'readableEnded=', this.socket.readableEnded,
|
|
329
|
+
'pending=', this.socket.pending);
|
|
324
330
|
}
|
|
325
331
|
|
|
326
332
|
const message = JSON.stringify({
|
|
@@ -330,17 +336,21 @@ export class TraceReporter extends EventEmitter {
|
|
|
330
336
|
});
|
|
331
337
|
|
|
332
338
|
return new Promise((resolve, reject) => {
|
|
333
|
-
this.socket.write(message + "\n", (err) => {
|
|
339
|
+
const writeResult = this.socket.write(message + "\n", (err) => {
|
|
334
340
|
if (err) {
|
|
335
|
-
if (lifecycleDebug) console.log('[LIFECYCLE reporter]
|
|
341
|
+
if (lifecycleDebug) console.log('[LIFECYCLE reporter] WRITE CALLBACK error:', err.message);
|
|
336
342
|
// Put traces back in buffer on failure
|
|
337
343
|
this.buffer.unshift(...traces);
|
|
338
344
|
reject(err);
|
|
339
345
|
} else {
|
|
346
|
+
if (lifecycleDebug) console.log('[LIFECYCLE reporter] WRITE CALLBACK success for', traces.length, 'traces');
|
|
340
347
|
this.emit("flushed", { count: traces.length });
|
|
341
348
|
resolve();
|
|
342
349
|
}
|
|
343
350
|
});
|
|
351
|
+
if (lifecycleDebug) {
|
|
352
|
+
console.log('[LIFECYCLE reporter] socket.write() returned:', writeResult, '(true=flushed to kernel, false=buffered)');
|
|
353
|
+
}
|
|
344
354
|
});
|
|
345
355
|
}
|
|
346
356
|
|