Problem
The in-process, workerd, and dynamic Worker app tool executors implement invocation timeouts with Promise.race, but they do not clear the timeout when the tool invocation settles first.
Each successful invocation therefore retains its timer and closure until the configured deadline. In the in-process Node runtime, the active timer also keeps the event loop alive.
Reproduction
Run a successful in-process app tool invocation with a 30-second timeout in a child Node process.
The invocation completes and prints its result immediately, but the child remains alive past a five-second process deadline because the losing timeout is still active.
Expected behavior
The timeout should be cleared as soon as the race settles, whether the invocation succeeds, fails, or times out.
The existing timeout duration and AppExecutorError behavior should remain unchanged. The emitted workerd and dynamic Worker drivers should follow the same timer lifecycle as the in-process executor.
Problem
The in-process, workerd, and dynamic Worker app tool executors implement invocation timeouts with
Promise.race, but they do not clear the timeout when the tool invocation settles first.Each successful invocation therefore retains its timer and closure until the configured deadline. In the in-process Node runtime, the active timer also keeps the event loop alive.
Reproduction
Run a successful in-process app tool invocation with a 30-second timeout in a child Node process.
The invocation completes and prints its result immediately, but the child remains alive past a five-second process deadline because the losing timeout is still active.
Expected behavior
The timeout should be cleared as soon as the race settles, whether the invocation succeeds, fails, or times out.
The existing timeout duration and
AppExecutorErrorbehavior should remain unchanged. The emitted workerd and dynamic Worker drivers should follow the same timer lifecycle as the in-process executor.