feat(#116): synchronous group command dispatch with multi-agent response collection

Add addGroupCommandWithReplies() to AgentRegistryService that sends commands
to all LIVE agents in a group and returns CompletableFuture per agent for
collecting replies. Update sendGroupCommand() and pushConfigToAgents() to
wait with a shared 10-second deadline, returning CommandGroupResponse with
per-agent status, timeouts, and overall success. Config update endpoint now
returns ConfigUpdateResponse wrapping both the saved config and push result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-02 19:00:56 +02:00
parent f39f07e7bf
commit 027e45aadf
5 changed files with 137 additions and 34 deletions

View File

@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -323,6 +324,28 @@ public class AgentRegistryService {
return future;
}
/**
* Send a command to all LIVE agents in a group and return futures for collecting replies.
* Returns a map of agentId -> CompletableFuture&lt;CommandReply&gt;.
*/
public Map<String, CompletableFuture<CommandReply>> addGroupCommandWithReplies(
String group, CommandType type, String payload) {
Map<String, CompletableFuture<CommandReply>> results = new LinkedHashMap<>();
List<AgentInfo> liveAgents = findByApplication(group).stream()
.filter(a -> a.state() == AgentState.LIVE)
.toList();
for (AgentInfo agent : liveAgents) {
AgentCommand cmd = addCommand(agent.instanceId(), type, payload);
CompletableFuture<CommandReply> future = new CompletableFuture<>();
pendingReplies.put(cmd.id(), future);
future.whenComplete((r, ex) -> pendingReplies.remove(cmd.id()));
results.put(agent.instanceId(), future);
}
return results;
}
/**
* Complete a pending reply future for a command.
* Called when an agent ACKs a command that was registered via {@link #addCommandWithReply}.