Skip to content

fix(azure-foundry): stateless getAgentStatus for multi-replica deployments - #1446

Open
shaileshpadave wants to merge 5 commits into
mainfrom
fix/azure-foundry-stateless-status-poll
Open

fix(azure-foundry): stateless getAgentStatus for multi-replica deployments#1446
shaileshpadave wants to merge 5 commits into
mainfrom
fix/azure-foundry-stateless-status-poll

Conversation

@shaileshpadave

Copy link
Copy Markdown
Contributor

Problem

AzureFoundryAgentClient stored per-run state (endpoint, runId, token provider) in an in-memory ConcurrentHashMap keyed by threadId. In multi-replica server deployments the 5-second status-poll callback arrives on a different pod than the one that ran startAgent, causing "No execution found" failures on every execution.

Confirmed on a 3-pod cluster: pod A runs startAgent, pod B/C handles the callback → empty map → task FAILED.

Fix

startAgent now returns a compound executionId that base64-encodes the non-sensitive run context {threadId, runId, endpoint, assistantId, apiVersion}. getAgentStatus decodes this to reconstruct the Azure API call on any pod and re-authenticates using the original task credentialRef.

Interface change: ConductorAgentClient.getAgentStatus(String) gains a ConductorAgentRequest parameter so implementations can access credentials without in-process state. All five implementations and both test fakes are updated.

The respondContexts map is retained only for respond()/cancelAgent() (multi-turn WAITING), which receive no credentialRef. Single-turn agents (the common case) no longer depend on in-memory state.

Test plan

  • ./gradlew :conductor-ai:compileJava :conductor-ai:compileTestJava :conductor-agentspan:compileJava passes
  • ./gradlew :conductor-ai:test passes
  • ./gradlew :conductor-agentspan:spotlessCheck passes
  • Azure agent workflows succeed on a 3-pod cluster (requires deployment)

…eployments

AzureFoundryAgentClient stored per-run state (endpoint, runId, token provider)
in an in-memory ConcurrentHashMap keyed by threadId. In multi-replica server
deployments the 5-second status-poll callback could arrive on a different pod
than the one that ran startAgent, causing "No execution found" failures on every
execution after the first.

Fix: startAgent now returns a compound executionId that base64-encodes the
non-sensitive run context {threadId, runId, endpoint, assistantId, apiVersion}.
getAgentStatus decodes this to reconstruct the Azure API call on any pod and
re-authenticates using the original task credentialRef, which is available in
the ConductorAgentRequest passed by the updated ConductorAgentDelegate.

Interface change: ConductorAgentClient.getAgentStatus(String) gains a second
ConductorAgentRequest parameter. All five implementations and both test fakes
are updated. ServiceConductorAgentClient ignores the new parameter (AgentService
has its own persistent state). BedrockAgentClient signature is updated; its
in-memory model is unchanged pending a follow-up — the stateless fix for Bedrock
requires a similar compound-executionId approach.

The respondContexts map is retained for respond() and cancelAgent(), which
receive no credentialRef and therefore cannot re-authenticate on a different
replica; single-turn agents (the common case) no longer use it.
…RunStore SPI

Following the same pattern as ServiceConductorAgentClient -> AgentService,
run context (threadId, runId, endpoint, credentialRef, scope) is now persisted
in an injected AzureAgentRunStore rather than encoded in the executionId.

The default store is in-memory (InMemoryAzureAgentRunStore, @ConditionalOnMissingBean);
HA deployments can substitute a Redis or DB-backed implementation, mirroring how
orkes-conductor overrides SkillMetadataDAO and SkillPackageStore.

This also removes the previous same-pod limitation on respond() and cancelAgent():
by storing credentialRef in the run context, any replica can re-authenticate and
handle multi-turn and cancellation requests without in-process state.
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.

1 participant