Compare commits

...
Author SHA1 Message Date
Vitali Zaidman 760af1499d dev-middleware: Remove redundant async queuing (#49982)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/49982

In D68708899, we removed dataURI inlining of sources and source maps into `Debugger.scriptParsed` CDP notifications.

After that, all message handling for which we need to preserve order is implemented completely synchronously, so there's no need for a promise queue to preserve order.

This removes the redundant queue.

Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D71036230
2025-03-24 07:35:03 -07:00
3 changed files with 30 additions and 154 deletions
@@ -1,72 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
// $FlowFixMe[cannot-resolve-module] libdef missing in RN OSS
import type {Timeout} from 'timers';
// $FlowFixMe[cannot-resolve-module] libdef missing in RN OSS
import {setTimeout} from 'timers';
const MAX_QUEUE_TIME_SPAN_MS = 3000;
export default class CDPMessagesQueueLogging {
#messageQueueSize = 0;
#maxMessageQueueSize = 0;
#messagesMemoryUsage = 0;
#maxMessageQueueCombinedStringSize = 0;
#loggingTimeout: Timeout | null = null;
#debounceStartMs = 0;
#onHighMessageQueueSize: (queueSize: number, memoryUsageMiB: number) => void;
constructor(
onHighMessageQueueSize: (queueSize: number, memoryUsageMiB: number) => void,
) {
this.#onHighMessageQueueSize = onHighMessageQueueSize;
}
messageReceived(messageSize: number) {
this.#messageQueueSize++;
this.#messagesMemoryUsage += messageSize;
if (this.#messageQueueSize > this.#maxMessageQueueSize) {
this.#maxMessageQueueSize = this.#messageQueueSize;
this.#maxMessageQueueCombinedStringSize = this.#messagesMemoryUsage;
// we only report when there were no higher queue size reached for MAX_QUEUE_TIME_SPAN_MS
if (this.#loggingTimeout) {
this.#loggingTimeout.refresh();
} else {
this.#debounceStartMs = Date.now();
this.#loggingTimeout = setTimeout(() => {
this.#onHighMessageQueueSize(
this.#maxMessageQueueSize,
// JS uses around 2 bytes per character
this.#maxMessageQueueCombinedStringSize * 2,
);
this.#loggingTimeout = null;
this.#maxMessageQueueSize = 0;
this.#maxMessageQueueCombinedStringSize = 0;
}, MAX_QUEUE_TIME_SPAN_MS).unref();
}
}
}
messageProcessed(messageSize: number) {
this.#messageQueueSize--;
this.#messagesMemoryUsage -= messageSize;
}
}
@@ -28,7 +28,6 @@ import type {
} from './types';
import CDPMessagesLogging from './CDPMessagesLogging';
import CDPMessagesQueueLogging from './CDPMessagesQueueLogging';
import DeviceEventReporter from './DeviceEventReporter';
import * as fs from 'fs';
import invariant from 'invariant';
@@ -97,14 +96,6 @@ export default class Device {
// Package name of the app.
#app: string;
// Sequences async processing of messages from device to preserve order. Only
// necessary while we need to accommodate #processMessageFromDeviceLegacy's
// async fetch.
#messageFromDeviceQueue: Promise<void> = Promise.resolve();
// Logging reporting the maximum size of cdp message coming from device in the queue for processing
#messageFromDeviceQueueLogging: ?CDPMessagesQueueLogging;
// Stores socket connection between Inspector Proxy and device.
#deviceSocket: WS;
@@ -170,37 +161,6 @@ export default class Device {
this.#id = id;
this.#name = name;
this.#app = app;
const deviceConnectedTimestamp = Date.now();
this.#messageFromDeviceQueueLogging = new CDPMessagesQueueLogging(
(maxCDPMessageQueueSize: number, maxCDPMessageQueueMemory: number) => {
if (maxCDPMessageQueueMemory > MIN_MESSAGE_QUEUE_BYTES_TO_REPORT) {
debug(
"CDP messages proxy queue reached='%d' messages using at least '%sMiB' coming from device='%s' for app='%s'",
maxCDPMessageQueueSize,
String(maxCDPMessageQueueMemory / 1024 / 1024).slice(0, 6),
name,
app,
);
const debuggerSessionIDs = {
appId: app,
deviceId: id,
deviceName: name,
pageId: null,
};
eventReporter?.logEvent({
type: 'device_high_message_queue',
maxCDPMessageQueueSize,
maxCDPMessageQueueMemory,
connectionUptime: Date.now() - deviceConnectedTimestamp,
...debuggerSessionIDs,
});
}
},
);
this.#deviceSocket = socket;
this.#projectRoot = projectRoot;
this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
@@ -220,40 +180,35 @@ export default class Device {
// $FlowFixMe[incompatible-call]
this.#deviceSocket.on('message', (message: string) => {
this.#messageFromDeviceQueueLogging?.messageReceived(message.length);
this.#messageFromDeviceQueue = this.#messageFromDeviceQueue
.then(async () => {
const parsedMessage = JSON.parse(message);
if (parsedMessage.event === 'getPages') {
// There's a 'getPages' message every second, so only show them if they change
if (message !== this.#lastGetPagesMessage) {
debug('Device getPages ping has changed: %s', message);
this.#lastGetPagesMessage = message;
}
} else {
this.#cdpMessagesLogging.log('DeviceToProxy', message);
try {
const parsedMessage = JSON.parse(message);
if (parsedMessage.event === 'getPages') {
// There's a 'getPages' message every second, so only show them if they change
if (message !== this.#lastGetPagesMessage) {
debug('Device getPages ping has changed: %s', message);
this.#lastGetPagesMessage = message;
}
await this.#handleMessageFromDevice(parsedMessage);
})
.catch(error => {
debug('%O\nHandling device message: %s', error, message);
try {
this.#deviceEventReporter?.logProxyMessageHandlingError(
'device',
error,
message,
);
} catch (loggingError) {
debug(
'Error logging message handling error to reporter: %O',
loggingError,
);
}
})
.finally(() => {
this.#messageFromDeviceQueueLogging?.messageProcessed(message.length);
});
} else {
this.#cdpMessagesLogging.log('DeviceToProxy', message);
}
this.#handleMessageFromDevice(parsedMessage);
} catch (error) {
debug('%O\nHandling device message: %s', error, message);
try {
this.#deviceEventReporter?.logProxyMessageHandlingError(
'device',
error,
message,
);
} catch (loggingError) {
debug(
'Error logging message handling error to reporter: %O',
loggingError,
);
}
}
});
// Sends 'getPages' request to device every PAGES_POLLING_INTERVAL milliseconds.
this.#pagesPollingIntervalId = setInterval(
() => this.#sendMessageToDevice({event: 'getPages'}),
@@ -558,7 +513,7 @@ export default class Device {
// In the future more logic will be added to this method for modifying
// some of the messages (like updating messages with source maps and file
// locations).
async #handleMessageFromDevice(message: MessageFromDevice) {
#handleMessageFromDevice(message: MessageFromDevice) {
if (message.event === 'getPages') {
// Preserve ordering - getPages guarantees addition order.
this.#pages = new Map(
@@ -664,7 +619,7 @@ export default class Device {
return;
}
await this.#processMessageFromDeviceLegacy(
this.#processMessageFromDeviceLegacy(
parsedPayload,
debuggerConnection,
pageId,
@@ -787,7 +742,7 @@ export default class Device {
}
// Allows to make changes in incoming message from device.
async #processMessageFromDeviceLegacy(
#processMessageFromDeviceLegacy(
payload: CDPServerMessage,
debuggerInfo: DebuggerConnection,
pageId: ?string,
@@ -131,13 +131,6 @@ export type ReportableEvent =
duration: number,
...ConnectionUptime,
...DebuggerSessionIDs,
}
| {
type: 'device_high_message_queue',
maxCDPMessageQueueSize: number,
maxCDPMessageQueueMemory: number,
...ConnectionUptime,
...DebuggerSessionIDs,
};
/**