Skip to content

fix(core): offload agent execution setup from caller thread - #2464

Open
Sparkle6979 wants to merge 3 commits into
agentscope-ai:mainfrom
Sparkle6979:agent/offload-before-agent-execution
Open

fix(core): offload agent execution setup from caller thread#2464
Sparkle6979 wants to merge 3 commits into
agentscope-ai:mainfrom
Sparkle6979:agent/offload-before-agent-execution

Conversation

@Sparkle6979

@Sparkle6979 Sparkle6979 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Move agent execution preparation onto Reactor bounded elastic threads so potentially blocking setup work does not run on the caller/event-loop thread.

Fixes #2462.

Details

ReActAgent.beforeAgentExecution may synchronously load AgentState through AgentStateStore#get. Some AgentStateStore implementations can be backed by Redis, MySQL, COS, or filesystem storage, so doing this work on the caller thread can block an event-loop style caller.

This change wraps the beforeAgentExecution and graceful-shutdown request binding step in Mono.fromCallable(...).subscribeOn(Schedulers.boundedElastic()), while keeping the existing per-key serialization gate and preserving the case where beforeAgentExecution returns null.

Validation

  • Ran: mvn -pl agentscope-core spotless:apply
  • Ran: git diff --cached --check before commit

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@CLAassistant

CLAassistant commented Jul 28, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Sparkle6979
Sparkle6979 marked this pull request as ready for review July 28, 2026 12:35
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@oss-maintainer oss-maintainer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review: Approve ✅

Clean fix for #2462 — correctly offloads potentially blocking beforeAgentExecution setup from the caller/event-loop thread onto Schedulers.boundedElastic().

Analysis

Problem: runLifecycleBody called beforeAgentExecution synchronously, which triggers AgentStateStore.get(). Backed by Redis/MySQL/filesystem, this blocks the caller thread — problematic in event-loop style callers.

Solution: Wrap beforeAgentExecution + bindRequestState in Mono.fromCallable(...).subscribeOn(Schedulers.boundedElastic()). The PreparedExecution record cleanly carries the scope out of the callable.

Observations

  1. Correctness ✅ — The scope == null path is preserved: PreparedExecution wraps null, and the flatMap branch skips contextWrite when scope is null. Semantically identical to the original.
  2. Scheduler choice ✅ — boundedElastic is the right pool for blocking I/O (Redis/MySQL/fs). Does not steal from the computation pool.
  3. Per-key serialization gate ✅ — Unchanged; the existing gate still serializes correctly since subscribeOn only affects the fromCallable segment.
  4. Tests ✅ — 105 lines of new tests covering the threading behavior. Good coverage.
  5. Scope — Minimal, focused change. 2 files, +140/-18.

Note

CLA is not yet signed — author needs to complete the CLA check before merge.

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@oss-maintainer oss-maintainer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review: Offload agent execution setup from caller thread

Verdict: Approved ✅ (pending CLA signature)

Good fix for the event-loop blocking issue reported in #2462. The approach is sound and well-targeted.

Analysis

  • Root cause correctly identifiedReActAgent.beforeAgentExecution may synchronously load AgentState through AgentStateStore#get, which can be backed by Redis/MySQL/COS/filesystem. Running this on the caller/event-loop thread is a blocking risk.
  • Solution — wrapping beforeAgentExecution + bindRequestState in Mono.fromCallable(...).subscribeOn(Schedulers.boundedElastic()) correctly offloads the blocking work. The PreparedExecution record cleanly bundles the result.
  • Serialization gate preserved — the per-key lock is maintained outside the deferred block, so concurrent calls for the same session still serialize correctly.
  • Null scope case handled — when beforeAgentExecution returns null, the contextWrite is skipped as before.
  • Test coverage — 105-line test validating the offload behavior.

Blocker

  • ⚠️ CLA not signed — the contributor license agreement check is pending. This needs to be resolved before merge.

LGTM once CLA is signed.

@Sparkle6979
Sparkle6979 force-pushed the agent/offload-before-agent-execution branch from 3d4f097 to 67404d5 Compare July 28, 2026 14:09
@Sparkle6979 Sparkle6979 changed the title Offload agent execution setup from caller thread fix(core): offload agent execution setup from caller thread Jul 28, 2026
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.

io.agentscope.core.ReActAgent#beforeAgentExecution 有副作用 可能会阻塞eventLoop线程

3 participants