Skip to content

Add Invoke batching#3065

Open
Apollon77 wants to merge 3 commits intomainfrom
invoke-batching
Open

Add Invoke batching#3065
Apollon77 wants to merge 3 commits intomainfrom
invoke-batching

Conversation

@Apollon77
Copy link
Collaborator

invokes are now batched (when device supports it and non-root-endopoint and not groups) within the same macro-task

invokes are now batched (when device supports it and non-root-endopoint and not groups) within the same macro-task
@Apollon77 Apollon77 requested a review from lauckhart as a code owner January 22, 2026 08:27
Copilot AI review requested due to automatic review settings January 22, 2026 08:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds automatic command batching to improve efficiency when multiple commands are invoked on a Matter device within the same timer tick. Commands sent to devices that support batching (maxPathsPerInvoke > 1) are now collected and sent as a single batched invoke request, reducing network overhead.

Changes:

  • Introduced CommandInvoker base class and CommandBatcher extension for intelligent command batching
  • Refactored ClientCommandMethod to use the new invoker infrastructure
  • Added batching support in ClientNodeInteraction while maintaining non-batching behavior for groups via ClientGroupInteraction

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/node/src/node/client/commands/CommandInvoker.ts New base class for command invocation with immediate execution logic
packages/node/src/node/client/commands/CommandBatcher.ts Implements batching logic that collects commands within a timer tick and sends them as a single request
packages/node/src/node/client/commands/ClientCommandMethod.ts Refactored to use the new invoker.invoke() API for batching support
packages/node/src/node/client/ClientNodeInteraction.ts Integrated CommandBatcher and added cleanup in close() method
packages/node/src/node/client/ClientGroupInteraction.ts Overrides to use plain CommandInvoker without batching for groups
packages/node/src/node/client/PeerBehavior.ts Updated import path for moved ClientCommandMethod
packages/node/src/node/ClientNode.ts Added prepareRuntimeShutdown() to close interaction and clean up batcher
packages/node/test/node/CommandBatcherTest.ts Comprehensive test suite covering batching scenarios, cache clearing, and error handling
packages/node/test/node/ClientNodeTest.ts Updated tests to use MockTime.resolve() for batched commands
packages/node/test/behaviors/scenes-management/ScenesManagementServerTest.ts Updated tests to use MockTime.resolve() for batched commands
packages/node/test/behaviors/group-key-management/GroupKeyManagementServerTest.ts Added comment explaining why root endpoint commands don't need MockTime.resolve()
CHANGELOG.md Documented the enhancement

*
* Extends {@link CommandInvoker} to add batching capability on top of single command invocation.
*/
export class CommandBatcher extends CommandInvoker {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would CommandBatch be an OK name?

Also, wondering if there's a reason to have a single instance for all batches vs. creating on-demand and integrating close/flush into a single process

async [name](this: ClusterBehavior, fields?: {}) {
const node = this.env.get(Node) as ClientNode;

return (node.interaction as ClientNodeInteraction).invoker.invoke({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the benefit of implementing this outside of ClientNodeInteraction vs. making it an internal implementation detail of invoke?

* This class is used directly for groups (which don't support batching)
* and extended by {@link CommandBatcher} for nodes that support batched invokes.
*/
export class CommandInvoker {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a more general way to implement this so that it only deals with an Interactable rather than a Node? Then it wouldn't need to be in @matter/node

The benefit of sticking stuff in @matter/protocol is that it avoids tight coupling between components... In order to keep packages well balanced I think we should consider @matter/protocol to include both low-level protocol implementation and associated helper logic. Otherwise I worry @matter/node is going to just become another big intertwined @project-chip/matter.js.

Same goes for CommandBatcher

/**
* The node this interaction is associated with.
*/
protected get node(): ClientNode {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little leary of exposing internal implementation details like this as if you need to ask an Interactable what it's node is then you're limiting the flexibility of your logic.

And we already have a way to convey "this logic requires a ClientNodeInteraction + ClientNode", which is just to take the ClientNode as an argument instead of ClientNodeInteraction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants