mirror of
https://github.com/appium/appium.git
synced 2026-10-29 21:11:02 +08:00
* fix(appium): track idle timeout across plugin commands * fix(base-driver): guard timeout restarts from legacy drivers * review * fix(base-driver)!: require shared command activity tracking Remove legacy timer method overrides and the compatibility capability flag. Document the driver migration requirement and verify shared activity across ESM copies without replacing timer methods. BREAKING CHANGE: Drivers must use base-driver with shared command activity tracking. Custom timeout implementations must delegate timer creation to super.startNewCommandTimeout(); legacy private-counter implementations are no longer protected by method overrides. * add fake driver/plugin example * remove from readme * Remove actions needed for driver updates in migration guide Removed the section detailing actions needed for driver updates related to shared command activity tracking. * refactor(base-driver): simplify shutdown promise handling * Add actions needed for custom startNewCommandTimeout Updated migration guide to include new requirements for custom command timeout implementations.
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import type {Driver} from '@appium/types';
|
|
|
|
type TimeoutDriver = Pick<
|
|
Driver,
|
|
'clearNewCommandTimeout' | 'startNewCommandTimeout' | 'isCommandsQueueEnabled' | 'sessionId'
|
|
> & {shutdownUnexpectedly?: boolean};
|
|
|
|
// Drivers installed in APPIUM_HOME may load another copy of base-driver. Share activity
|
|
// tokens so their HTTP commands and the server's plugin/BiDi wrappers protect each other.
|
|
const STORE_KEY = Symbol.for('@appium/base-driver:command-activity');
|
|
const stores = globalThis as typeof globalThis & {[STORE_KEY]?: WeakMap<object, Set<symbol>>};
|
|
const activeCommands = (stores[STORE_KEY] ??= new WeakMap<object, Set<symbol>>());
|
|
|
|
/** Whether a driver has commands or plugin handlers still in flight. */
|
|
export function hasRunningCommands(driver: object): boolean {
|
|
return (activeCommands.get(driver)?.size ?? 0) > 0;
|
|
}
|
|
|
|
/**
|
|
* Suspend the idle timer until the last overlapping command or plugin handler finishes.
|
|
* Requires a driver whose startNewCommandTimeout honors shared command activity, as BaseDriver does.
|
|
*/
|
|
export async function runWithCommandTimeout<T>(
|
|
driver: TimeoutDriver,
|
|
command: () => Promise<T>,
|
|
{restart = true}: {restart?: boolean | (() => boolean)} = {},
|
|
): Promise<T> {
|
|
let activity = activeCommands.get(driver);
|
|
if (!activity) {
|
|
activity = new Set();
|
|
activeCommands.set(driver, activity);
|
|
}
|
|
const token = Symbol();
|
|
activity.add(token);
|
|
try {
|
|
await driver.clearNewCommandTimeout();
|
|
return await command();
|
|
} finally {
|
|
activity.delete(token);
|
|
if (activity.size === 0) {
|
|
activeCommands.delete(driver);
|
|
if (
|
|
(typeof restart === 'function' ? restart() : restart) &&
|
|
Boolean(driver.sessionId) &&
|
|
!driver.shutdownUnexpectedly &&
|
|
driver.isCommandsQueueEnabled
|
|
) {
|
|
await driver.startNewCommandTimeout();
|
|
}
|
|
}
|
|
}
|
|
}
|