taist 0.1.5 → 0.1.6
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 +29 -13
- package/lib/trace-reporter.js +57 -7
- package/package.json +1 -1
package/lib/trace-collector.js
CHANGED
|
@@ -184,28 +184,44 @@ export class TraceCollector extends EventEmitter {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
return new Promise((resolve) => {
|
|
187
|
-
//
|
|
187
|
+
// Gracefully close any remaining connections (allows pending data to be read)
|
|
188
188
|
for (const socket of this.connections) {
|
|
189
|
-
|
|
189
|
+
try {
|
|
190
|
+
socket.end();
|
|
191
|
+
} catch {
|
|
192
|
+
try { socket.destroy(); } catch { /* ignore */ }
|
|
193
|
+
}
|
|
190
194
|
}
|
|
191
|
-
this.connections.clear();
|
|
192
|
-
|
|
193
|
-
// Close server
|
|
194
|
-
this.server.close(() => {
|
|
195
|
-
this.started = false;
|
|
196
195
|
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
// Give a moment for final data to arrive before destroying
|
|
197
|
+
setTimeout(() => {
|
|
198
|
+
// Force destroy any sockets that didn't close gracefully
|
|
199
|
+
for (const socket of this.connections) {
|
|
199
200
|
try {
|
|
200
|
-
|
|
201
|
+
socket.destroy();
|
|
201
202
|
} catch {
|
|
202
203
|
// Ignore
|
|
203
204
|
}
|
|
204
205
|
}
|
|
206
|
+
this.connections.clear();
|
|
207
|
+
|
|
208
|
+
// Close server
|
|
209
|
+
this.server.close(() => {
|
|
210
|
+
this.started = false;
|
|
211
|
+
|
|
212
|
+
// Clean up socket file
|
|
213
|
+
if (process.platform !== "win32") {
|
|
214
|
+
try {
|
|
215
|
+
fs.unlinkSync(this.socketPath);
|
|
216
|
+
} catch {
|
|
217
|
+
// Ignore
|
|
218
|
+
}
|
|
219
|
+
}
|
|
205
220
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
221
|
+
this.emit("stopped");
|
|
222
|
+
resolve();
|
|
223
|
+
});
|
|
224
|
+
}, 100); // 100ms grace period for data to be read
|
|
209
225
|
});
|
|
210
226
|
}
|
|
211
227
|
|
package/lib/trace-reporter.js
CHANGED
|
@@ -152,12 +152,14 @@ export class TraceReporter extends EventEmitter {
|
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
154
|
* Handle shutdown signal from collector.
|
|
155
|
-
*
|
|
155
|
+
* Flushes buffer and waits for data to be sent before closing.
|
|
156
156
|
*/
|
|
157
157
|
_handleShutdown() {
|
|
158
158
|
if (this.closed) return;
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
this._stopFlushTimer();
|
|
161
|
+
|
|
162
|
+
// Flush and wait for data to be sent
|
|
161
163
|
if (this.buffer.length > 0 && this.socket && this.connected) {
|
|
162
164
|
const traces = this.buffer.splice(0, this.buffer.length);
|
|
163
165
|
const message = JSON.stringify({
|
|
@@ -166,15 +168,63 @@ export class TraceReporter extends EventEmitter {
|
|
|
166
168
|
data: traces,
|
|
167
169
|
});
|
|
168
170
|
|
|
171
|
+
logger.debug("[reporter] Shutdown flushing", traces.length, "traces");
|
|
172
|
+
|
|
169
173
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
174
|
+
// Write data
|
|
175
|
+
const flushed = this.socket.write(message + "\n");
|
|
176
|
+
|
|
177
|
+
if (flushed) {
|
|
178
|
+
// Data was written to kernel buffer, use setImmediate to allow
|
|
179
|
+
// the event loop to process and send the data before closing
|
|
180
|
+
setImmediate(() => {
|
|
181
|
+
this._gracefulClose();
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
// Buffer is full, wait for drain
|
|
185
|
+
this.socket.once('drain', () => {
|
|
186
|
+
logger.debug("[reporter] Drained, closing");
|
|
187
|
+
this._gracefulClose();
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
} catch (err) {
|
|
191
|
+
logger.debug("[reporter] Write error:", err.message);
|
|
175
192
|
this.close();
|
|
176
193
|
}
|
|
177
194
|
} else {
|
|
195
|
+
this._gracefulClose();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Close connection gracefully, allowing pending data to be sent.
|
|
201
|
+
*/
|
|
202
|
+
_gracefulClose() {
|
|
203
|
+
if (!this.socket) {
|
|
204
|
+
this.close();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Use socket.end() for graceful TCP close (sends FIN, allows pending data)
|
|
209
|
+
// Add a small delay to allow the collector to read the data
|
|
210
|
+
this.socket.once('close', () => {
|
|
211
|
+
logger.debug("[reporter] Socket closed gracefully");
|
|
212
|
+
this.closed = true;
|
|
213
|
+
this.connected = false;
|
|
214
|
+
this.socket = null;
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Set a timeout in case close doesn't happen
|
|
218
|
+
const closeTimeout = setTimeout(() => {
|
|
219
|
+
logger.debug("[reporter] Close timeout, forcing");
|
|
220
|
+
this.close();
|
|
221
|
+
}, 500);
|
|
222
|
+
closeTimeout.unref();
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
this.socket.end();
|
|
226
|
+
} catch {
|
|
227
|
+
clearTimeout(closeTimeout);
|
|
178
228
|
this.close();
|
|
179
229
|
}
|
|
180
230
|
}
|