You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by zf...@apache.org on 2025/12/18 06:47:12 UTC

(incubator-seata-go) branch master updated: Feature/saga (#1030)

This is an automated email from the ASF dual-hosted git repository.

zfeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-seata-go.git


The following commit(s) were added to refs/heads/master by this push:
     new c39fcc63 Feature/saga (#1030)
c39fcc63 is described below

commit c39fcc63f7eb0b19c8b2d98f5ec668066ae3a676
Author: FengZhang <zf...@qq.com>
AuthorDate: Thu Dec 18 14:47:07 2025 +0800

    Feature/saga (#1030)
    
    * feature: init saga framework (#635)
    
    init saga framework
    
    * refactor: refactor saga scaffold to break import cycles (#647)
    
    * feature: add serverice task parse in statelang (#650)
    
    * feature: add saga persistence layer (#649)
    
    * feat: add grpc invoker in saga mode (#668)
    
    * feat: add grpc invoker in saga mode
    
    * fix: fix some chores
    
    * feature: add default implementation for StateMachineConfig (#669)
    
    * feature saga :support generate id by Snowflake (#670)
    
    * feature: sequential execution of state machine in Saga (#681)
    
    * feat: add func invoker (#744)
    
    * add func task state
    
    * [to-reply] feature: support saga multi type config (#741)
    
    * added yaml format of statelang related test data
    
    * feature: implement multi type config parser
    
    * adjust statemachine_json_parser to suit config parser
    
    * bugfix: fix the problem of failure to parse "ServiceName"
    
    * adjust statemachine_parser to be compatible with yaml
    
    * add apache License, add some comments, and make some logical adjustments
    
    * update state_machine_new_designer.yaml
    
    * optimize and improve the unit test of config parser
    
    * refactor config parser
    
    * add apache License
    
    * update
    
    * [Refactor] Migrate StateMachineObject to client/config and unify config parsing with koanf (#785)
    
    * optimize saga config reuse
    
    * upd-test
    
    * Modularize SagaConfig into independent configuration structure
    
    * feat: HttpServiceTaskState Support (#769)
    
    * support http invoker for sage engine
    
    * fix comment language
    
    * Feature: Database persistence for seata-go Saga state machine (#794)
    
    * implement state machine repository
    
    * temporary recording
    
    * temporary recording
    
    * temporary storage
    
    * Supplementary test
    
    * feat: Supplement the statelog_repository section in Database persistence for Saga state machine (#800)
    
    * fix: Wrong commit
    
    * feat:add state_log_repository
    
    * fix: conflicts and wrong commit
    
    * fix: delete Remove redundant singleton patterns
    
    * Feature/saga interface optimization (#778)
    
    feature: saga Interface optimization
    
    * refactor: implement pending TODOs in machine status_decision logic (#808)
    
    * refactor: implement pending TODOs in machine status_decision logic
    
    * feat(status-decision): add detailed logs to methods for better debugging
    
    * Feat cel expression (#788)
    
    * implement cel expression
    
    * move sequence expression into a new file
    
    * mv expression factory into a new file
    
    * move expression factory manager into a new file
    
    * implement cel expression factory and add test
    
    * move expression resolver into a new file
    
    * add parse expression struct test
    
    * update
    
    * update go.mod
    
    ---------
    
    Co-authored-by: FengZhang <zf...@qq.com>
    
    * change the StateLangStore type (#812)
    
    * Revert "bugfix:Remove issue translation workflow as usthe/issues-translate-action@v2.7 does not allow issues in apache/incubator-seata-go" (#822)
    
    Revert "bugfix:Remove issue translation workflow as usthe/issues-translate-ac…"
    
    This reverts commit 018486951c9031caacf151c018f647e81b2f1c11.
    
    * refactor-engine/core (#838)
    
    * refactor-engine/core
    
    * Decouple the core package
    
    * Feature: finish implementation for StateMachineConfig  (#805)
    
    * finish implementation for StateMachineConfig
    
    * reuse the exiting logic from statemachine_config_parser.go
    
    * add_license&change_cn_to_en&fix_logic
    
    * sort imports & rename struct & change the visbility
    
    * Merge feature/saga into feature/saga-config-selection-and-loading
    
    * fix_conflict_from_expression-pr
    
    * fix_test&Lock-logic_from_invoker.go
    
    * change_method_name
    
    * add-seqGenerator_init
    
    * add-event_bus&event_publiser-init
    
    * add-status_desicion-init & enhence-validate_method
    
    * refactor: move error_expression-about to expr
    
    * fix: stateMachineResources-load
    
    * fix - test
    
    * Optimize the judgment of persistence-related components.
    
    * Optimize the logic of loadconfig and statemachineresource.
    
    * add-store-init
    
    * refactor-engine/core
    
    * Decouple the core package
    
    * Update default_statemachine_config_test.go
    
    ---------
    
    Co-authored-by: FengZhang <zf...@qq.com>
    
    * Decouple the transaction from the statelog (#841)
    
    * Decouple the transaction from the statelog
    
    * Decouple the transaction from the statelog
    
    * Decouple the transaction from the statelog
    
    * Resolve Merge Conflicts, Add Persistence Initialization, and Optimize Tests (#847)
    
    * fix-conflict&add-store-component-init&fix-test
    
    * Update process_ctrl_statemachine_engine.go
    
    * Feature/add script manager&actuator (#868)
    
    * add script manager & actuator
    
    * Otto package replaces Goja package
    
    * Resolve the issues raised by Copilot
    
    * add test for vm-pool
    
    * update GetServiceInvoker method
    
    * Implement SagaResource and SagaResourceManager (#855)
    
    * feat : impl SagaResource #843
    
    * feat : impl SagaResource #843
    
    * feat : impl SagaResourceManager #843
    
    * feat : impl SagaResourceManager BranchRollback #843
    
    * feat : impl handler_saga #843
    
    * feat : impl invalid_exception_test #843
    
    * update #843
    
    * update:elegant code #843
    
    * abstracting tm branch registration out to rm and add test #846
    
    * test #846
    
    * add licensed  #846
    
    * replace panic to return #843
    
    * update  #843
    
    * update init and handler_saga  #843
    
    ---------
    
    Co-authored-by: FengZhang <zf...@qq.com>
    
    * Support Saga mode config initialization (#871)
    
    * remove redundant logic and methods
    
    Make the loadconfig method only responsible for loading static parameters and remove redundant memory storage
    
    * add the init method and refine other logic
    
    * remove redundant logic and methods
    
    Make the loadconfig method only responsible for loading static parameters and remove redundant memory storage
    
    * add the init method and refine other logic
    
    * update
    
    * upd
    
    ---------
    
    Co-authored-by: FengZhang <zf...@qq.com>
    
    * Saga end-to-end verification (#897)
    
    * saga support
    
    * fix bug
    
    * merge code
    
    * format
    
    * fix vet
    
    * fix vet
    
    * fix vet and lincese checker
    
    * fix lincese chekcer
    
    ---------
    
    Co-authored-by: wt_better <m1...@163.com>
    Co-authored-by: Xiangkun Yin <32...@users.noreply.github.com>
    Co-authored-by: Jingliu Xiong <92...@qq.com>
    Co-authored-by: FanOne <co...@outlook.com>
    Co-authored-by: marsevilspirit <ma...@gmail.com>
    Co-authored-by: FinnTew <na...@gmail.com>
    Co-authored-by: flypiggy <15...@users.noreply.github.com>
    Co-authored-by: lxfeng1997 <33...@users.noreply.github.com>
    Co-authored-by: 1kasa <13...@users.noreply.github.com>
    Co-authored-by: 深几许 <14...@users.noreply.github.com>
    Co-authored-by: Wiggins <12...@users.noreply.github.com>
---
 .github/workflows/issue-robot.yml                  |   33 +
 .licenserc.yaml                                    |    1 +
 go.mod                                             |   24 +-
 go.sum                                             |   35 +-
 pkg/client/client.go                               |    4 +-
 pkg/client/client_test.go                          |    9 +-
 pkg/client/config.go                               |    5 +
 pkg/datasource/sql/conn_xa.go                      |    1 +
 .../sql/datasource/base/meta_cache_test.go         |    1 +
 pkg/datasource/sql/datasource/mysql/trigger.go     |   10 +
 .../sql/datasource/mysql/trigger_test.go           |    1 +
 pkg/datasource/sql/exec/at/base_executor_test.go   |    4 +-
 pkg/datasource/sql/exec/at/update_executor.go      |    4 +-
 .../sql/exec/at/update_join_executor_test.go       |    3 +-
 pkg/datasource/sql/undo/base/undo_test.go          |    6 +-
 .../sql/undo/builder/basic_undo_log_builder.go     |    6 +-
 .../undo/builder/basic_undo_log_builder_test.go    |    6 +-
 .../sql/undo/parser/branch_undo_log.pb.go          |    5 +-
 .../sql/undo/parser/parser_protobuf_test.go        |    1 +
 pkg/datasource/sql/util/ctxutil_test.go            |    3 +-
 pkg/datasource/sql/util/lockkey.go                 |    3 +-
 pkg/datasource/sql/util/lockkey_test.go            |    1 +
 pkg/discovery/etcd3_test.go                        |   10 +-
 pkg/discovery/mock/test_etcd_client.go             |    2 +-
 pkg/protocol/codec/codec.go                        |    1 +
 pkg/protocol/codec/global_report_request_codec.go  |    3 +-
 pkg/remoting/config/config_test.go                 |    1 +
 .../loadbalance/least_active_loadbalance_test.go   |    1 +
 pkg/remoting/loadbalance/loadbalance.go            |    4 -
 pkg/rm/init.go                                     |    5 +
 pkg/rm/tcc/fence/fence.go                          |    3 +-
 .../tcc/fence/handler/tcc_fence_wrapper_handler.go |    6 +-
 pkg/rm/tcc/fence/store/db/dao/tcc_fence_db.go      |    3 +-
 pkg/rm/tcc/tcc_resource.go                         |    3 +-
 pkg/{rm/init.go => saga/config.go}                 |   20 +-
 pkg/saga/readme.md                                 |   47 +
 pkg/{rm/init.go => saga/rm/handler_saga.go}        |   21 +-
 pkg/{rm/init.go => saga/rm/saga_resource.go}       |   37 +-
 pkg/saga/rm/saga_resource_manager.go               |  159 +++
 .../rm/saga_resource_manager_test.go}              |   31 +-
 .../rm/state_machine_engine_holder.go}             |   23 +-
 .../runtime/engine_registry.go}                    |   61 +-
 pkg/saga/statemachine/constant/constant.go         |  104 ++
 pkg/saga/statemachine/engine/config/bootstrap.go   |   62 +
 .../engine/config/default_statemachine_config.go   |  824 ++++++++++++
 .../config/default_statemachine_config_test.go     |  325 +++++
 pkg/saga/statemachine/engine/config/noop_store.go  |   87 ++
 .../statemachine/engine/config/store_bootstrap.go  |   71 +
 .../engine/config/testdata/invalid.json            |    3 +
 .../engine/config/testdata/invalid.yaml            |   19 +
 .../engine/config/testdata/order_saga.json         |  274 ++++
 .../engine/config/testdata/order_saga.yaml         |  204 +++
 .../engine/config/testdata/order_saga_v2.json      |  322 +++++
 .../engine/config/testdata/order_saga_v2.yaml      |  228 ++++
 .../engine/config/testdata/saga_config.json        |   13 +
 .../engine/config/testdata/saga_config.yaml        |   25 +
 .../engine/config/testdata/saga_config_v2.json     |   13 +
 .../engine/config/testdata/saga_config_v2.yaml     |   25 +
 .../core/process_ctrl_statemachine_engine.go       |  747 +++++++++++
 .../process_ctrl_statemachine_engine_async_test.go |  345 +++++
 .../statemachine/engine/exception/exception.go     |   84 ++
 .../engine/exception/exception_test.go             |   68 +
 .../engine/exception/forward_invalid_exception.go} |   20 +-
 .../exception/forward_invalid_exception_test.go    |   68 +
 .../statemachine/engine/expr/cel_expression.go     |   96 ++
 .../engine/expr/cel_expression_factory.go}         |   22 +-
 .../engine/expr/cel_expression_factory_test.go}    |   21 +-
 .../engine/expr/cel_expression_test.go}            |   28 +-
 .../statemachine/engine/expr/error_expression.go}  |   24 +-
 .../statemachine/engine/expr/expression.go}        |   20 +-
 .../engine/expr/expression_factory.go}             |    9 +-
 .../engine/expr/expression_factory_manager.go      |   51 +
 .../engine/expr/expression_resolver.go             |  105 ++
 .../engine/expr/expression_resolver_test.go        |   70 +
 .../engine/expr/sequence_expression.go             |   64 +
 .../engine/expr/sequence_expression_factory.go     |   56 +
 .../statemachine/engine/invoker/func_invoker.go    |  225 ++++
 .../engine/invoker/func_invoker_test.go            |  168 +++
 .../statemachine/engine/invoker/grpc_invoker.go    |  263 ++++
 .../engine/invoker/grpc_invoker_test.go            |  187 +++
 .../statemachine/engine/invoker/http_invoker.go    |  220 ++++
 .../engine/invoker/http_invoker_test.go            |  179 +++
 pkg/saga/statemachine/engine/invoker/invoker.go    |  101 ++
 .../engine/invoker/javascript_script_invoker.go    |  162 +++
 .../invoker/javascript_script_invoker_test.go      |  262 ++++
 .../statemachine/engine/invoker/json_parser.go}    |   23 +-
 .../statemachine/engine/invoker/local_invoker.go   |  200 +++
 .../engine/invoker/local_invoker_test.go           |  212 +++
 .../engine/pcext/compensation_holder.go            |   92 ++
 pkg/saga/statemachine/engine/pcext/engine_utils.go |  236 ++++
 pkg/saga/statemachine/engine/pcext/instruction.go  |  113 ++
 .../engine/pcext/loop_context_holder.go            |  111 ++
 .../statemachine/engine/pcext/loop_task_utils.go   |   78 ++
 .../statemachine/engine/pcext/parameter_utils.go   |  143 ++
 .../statemachine/engine/pcext/process_handler.go   |  197 +++
 .../statemachine/engine/pcext/process_router.go    |  139 ++
 .../statemachine/engine/pcext/state_router_impl.go |  355 +++++
 .../engine/pcext/state_router_impl_test.go         |  152 +++
 .../engine/repo/repository/state_log_repository.go |  139 ++
 .../repo/repository/state_machine_repository.go    |  255 ++++
 .../repository/state_machine_repository_test.go    |  162 +++
 .../statemachine/engine/repo/statemachine_store.go |   48 +
 .../statemachine/engine/sequence/sequence.go}      |    9 +-
 pkg/saga/statemachine/engine/sequence/snowflake.go |  133 ++
 .../engine/sequence/snowflake_test.go}             |   33 +-
 .../statemachine/engine/sequence/uuid.go}          |   17 +-
 .../statemachine/engine/serializer/serializer.go   |   60 +
 .../engine/serializer/serializer_test.go}          |   25 +-
 .../statemachine/engine/statemachine_config.go     |   81 ++
 .../statemachine/engine/statemachine_engine.go     |   60 +
 .../engine/statemachine_engine_test.go             |   49 +
 pkg/saga/statemachine/engine/strategy.go           |   37 +
 .../engine/strategy/status_decision.go             |  274 ++++
 .../engine/utils/process_context_utils.go          |  113 ++
 .../process_ctrl/bussiness_processor.go            |  111 ++
 .../process_ctrl/default_process_handler.go}       |    9 +-
 .../statemachine/process_ctrl/event.go}            |    8 +-
 pkg/saga/statemachine/process_ctrl/event_bus.go    |  157 +++
 .../statemachine/process_ctrl/event_consumer.go    |   54 +
 .../statemachine/process_ctrl/event_publisher.go}  |   22 +-
 .../handlers/service_task_state_handler.go         |  266 ++++
 .../statemachine/process_ctrl/instruction.go}      |    8 +-
 .../process_ctrl/process/process_type.go}          |   11 +-
 .../statemachine/process_ctrl/process_context.go   |  225 ++++
 .../process_ctrl/process_controller.go}            |   57 +-
 .../statemachine/process_ctrl/process_router.go    |  112 ++
 .../statelang/parser/choice_state_json_parser.go   |   93 ++
 .../parser/compensation_trigger_state_parser.go    |   48 +
 .../statelang/parser/end_state_parser.go           |   83 ++
 .../statelang/parser/statemachine_config_parser.go |  140 ++
 .../parser/statemachine_config_parser_test.go      |  884 +++++++++++++
 .../statelang/parser/statemachine_json_parser.go   |  131 ++
 .../parser/statemachine_json_parser_test.go        |  127 ++
 .../statelang/parser/statemachine_parser.go        |  262 ++++
 .../statelang/parser/sub_state_machine_parser.go   |  103 ++
 .../statelang/parser/task_state_json_parser.go     |  351 +++++
 pkg/saga/statemachine/statelang/state.go           |   92 ++
 .../statemachine/statelang/state/choice_state.go   |   92 ++
 .../statelang/state/compensation_trigger_state.go} |   25 +-
 pkg/saga/statemachine/statelang/state/end_state.go |   81 ++
 .../statelang/state/loop_start_state.go}           |   25 +-
 .../statelang/state/sub_state_machine.go           |   87 ++
 .../statemachine/statelang/state/task_state.go     |  478 +++++++
 pkg/saga/statemachine/statelang/state_instance.go  |  360 ++++++
 pkg/saga/statemachine/statelang/statemachine.go    |  278 ++++
 .../statelang/statemachine_instance.go             |  351 +++++
 pkg/saga/statemachine/statemachine.go              |   47 +
 pkg/saga/statemachine/store/db/db.go               |  121 ++
 pkg/saga/statemachine/store/db/db_test.go          |   64 +
 pkg/saga/statemachine/store/db/statelang.go        |  133 ++
 pkg/saga/statemachine/store/db/statelang_test.go   |   92 ++
 pkg/saga/statemachine/store/db/statelog.go         | 1360 ++++++++++++++++++++
 pkg/saga/statemachine/store/db/statelog_test.go    |  823 ++++++++++++
 pkg/saga/statemachine/store/store.go               |   57 +
 pkg/saga/tm/default_saga_transactional_template.go |  175 +++
 pkg/saga/tm/saga_transactional_template.go         |   44 +
 pkg/tm/context.go                                  |    3 +-
 pkg/tm/global_transaction.go                       |   25 +
 pkg/tm/transaction_executor_test.go                |    2 +-
 pkg/{rm/init.go => tm/transaction_hook.go}         |   22 +-
 pkg/tm/transaction_hook_manager.go                 |   61 +
 pkg/util/collection/collection.go                  |   44 +-
 pkg/util/collection/collection_test.go             |   23 +
 pkg/util/errors/code.go                            |   15 +
 pkg/util/reflectx/unmarkshaler.go                  |  165 +++
 .../saga/engine/invoker/grpc/product.go            |   61 +-
 testdata/saga/engine/invoker/grpc/product.pb.go    |  237 ++++
 testdata/saga/engine/invoker/grpc/product.proto    |   35 +
 .../saga/engine/invoker/grpc/product_grpc.pb.go    |  168 +++
 .../statelang/simple_statelang_with_choice.json    |   38 +
 .../statelang/simple_statelang_with_choice.yaml    |   41 +
 testdata/saga/statelang/simple_statemachine.json   |  138 ++
 testdata/saga/statelang/simple_statemachine.yaml   |  105 ++
 .../saga/statelang/state_machine_new_designer.json |  424 ++++++
 .../saga/statelang/state_machine_new_designer.yaml |  301 +++++
 testdata/sql/saga/sqlite_init.sql                  |   81 ++
 176 files changed, 20086 insertions(+), 367 deletions(-)

diff --git a/.github/workflows/issue-robot.yml b/.github/workflows/issue-robot.yml
new file mode 100644
index 00000000..3052ce99
--- /dev/null
+++ b/.github/workflows/issue-robot.yml
@@ -0,0 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+name: 'issue translator'
+on:
+  issue_comment:
+    types: [created]
+  issues:
+    types: [opened]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: tomsun28/issues-translate-action@v2.6
+        with:
+          # it is not necessary to decide whether you need to modify the issue header content
+          IS_MODIFY_TITLE: false
+          CUSTOM_BOT_NOTE: RoBot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿
diff --git a/.licenserc.yaml b/.licenserc.yaml
index c42dae30..ad64d6e1 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -61,6 +61,7 @@ header: # `header` section is configurations for source codes license header.
     - 'DISCLAIMER'
     - 'NOTICE'
     - '.github'
+    - '**/*.json'
   comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.
 
   language:
diff --git a/go.mod b/go.mod
index 3c55e2bc..8665db27 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,9 @@ require (
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/goccy/go-json v0.10.2
 	github.com/golang/mock v1.6.0
+	github.com/google/cel-go v0.18.0
 	github.com/google/uuid v1.3.0
+	github.com/mattn/go-sqlite3 v1.14.19
 	github.com/natefinch/lumberjack v2.0.0+incompatible
 	github.com/pierrec/lz4/v4 v4.1.17
 	github.com/pkg/errors v0.9.1
@@ -24,8 +26,10 @@ require (
 	github.com/stretchr/testify v1.8.3
 	go.uber.org/atomic v1.9.0
 	go.uber.org/zap v1.27.0
-	google.golang.org/grpc v1.56.3
+	golang.org/x/sync v0.11.0
+	google.golang.org/grpc v1.57.0
 	gopkg.in/yaml.v2 v2.4.0
+	gopkg.in/yaml.v3 v3.0.1
 	vimagination.zapto.org/byteio v0.0.0-20200222190125-d27cba0f0b10
 )
 
@@ -34,14 +38,18 @@ require (
 	github.com/golang/protobuf v1.5.3
 	go.etcd.io/etcd/api/v3 v3.5.6
 	go.etcd.io/etcd/client/v3 v3.5.6
-	google.golang.org/protobuf v1.30.0
+	google.golang.org/protobuf v1.31.0
 )
 
-require github.com/knadh/koanf v1.5.0
+require (
+	github.com/knadh/koanf v1.5.0
+	github.com/robertkrimen/otto v0.4.0
+)
 
 require (
 	github.com/RoaringBitmap/roaring v1.2.0 // indirect
 	github.com/Workiva/go-datastructures v1.0.52 // indirect
+	github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
 	github.com/apache/dubbo-go-hessian2 v1.11.4 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bits-and-blooms/bitset v1.2.0 // indirect
@@ -78,10 +86,11 @@ require (
 	github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
-	github.com/prometheus/client_model v0.2.0 // indirect
+	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect
 	github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
 	github.com/shirou/gopsutil/v3 v3.22.2 // indirect
+	github.com/stoewer/go-strcase v1.2.0 // indirect
 	github.com/stretchr/objx v0.5.0 // indirect
 	github.com/tklauser/go-sysconf v0.3.10 // indirect
 	github.com/tklauser/numcpus v0.4.0 // indirect
@@ -91,9 +100,12 @@ require (
 	go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect
 	go.uber.org/multierr v1.10.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
+	golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
 	golang.org/x/text v0.14.0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
+	gopkg.in/sourcemap.v1 v1.0.5 // indirect
 )
 
 require (
@@ -107,7 +119,7 @@ require (
 	golang.org/x/crypto v0.21.0 // indirect
 	golang.org/x/net v0.23.0 // indirect
 	golang.org/x/sys v0.18.0 // indirect
-	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+	google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect
 	vimagination.zapto.org/memio v0.0.0-20200222190306-588ebc67b97d // indirect
 )
 
diff --git a/go.sum b/go.sum
index e76a9f09..aa97433e 100644
--- a/go.sum
+++ b/go.sum
@@ -65,6 +65,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
 github.com/alibaba/sentinel-golang v1.0.4/go.mod h1:Lag5rIYyJiPOylK8Kku2P+a23gdKMMqzQS7wTnjWEpk=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
+github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
 github.com/apache/dubbo-getty v1.4.9-0.20221022181821-4dc6252ce98c/go.mod h1:6qmrqBSPGs3B35zwEuGhEYNVsx1nfGT/xzV2yOt2amM=
 github.com/apache/dubbo-getty v1.5.0 h1:40RMjEoSfTuoG5EwKbGgfhjd7m6Zc7qBfOFgQv1jHCI=
 github.com/apache/dubbo-getty v1.5.0/go.mod h1:V64WqLIxksEgNu5aBJBOxNIvpOZyfUJ7J/DXBlKSUoA=
@@ -314,6 +316,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/cel-go v0.18.0 h1:u74MPiEC8mejBrkXqrTWT102g5IFEUjxOngzQIijMzU=
+github.com/google/cel-go v0.18.0/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -518,6 +522,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
 github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
 github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-sqlite3 v1.14.19 h1:fhGleo2h1p8tVChob4I9HpmVFIAkKGpiukdrgQbWfGI=
+github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
@@ -638,8 +644,9 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
+github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@@ -667,6 +674,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
+github.com/robertkrimen/otto v0.4.0 h1:/c0GRrK1XDPcgIasAsnlpBT5DelIeB9U/Z/JCQsgr7E=
+github.com/robertkrimen/otto v0.4.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -709,6 +718,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
 github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
@@ -855,6 +866,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
+golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -949,6 +962,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1176,8 +1191,12 @@ google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
 google.golang.org/genproto v0.0.0-20211104193956-4c6863e31247/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
-google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
+google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg=
+google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108=
+google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44=
+google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
 google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -1208,8 +1227,8 @@ google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzI
 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
-google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
-google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
+google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1225,8 +1244,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1244,6 +1263,8 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
+gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
 gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
diff --git a/pkg/client/client.go b/pkg/client/client.go
index 53ab7a00..9d9bea4d 100644
--- a/pkg/client/client.go
+++ b/pkg/client/client.go
@@ -30,6 +30,7 @@ import (
 	"seata.apache.org/seata-go/pkg/remoting/processor/client"
 	"seata.apache.org/seata-go/pkg/rm"
 	"seata.apache.org/seata-go/pkg/rm/tcc"
+	saga "seata.apache.org/seata-go/pkg/saga/rm"
 	"seata.apache.org/seata-go/pkg/tm"
 	"seata.apache.org/seata-go/pkg/util/log"
 )
@@ -62,7 +63,7 @@ func initTmClient(cfg *Config) {
 	})
 }
 
-// initRemoting init remoting
+// initRemoting init rpc client
 func initRemoting(cfg *Config) {
 	seataConfig := remoteConfig.SeataConfig{
 		ApplicationID:        cfg.ApplicationID,
@@ -89,6 +90,7 @@ func initRmClient(cfg *Config) {
 		client.RegisterProcessor()
 		integration.Init()
 		tcc.InitTCC(cfg.TCCConfig.FenceConfig)
+		saga.InitSaga()
 		at.InitAT(cfg.ClientConfig.UndoConfig, cfg.AsyncWorkerConfig)
 		at.InitXA(cfg.ClientConfig.XaConfig)
 	})
diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go
index 8af3cd14..c92746da 100644
--- a/pkg/client/client_test.go
+++ b/pkg/client/client_test.go
@@ -22,6 +22,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/tm"
 )
 
@@ -125,10 +126,10 @@ func TestInitRemotingFunction(t *testing.T) {
 
 func TestSyncOnceTypes(t *testing.T) {
 	// Test that all once variables are of type sync.Once
-	assert.IsType(t, sync.Once{}, onceInitTmClient)
-	assert.IsType(t, sync.Once{}, onceInitRmClient)
-	assert.IsType(t, sync.Once{}, onceInitDatasource)
-	assert.IsType(t, sync.Once{}, onceInitRegistry)
+	assert.IsType(t, &sync.Once{}, &onceInitTmClient)
+	assert.IsType(t, &sync.Once{}, &onceInitRmClient)
+	assert.IsType(t, &sync.Once{}, &onceInitDatasource)
+	assert.IsType(t, &sync.Once{}, &onceInitRegistry)
 }
 
 func TestConfigStruct(t *testing.T) {
diff --git a/pkg/client/config.go b/pkg/client/config.go
index 2e15c45b..9b2c8ea7 100644
--- a/pkg/client/config.go
+++ b/pkg/client/config.go
@@ -26,6 +26,8 @@ import (
 	"runtime"
 	"strings"
 
+	"seata.apache.org/seata-go/pkg/saga"
+
 	"github.com/knadh/koanf"
 	"github.com/knadh/koanf/parsers/json"
 	"github.com/knadh/koanf/parsers/toml"
@@ -85,6 +87,8 @@ type Config struct {
 	TransportConfig   remoteConfig.TransportConfig `yaml:"transport" json:"transport" koanf:"transport"`
 	ServiceConfig     discovery.ServiceConfig      `yaml:"service" json:"service" koanf:"service"`
 	RegistryConfig    discovery.RegistryConfig     `yaml:"registry" json:"registry" koanf:"registry"`
+
+	SagaConfig saga.Config `yaml:"saga" json:"saga" koanf:"saga"`
 }
 
 func (c *Config) RegisterFlags(f *flag.FlagSet) {
@@ -103,6 +107,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) {
 	c.TransportConfig.RegisterFlagsWithPrefix("transport", f)
 	c.RegistryConfig.RegisterFlagsWithPrefix("registry", f)
 	c.ServiceConfig.RegisterFlagsWithPrefix("service", f)
+	c.SagaConfig.RegisterFlagsWithPrefix("saga", f)
 }
 
 type loaderConf struct {
diff --git a/pkg/datasource/sql/conn_xa.go b/pkg/datasource/sql/conn_xa.go
index 9dc00bda..14984a95 100644
--- a/pkg/datasource/sql/conn_xa.go
+++ b/pkg/datasource/sql/conn_xa.go
@@ -27,6 +27,7 @@ import (
 	"time"
 
 	"github.com/go-sql-driver/mysql"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 	"seata.apache.org/seata-go/pkg/datasource/sql/xa"
 	"seata.apache.org/seata-go/pkg/tm"
diff --git a/pkg/datasource/sql/datasource/base/meta_cache_test.go b/pkg/datasource/sql/datasource/base/meta_cache_test.go
index 7ebbc03c..e0a5ed61 100644
--- a/pkg/datasource/sql/datasource/base/meta_cache_test.go
+++ b/pkg/datasource/sql/datasource/base/meta_cache_test.go
@@ -28,6 +28,7 @@ import (
 	"github.com/agiledragon/gomonkey/v2"
 	"github.com/go-sql-driver/mysql"
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 	"seata.apache.org/seata-go/testdata"
 )
diff --git a/pkg/datasource/sql/datasource/mysql/trigger.go b/pkg/datasource/sql/datasource/mysql/trigger.go
index adbbb2f7..fa1ca922 100644
--- a/pkg/datasource/sql/datasource/mysql/trigger.go
+++ b/pkg/datasource/sql/datasource/mysql/trigger.go
@@ -30,6 +30,8 @@ import (
 )
 
 type mysqlTrigger struct {
+	getColumnMetasFn func(ctx context.Context, dbName string, table string, conn *sql.Conn) ([]types.ColumnMeta, error)
+	getIndexesFn     func(ctx context.Context, dbName string, tableName string, conn *sql.Conn) ([]types.IndexMeta, error)
 }
 
 func NewMysqlTrigger() *mysqlTrigger {
@@ -93,6 +95,10 @@ func (m *mysqlTrigger) LoadAll(ctx context.Context, dbName string, conn *sql.Con
 
 // getColumnMetas get tableMeta column
 func (m *mysqlTrigger) getColumnMetas(ctx context.Context, dbName string, table string, conn *sql.Conn) ([]types.ColumnMeta, error) {
+	if m.getColumnMetasFn != nil {
+		return m.getColumnMetasFn(ctx, dbName, table, conn)
+	}
+
 	table = executor.DelEscape(table, types.DBTypeMySQL)
 	var columnMetas []types.ColumnMeta
 
@@ -165,6 +171,10 @@ func (m *mysqlTrigger) getColumnMetas(ctx context.Context, dbName string, table
 
 // getIndex get tableMetaIndex
 func (m *mysqlTrigger) getIndexes(ctx context.Context, dbName string, tableName string, conn *sql.Conn) ([]types.IndexMeta, error) {
+	if m.getIndexesFn != nil {
+		return m.getIndexesFn(ctx, dbName, tableName, conn)
+	}
+
 	tableName = executor.DelEscape(tableName, types.DBTypeMySQL)
 	result := make([]types.IndexMeta, 0)
 
diff --git a/pkg/datasource/sql/datasource/mysql/trigger_test.go b/pkg/datasource/sql/datasource/mysql/trigger_test.go
index 16b15399..98aece14 100644
--- a/pkg/datasource/sql/datasource/mysql/trigger_test.go
+++ b/pkg/datasource/sql/datasource/mysql/trigger_test.go
@@ -27,6 +27,7 @@ import (
 	"github.com/agiledragon/gomonkey/v2"
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/testdata"
 
 	"seata.apache.org/seata-go/pkg/datasource/sql/mock"
diff --git a/pkg/datasource/sql/exec/at/base_executor_test.go b/pkg/datasource/sql/exec/at/base_executor_test.go
index 432ca0aa..82062ba3 100644
--- a/pkg/datasource/sql/exec/at/base_executor_test.go
+++ b/pkg/datasource/sql/exec/at/base_executor_test.go
@@ -18,9 +18,11 @@
 package at
 
 import (
+	"testing"
+
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
-	"testing"
 )
 
 func TestBaseExecBuildLockKey(t *testing.T) {
diff --git a/pkg/datasource/sql/exec/at/update_executor.go b/pkg/datasource/sql/exec/at/update_executor.go
index 0f14e97b..023331f3 100644
--- a/pkg/datasource/sql/exec/at/update_executor.go
+++ b/pkg/datasource/sql/exec/at/update_executor.go
@@ -21,9 +21,11 @@ import (
 	"context"
 	"database/sql/driver"
 	"fmt"
+	"strings"
+
 	"github.com/arana-db/parser/model"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/util"
-	"strings"
 
 	"github.com/arana-db/parser/ast"
 	"github.com/arana-db/parser/format"
diff --git a/pkg/datasource/sql/exec/at/update_join_executor_test.go b/pkg/datasource/sql/exec/at/update_join_executor_test.go
index 401abd1a..23bf19a4 100644
--- a/pkg/datasource/sql/exec/at/update_join_executor_test.go
+++ b/pkg/datasource/sql/exec/at/update_join_executor_test.go
@@ -20,9 +20,10 @@ package at
 import (
 	"context"
 	"database/sql/driver"
-	"seata.apache.org/seata-go/pkg/datasource/sql/undo"
 	"testing"
 
+	"seata.apache.org/seata-go/pkg/datasource/sql/undo"
+
 	"github.com/stretchr/testify/assert"
 
 	"seata.apache.org/seata-go/pkg/datasource/sql/exec"
diff --git a/pkg/datasource/sql/undo/base/undo_test.go b/pkg/datasource/sql/undo/base/undo_test.go
index 10b5115d..dcda2904 100644
--- a/pkg/datasource/sql/undo/base/undo_test.go
+++ b/pkg/datasource/sql/undo/base/undo_test.go
@@ -22,11 +22,13 @@ import (
 	"database/sql/driver"
 	"encoding/json"
 	"errors"
+	"strings"
+	"testing"
+
 	"github.com/DATA-DOG/go-sqlmock"
 	"github.com/stretchr/testify/require"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
-	"strings"
-	"testing"
 
 	"github.com/stretchr/testify/assert"
 
diff --git a/pkg/datasource/sql/undo/builder/basic_undo_log_builder.go b/pkg/datasource/sql/undo/builder/basic_undo_log_builder.go
index a216d813..1093b02f 100644
--- a/pkg/datasource/sql/undo/builder/basic_undo_log_builder.go
+++ b/pkg/datasource/sql/undo/builder/basic_undo_log_builder.go
@@ -22,12 +22,14 @@ import (
 	"database/sql"
 	"database/sql/driver"
 	"fmt"
+	"io"
+	"strings"
+
 	"github.com/arana-db/parser/ast"
 	"github.com/arana-db/parser/test_driver"
 	gxsort "github.com/dubbogo/gost/sort"
-	"io"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/util"
-	"strings"
 
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 )
diff --git a/pkg/datasource/sql/undo/builder/basic_undo_log_builder_test.go b/pkg/datasource/sql/undo/builder/basic_undo_log_builder_test.go
index e4360101..821d246a 100644
--- a/pkg/datasource/sql/undo/builder/basic_undo_log_builder_test.go
+++ b/pkg/datasource/sql/undo/builder/basic_undo_log_builder_test.go
@@ -128,9 +128,9 @@ func TestBuildLockKey(t *testing.T) {
 			types.RecordImage{
 				TableName: "test2_name",
 				Rows: []types.RowImage{
-					{[]types.ColumnImage{getColumnImage("id", 1), getColumnImage("userId", "one"), getColumnImage("age", "11")}},
-					{[]types.ColumnImage{getColumnImage("id", 2), getColumnImage("userId", "two"), getColumnImage("age", "22")}},
-					{[]types.ColumnImage{getColumnImage("id", 3), getColumnImage("userId", "three"), getColumnImage("age", "33")}},
+					{Columns: []types.ColumnImage{getColumnImage("id", 1), getColumnImage("userId", "one"), getColumnImage("age", "11")}},
+					{Columns: []types.ColumnImage{getColumnImage("id", 2), getColumnImage("userId", "two"), getColumnImage("age", "22")}},
+					{Columns: []types.ColumnImage{getColumnImage("id", 3), getColumnImage("userId", "three"), getColumnImage("age", "33")}},
 				},
 			},
 			"TEST2_NAME:1_one_11,2_two_22,3_three_33",
diff --git a/pkg/datasource/sql/undo/parser/branch_undo_log.pb.go b/pkg/datasource/sql/undo/parser/branch_undo_log.pb.go
index 041a8aa5..c6c5333a 100644
--- a/pkg/datasource/sql/undo/parser/branch_undo_log.pb.go
+++ b/pkg/datasource/sql/undo/parser/branch_undo_log.pb.go
@@ -24,11 +24,12 @@
 package parser
 
 import (
+	reflect "reflect"
+	sync "sync"
+
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	anypb "google.golang.org/protobuf/types/known/anypb"
-	reflect "reflect"
-	sync "sync"
 )
 
 const (
diff --git a/pkg/datasource/sql/undo/parser/parser_protobuf_test.go b/pkg/datasource/sql/undo/parser/parser_protobuf_test.go
index 7427d590..7ca4dfe5 100644
--- a/pkg/datasource/sql/undo/parser/parser_protobuf_test.go
+++ b/pkg/datasource/sql/undo/parser/parser_protobuf_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/undo"
 )
 
diff --git a/pkg/datasource/sql/util/ctxutil_test.go b/pkg/datasource/sql/util/ctxutil_test.go
index 6a5690c8..51bef2f6 100644
--- a/pkg/datasource/sql/util/ctxutil_test.go
+++ b/pkg/datasource/sql/util/ctxutil_test.go
@@ -21,8 +21,9 @@ import (
 	"context"
 	"database/sql/driver"
 	"errors"
-	"github.com/stretchr/testify/assert"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 // Mock implementations for testing
diff --git a/pkg/datasource/sql/util/lockkey.go b/pkg/datasource/sql/util/lockkey.go
index e1aaa9f5..1b5fc05a 100644
--- a/pkg/datasource/sql/util/lockkey.go
+++ b/pkg/datasource/sql/util/lockkey.go
@@ -23,8 +23,9 @@ package util
 
 import (
 	"fmt"
-	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 	"strings"
+
+	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 )
 
 func BuildLockKey(records *types.RecordImage, meta types.TableMeta) string {
diff --git a/pkg/datasource/sql/util/lockkey_test.go b/pkg/datasource/sql/util/lockkey_test.go
index a69cad9f..882778b5 100644
--- a/pkg/datasource/sql/util/lockkey_test.go
+++ b/pkg/datasource/sql/util/lockkey_test.go
@@ -21,6 +21,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/datasource/sql/types"
 )
 
diff --git a/pkg/discovery/etcd3_test.go b/pkg/discovery/etcd3_test.go
index 81f87c6d..c804be13 100644
--- a/pkg/discovery/etcd3_test.go
+++ b/pkg/discovery/etcd3_test.go
@@ -18,14 +18,16 @@
 package discovery
 
 import (
+	"reflect"
+	"testing"
+	"time"
+
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
 	"go.etcd.io/etcd/api/v3/mvccpb"
-	"go.etcd.io/etcd/client/v3"
-	"reflect"
+	clientv3 "go.etcd.io/etcd/client/v3"
+
 	"seata.apache.org/seata-go/pkg/discovery/mock"
-	"testing"
-	"time"
 )
 
 func TestEtcd3RegistryService_Lookup(t *testing.T) {
diff --git a/pkg/discovery/mock/test_etcd_client.go b/pkg/discovery/mock/test_etcd_client.go
index e7cc5fc0..72fcd558 100644
--- a/pkg/discovery/mock/test_etcd_client.go
+++ b/pkg/discovery/mock/test_etcd_client.go
@@ -17,7 +17,7 @@
 
 package mock
 
-import "go.etcd.io/etcd/client/v3"
+import clientv3 "go.etcd.io/etcd/client/v3"
 
 type EtcdClient interface {
 	clientv3.KV
diff --git a/pkg/protocol/codec/codec.go b/pkg/protocol/codec/codec.go
index a7e9a863..5330d968 100644
--- a/pkg/protocol/codec/codec.go
+++ b/pkg/protocol/codec/codec.go
@@ -114,6 +114,7 @@ func (c *CodecManager) Encode(codecType CodecType, in interface{}) []byte {
 
 func Init() {
 	// Global
+	GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalReportRequestCodec{})
 	GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalReportResponseCodec{})
 	GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalBeginRequestCodec{})
 	GetCodecManager().RegisterCodec(CodecTypeSeata, &GlobalBeginResponseCodec{})
diff --git a/pkg/protocol/codec/global_report_request_codec.go b/pkg/protocol/codec/global_report_request_codec.go
index b261d227..6065e244 100644
--- a/pkg/protocol/codec/global_report_request_codec.go
+++ b/pkg/protocol/codec/global_report_request_codec.go
@@ -52,5 +52,6 @@ func (g *GlobalReportRequestCodec) Encode(in interface{}) []byte {
 
 // GetMessageType get global report request's message type
 func (g *GlobalReportRequestCodec) GetMessageType() message.MessageType {
-	return message.MessageTypeGlobalReportResult
+	// must be the request type, not the result type
+	return message.MessageTypeGlobalReport
 }
diff --git a/pkg/remoting/config/config_test.go b/pkg/remoting/config/config_test.go
index 45c29b48..2ab050d0 100644
--- a/pkg/remoting/config/config_test.go
+++ b/pkg/remoting/config/config_test.go
@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/util/flagext"
 )
 
diff --git a/pkg/remoting/loadbalance/least_active_loadbalance_test.go b/pkg/remoting/loadbalance/least_active_loadbalance_test.go
index b82b13df..81d5bad2 100644
--- a/pkg/remoting/loadbalance/least_active_loadbalance_test.go
+++ b/pkg/remoting/loadbalance/least_active_loadbalance_test.go
@@ -25,6 +25,7 @@ import (
 
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/assert"
+
 	"seata.apache.org/seata-go/pkg/remoting/mock"
 	"seata.apache.org/seata-go/pkg/remoting/rpc"
 )
diff --git a/pkg/remoting/loadbalance/loadbalance.go b/pkg/remoting/loadbalance/loadbalance.go
index abfb6b6f..8451e170 100644
--- a/pkg/remoting/loadbalance/loadbalance.go
+++ b/pkg/remoting/loadbalance/loadbalance.go
@@ -37,10 +37,6 @@ func Select(loadBalanceType string, sessions *sync.Map, xid string) getty.Sessio
 		return RandomLoadBalance(sessions, xid)
 	case xidLoadBalance:
 		return XidLoadBalance(sessions, xid)
-	case consistentHashLoadBalance:
-		return ConsistentHashLoadBalance(sessions, xid)
-	case leastActiveLoadBalance:
-		return LeastActiveLoadBalance(sessions, xid)
 	case roundRobinLoadBalance:
 		return RoundRobinLoadBalance(sessions, xid)
 	default:
diff --git a/pkg/rm/init.go b/pkg/rm/init.go
index 469cdfaa..a88d36f2 100644
--- a/pkg/rm/init.go
+++ b/pkg/rm/init.go
@@ -30,3 +30,8 @@ type RmConfig struct {
 func InitRm(cfg RmConfig) {
 	rmConfig = cfg
 }
+
+// GetRmAppAndGroup returns current RM applicationId and txServiceGroup
+func GetRmAppAndGroup() (string, string) {
+	return rmConfig.ApplicationID, rmConfig.TxServiceGroup
+}
diff --git a/pkg/rm/tcc/fence/fence.go b/pkg/rm/tcc/fence/fence.go
index ce9009e5..0b85aaa5 100644
--- a/pkg/rm/tcc/fence/fence.go
+++ b/pkg/rm/tcc/fence/fence.go
@@ -19,10 +19,11 @@ package fence
 
 import (
 	"flag"
+	"time"
+
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/config"
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/handler"
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/store/db/dao"
-	"time"
 )
 
 var (
diff --git a/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler.go b/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler.go
index 1517300d..6dbf2e73 100644
--- a/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler.go
+++ b/pkg/rm/tcc/fence/handler/tcc_fence_wrapper_handler.go
@@ -23,11 +23,13 @@ import (
 	"database/sql"
 	"errors"
 	"fmt"
+	"sync"
+	"time"
+
 	"github.com/go-sql-driver/mysql"
+
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/store/db/dao"
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/store/db/model"
-	"sync"
-	"time"
 
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
 	"seata.apache.org/seata-go/pkg/tm"
diff --git a/pkg/rm/tcc/fence/store/db/dao/tcc_fence_db.go b/pkg/rm/tcc/fence/store/db/dao/tcc_fence_db.go
index a2b0692c..ed3c6533 100644
--- a/pkg/rm/tcc/fence/store/db/dao/tcc_fence_db.go
+++ b/pkg/rm/tcc/fence/store/db/dao/tcc_fence_db.go
@@ -21,11 +21,12 @@ import (
 	"context"
 	"database/sql"
 	"fmt"
-	"seata.apache.org/seata-go/pkg/util/log"
 	"strings"
 	"sync"
 	"time"
 
+	"seata.apache.org/seata-go/pkg/util/log"
+
 	"github.com/go-sql-driver/mysql"
 
 	"seata.apache.org/seata-go/pkg/rm/tcc/fence/enum"
diff --git a/pkg/rm/tcc/tcc_resource.go b/pkg/rm/tcc/tcc_resource.go
index fae919c1..94039e89 100644
--- a/pkg/rm/tcc/tcc_resource.go
+++ b/pkg/rm/tcc/tcc_resource.go
@@ -21,9 +21,10 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"seata.apache.org/seata-go/pkg/rm/tcc/fence"
 	"sync"
 
+	"seata.apache.org/seata-go/pkg/rm/tcc/fence"
+
 	"seata.apache.org/seata-go/pkg/constant"
 	"seata.apache.org/seata-go/pkg/protocol/branch"
 	"seata.apache.org/seata-go/pkg/rm"
diff --git a/pkg/rm/init.go b/pkg/saga/config.go
similarity index 67%
copy from pkg/rm/init.go
copy to pkg/saga/config.go
index 469cdfaa..93761ea2 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/config.go
@@ -15,18 +15,20 @@
  * limitations under the License.
  */
 
-package rm
+package saga
 
-var rmConfig RmConfig
+import (
+	"flag"
 
-type RmConfig struct {
-	Config
+	"seata.apache.org/seata-go/pkg/saga/statemachine"
+)
 
-	ApplicationID  string
-	TxServiceGroup string
+type Config struct {
+	StateMachine *statemachine.StateMachineObject `yaml:"state-machine" json:"state-machine" koanf:"state-machine"`
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func (cfg *Config) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
+	if cfg.StateMachine != nil {
+		cfg.StateMachine.RegisterFlagsWithPrefix(prefix+".state-machine", f)
+	}
 }
diff --git a/pkg/saga/readme.md b/pkg/saga/readme.md
new file mode 100644
index 00000000..4b59bbc7
--- /dev/null
+++ b/pkg/saga/readme.md
@@ -0,0 +1,47 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+-->
+
+# seata saga
+
+未来计划有三种使用方式
+
+- 基于状态机引擎的 json
+   link: statemachine_engine#Start
+- stream builder
+    stateMachine.serviceTask().build().Start
+- 二阶段方式saga,类似tcc使用
+
+上面1、2是以来[statemachine](statemachine),状态机引擎实现的,3相对比较独立。
+
+
+状态机的实现在:saga-statemachine包中
+其中[statelang](statemachine%2Fstatelang)是状态机语言的解析,目前实现的是json解析方式,状态机语言可以参考:
+https://seata.io/docs/user/mode/saga
+
+状态机json执行的入口类是:[statemachine_engine.go](statemachine%2Fengine%2Fstatemachine_engine.go)
+
+下面简单说下engine中各个包的作用:
+events:saga的是基于事件处理的,其中是event、eventBus的实现
+expr:表达式声明、解析、执行
+invoker:声明了serviceInvoker、scriptInvoker等接口、task调用管理、执行都在这个包中,例如httpInvoker
+process_ctrl:状态机处理流程:上下文、执行、事件流转
+sequence:分布式id
+store:状态机存储接口、实现
+status_decision:状态机状态决策
+
+
+
diff --git a/pkg/rm/init.go b/pkg/saga/rm/handler_saga.go
similarity index 64%
copy from pkg/rm/init.go
copy to pkg/saga/rm/handler_saga.go
index 469cdfaa..27c01fef 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/rm/handler_saga.go
@@ -17,16 +17,19 @@
 
 package rm
 
-var rmConfig RmConfig
+import (
+	"seata.apache.org/seata-go/pkg/protocol/branch"
+	"seata.apache.org/seata-go/pkg/rm"
+)
 
-type RmConfig struct {
-	Config
+type RMHandlerSaga struct{}
 
-	ApplicationID  string
-	TxServiceGroup string
+func (h *RMHandlerSaga) HandleUndoLogDeleteRequest(request interface{}) {
+	// do nothing
 }
-
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func (h *RMHandlerSaga) GetResourceManager() rm.ResourceManager {
+	return rm.GetRmCacheInstance().GetResourceManager(branch.BranchTypeSAGA)
+}
+func (h *RMHandlerSaga) GetBranchType() branch.BranchType {
+	return branch.BranchTypeSAGA
 }
diff --git a/pkg/rm/init.go b/pkg/saga/rm/saga_resource.go
similarity index 53%
copy from pkg/rm/init.go
copy to pkg/saga/rm/saga_resource.go
index 469cdfaa..ea46c552 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/rm/saga_resource.go
@@ -17,16 +17,37 @@
 
 package rm
 
-var rmConfig RmConfig
+import (
+	"fmt"
 
-type RmConfig struct {
-	Config
+	"seata.apache.org/seata-go/pkg/protocol/branch"
+)
 
-	ApplicationID  string
-	TxServiceGroup string
+type SagaResource struct {
+	resourceGroupId string
+	applicationId   string
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func (r *SagaResource) GetResourceGroupId() string {
+	return r.resourceGroupId
+}
+
+func (r *SagaResource) SetResourceGroupId(resourceGroupId string) {
+	r.resourceGroupId = resourceGroupId
+}
+
+func (r *SagaResource) GetResourceId() string {
+	return fmt.Sprintf("%s#%s", r.applicationId, r.resourceGroupId)
+}
+
+func (r *SagaResource) GetBranchType() branch.BranchType {
+	return branch.BranchTypeSAGA
+}
+
+func (r *SagaResource) GetApplicationId() string {
+	return r.applicationId
+}
+
+func (r *SagaResource) SetApplicationId(applicationId string) {
+	r.applicationId = applicationId
 }
diff --git a/pkg/saga/rm/saga_resource_manager.go b/pkg/saga/rm/saga_resource_manager.go
new file mode 100644
index 00000000..27547032
--- /dev/null
+++ b/pkg/saga/rm/saga_resource_manager.go
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rm
+
+import (
+	"bytes"
+	"context"
+	"fmt"
+	"log"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/protocol/branch"
+	"seata.apache.org/seata-go/pkg/protocol/message"
+	"seata.apache.org/seata-go/pkg/rm"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/exception"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	seataErrors "seata.apache.org/seata-go/pkg/util/errors"
+)
+
+var (
+	sagaResourceManagerInstance *SagaResourceManager
+	once                        sync.Once
+)
+
+type SagaResourceManager struct {
+	rmRemoting    *rm.RMRemoting
+	resourceCache sync.Map
+}
+
+func InitSaga() {
+	rm.GetRmCacheInstance().RegisterResourceManager(GetSagaResourceManager())
+}
+
+func GetSagaResourceManager() *SagaResourceManager {
+	once.Do(func() {
+		sagaResourceManagerInstance = &SagaResourceManager{
+			rmRemoting:    rm.GetRMRemotingInstance(),
+			resourceCache: sync.Map{},
+		}
+	})
+	return sagaResourceManagerInstance
+}
+
+func (s *SagaResourceManager) RegisterResource(resource rm.Resource) error {
+	if _, ok := resource.(*SagaResource); !ok {
+		return fmt.Errorf("register saga resource error, SagaResource is needed, param %v", resource)
+	}
+	s.resourceCache.Store(resource.GetResourceId(), resource)
+	return s.rmRemoting.RegisterResource(resource)
+
+}
+
+func (s *SagaResourceManager) GetCachedResources() *sync.Map {
+	return &s.resourceCache
+}
+
+func (s *SagaResourceManager) GetBranchType() branch.BranchType {
+	return branch.BranchTypeSAGA
+}
+
+func (s *SagaResourceManager) BranchCommit(ctx context.Context, resource rm.BranchResource) (branch.BranchStatus, error) {
+	engine := GetStateMachineEngine()
+	stMaInst, err := engine.Forward(ctx, resource.Xid, nil)
+	if err != nil {
+		if fie, ok := exception.IsForwardInvalidException(err); ok {
+			log.Printf("StateMachine forward failed, xid: %s, err: %v", resource.Xid, err)
+			if isInstanceNotExists(fie.ErrCode) {
+				return branch.BranchStatusPhasetwoCommitted, nil
+			}
+		}
+		log.Printf("StateMachine forward failed, xid: %s, err: %v", resource.Xid, err)
+		return branch.BranchStatusPhasetwoCommitFailedRetryable, err
+	}
+
+	status := stMaInst.Status()
+	compStatus := stMaInst.CompensationStatus()
+
+	switch {
+	case status == statelang.SU && compStatus == "":
+		return branch.BranchStatusPhasetwoCommitted, nil
+	case compStatus == statelang.SU:
+		return branch.BranchStatusPhasetwoRollbacked, nil
+	case compStatus == statelang.FA || compStatus == statelang.UN:
+		return branch.BranchStatusPhasetwoRollbackFailedRetryable, nil
+	case status == statelang.FA && compStatus == "":
+		return branch.BranchStatusPhaseoneFailed, nil
+	default:
+		return branch.BranchStatusPhasetwoCommitFailedRetryable, nil
+	}
+}
+
+func (s *SagaResourceManager) BranchRollback(ctx context.Context, resource rm.BranchResource) (branch.BranchStatus, error) {
+	engine := GetStateMachineEngine()
+	stMaInst, err := engine.ReloadStateMachineInstance(ctx, resource.Xid)
+	if err != nil || stMaInst == nil {
+		return branch.BranchStatusPhasetwoRollbacked, nil
+	}
+
+	strategy := stMaInst.StateMachine().RecoverStrategy()
+	appData := resource.ApplicationData
+	isTimeoutRollback := bytes.Equal(appData, []byte{byte(message.GlobalStatusTimeoutRollbacking)}) || bytes.Equal(appData, []byte{byte(message.GlobalStatusTimeoutRollbackRetrying)})
+
+	if strategy == statelang.Forward && isTimeoutRollback {
+		log.Printf("Retry by custom recover strategy [Forward] on timeout, SAGA global[%s]", resource.Xid)
+		return branch.BranchStatusPhasetwoCommitFailedRetryable, nil
+	}
+
+	stMaInst, err = engine.Compensate(ctx, resource.Xid, nil)
+	if err == nil && stMaInst.CompensationStatus() == statelang.SU {
+		return branch.BranchStatusPhasetwoRollbacked, nil
+	}
+
+	if fie, ok := exception.IsEngineExecutionException(err); ok {
+		log.Printf("StateMachine compensate failed, xid: %s, err: %v", resource.Xid, err)
+		if isInstanceNotExists(fie.ErrCode) {
+			return branch.BranchStatusPhasetwoRollbacked, nil
+		}
+	}
+	log.Printf("StateMachine compensate failed, xid: %s, err: %v", resource.Xid, err)
+	return branch.BranchStatusPhasetwoRollbackFailedRetryable, err
+}
+
+func (s *SagaResourceManager) BranchRegister(ctx context.Context, param rm.BranchRegisterParam) (int64, error) {
+	return s.rmRemoting.BranchRegister(param)
+}
+
+func (s *SagaResourceManager) BranchReport(ctx context.Context, param rm.BranchReportParam) error {
+	return s.rmRemoting.BranchReport(param)
+}
+
+func (s *SagaResourceManager) LockQuery(ctx context.Context, param rm.LockQueryParam) (bool, error) {
+	// LockQuery is not supported for Saga resources
+	return false, fmt.Errorf("LockQuery is not supported for Saga resources")
+}
+
+func (s *SagaResourceManager) UnregisterResource(resource rm.Resource) error {
+	// UnregisterResource is not supported for SagaResourceManager
+	return fmt.Errorf("UnregisterResource is not supported for SagaResourceManager")
+}
+
+// isInstanceNotExists checks if the error code indicates StateMachineInstanceNotExists
+func isInstanceNotExists(errCode string) bool {
+	return errCode == fmt.Sprintf("%v", seataErrors.StateMachineInstanceNotExists)
+}
diff --git a/pkg/rm/init.go b/pkg/saga/rm/saga_resource_manager_test.go
similarity index 63%
copy from pkg/rm/init.go
copy to pkg/saga/rm/saga_resource_manager_test.go
index 469cdfaa..61af679f 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/rm/saga_resource_manager_test.go
@@ -17,16 +17,27 @@
 
 package rm
 
-var rmConfig RmConfig
+import (
+	"sync"
+	"testing"
+)
 
-type RmConfig struct {
-	Config
+func TestGetSagaResourceManager_Singleton(t *testing.T) {
+	var wg sync.WaitGroup
+	instances := make([]*SagaResourceManager, 10)
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func(idx int) {
+			defer wg.Done()
+			instances[idx] = GetSagaResourceManager()
+		}(i)
+	}
+	wg.Wait()
 
-	ApplicationID  string
-	TxServiceGroup string
-}
-
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+	first := instances[0]
+	for i, inst := range instances {
+		if inst != first {
+			t.Errorf("Instance at index %d is not the same as the first instance", i)
+		}
+	}
 }
diff --git a/pkg/rm/init.go b/pkg/saga/rm/state_machine_engine_holder.go
similarity index 67%
copy from pkg/rm/init.go
copy to pkg/saga/rm/state_machine_engine_holder.go
index 469cdfaa..e7fb9efc 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/rm/state_machine_engine_holder.go
@@ -17,16 +17,23 @@
 
 package rm
 
-var rmConfig RmConfig
+import (
+	"sync"
 
-type RmConfig struct {
-	Config
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+)
 
-	ApplicationID  string
-	TxServiceGroup string
+var (
+	stateMachineEngine     engine.StateMachineEngine
+	stateMachineEngineOnce sync.Once
+)
+
+func GetStateMachineEngine() engine.StateMachineEngine {
+	return stateMachineEngine
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func SetStateMachineEngine(smEngine engine.StateMachineEngine) {
+	stateMachineEngineOnce.Do(func() {
+		stateMachineEngine = smEngine
+	})
 }
diff --git a/pkg/util/collection/collection_test.go b/pkg/saga/runtime/engine_registry.go
similarity index 51%
copy from pkg/util/collection/collection_test.go
copy to pkg/saga/runtime/engine_registry.go
index 74df03cd..bdf70255 100644
--- a/pkg/util/collection/collection_test.go
+++ b/pkg/saga/runtime/engine_registry.go
@@ -15,45 +15,36 @@
  * limitations under the License.
  */
 
-package collection
+package runtime
 
 import (
-	"reflect"
-	"testing"
+	"context"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
 )
 
-func TestEncodeDecodeMap(t *testing.T) {
-	testCases := []struct {
-		name     string
-		dataMap  map[string]string
-		expected map[string]string
-	}{
-		{
-			name: "test case 1",
-			dataMap: map[string]string{
-				"key1": "value1",
-				"key2": "value2",
-			},
-			expected: map[string]string{
-				"key1": "value1",
-				"key2": "value2",
-			},
-		},
-		{
-			name:     "test case 2",
-			dataMap:  nil,
-			expected: nil,
-		},
-	}
+// Engine is a minimal facade for state machine operations needed by Saga RM
+type Engine interface {
+	Forward(ctx context.Context, stateMachineInstId string, replaceParams map[string]interface{}) (statelang.StateMachineInstance, error)
+	Compensate(ctx context.Context, stateMachineInstId string, replaceParams map[string]interface{}) (statelang.StateMachineInstance, error)
+	ReloadStateMachineInstance(ctx context.Context, instId string) (statelang.StateMachineInstance, error)
+}
 
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			encoded := EncodeMap(tc.dataMap)
-			decoded := DecodeMap(encoded)
+var (
+	mu        sync.RWMutex
+	engineRef Engine
+)
+
+func SetEngine(e Engine) {
+	mu.Lock()
+	engineRef = e
+	mu.Unlock()
+}
 
-			if !reflect.DeepEqual(decoded, tc.expected) {
-				t.Errorf("DecodeMap(%v) = %v, expected %v", encoded, decoded, tc.expected)
-			}
-		})
-	}
+func GetEngine() Engine {
+	mu.RLock()
+	e := engineRef
+	mu.RUnlock()
+	return e
 }
diff --git a/pkg/saga/statemachine/constant/constant.go b/pkg/saga/statemachine/constant/constant.go
new file mode 100644
index 00000000..3d22e386
--- /dev/null
+++ b/pkg/saga/statemachine/constant/constant.go
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package constant
+
+type NetExceptionType string
+
+const (
+	// region State Types
+	StateTypeServiceTask          string = "ServiceTask"
+	StateTypeChoice               string = "Choice"
+	StateTypeFail                 string = "Fail"
+	StateTypeSucceed              string = "Succeed"
+	StateTypeCompensationTrigger  string = "CompensationTrigger"
+	StateTypeSubStateMachine      string = "SubStateMachine"
+	StateTypeCompensateSubMachine string = "CompensateSubMachine"
+	StateTypeScriptTask           string = "ScriptTask"
+	StateTypeLoopStart            string = "LoopStart"
+	// end region
+
+	// region Service Types
+	ServiceTypeGRPC string = "GRPC"
+	// end region
+
+	// region System Variables
+	VarNameOutputParams                  string = "outputParams"
+	VarNameProcessType                   string = "_ProcessType_"
+	VarNameOperationName                 string = "_operation_name_"
+	OperationNameStart                   string = "start"
+	OperationNameCompensate              string = "compensate"
+	VarNameAsyncCallback                 string = "_async_callback_"
+	VarNameCurrentExceptionRoute         string = "_current_exception_route_"
+	VarNameIsExceptionNotCatch           string = "_is_exception_not_catch_"
+	VarNameSubMachineParentId            string = "_sub_machine_parent_id_"
+	VarNameCurrentChoice                 string = "_current_choice_"
+	VarNameStateMachineInst              string = "_current_statemachine_instance_"
+	VarNameStateMachine                  string = "_current_statemachine_"
+	VarNameStateMachineEngine            string = "_current_statemachine_engine_"
+	VarNameStateMachineConfig            string = "_statemachine_config_"
+	VarNameStateMachineContext           string = "context"
+	VarNameIsAsyncExecution              string = "_is_async_execution_"
+	VarNameStateInst                     string = "_current_state_instance_"
+	VarNameBusinesskey                   string = "_business_key_"
+	VarNameParentId                      string = "_parent_id_"
+	VarNameCurrentException              string = "currentException"
+	CompensateSubMachineStateNamePrefix  string = "_compensate_sub_machine_state_"
+	DefaultScriptType                    string = "groovy"
+	VarNameSyncExeStack                  string = "_sync_execution_stack_"
+	VarNameInputParams                   string = "inputParams"
+	VarNameIsLoopState                   string = "_is_loop_state_"
+	VarNameCurrentCompensateTriggerState string = "_is_compensating_"
+	VarNameCurrentCompensationHolder     string = "_current_compensation_holder_"
+	VarNameFirstCompensationStateStarted string = "_first_compensation_state_started"
+	VarNameNoCompensation                string = "_no_compensation_case_"
+	VarNameCurrentLoopContextHolder      string = "_current_loop_context_holder_"
+	VarNameRetriedStateInstId            string = "_retried_state_instance_id"
+	VarNameIsForSubStatMachineForward    string = "_is_for_sub_statemachine_forward_"
+	// TODO: this lock in process context only has one, try to add more to add concurrent
+	VarNameProcessContextMutexLock string = "_current_context_mutex_lock"
+	VarNameFailEndStateFlag        string = "_fail_end_state_flag_"
+	VarNameGlobalTx                string = "_global_transaction_"
+	// end region
+
+	// region of loop
+	LoopCounter                string = "loopCounter"
+	LoopSemaphore              string = "loopSemaphore"
+	LoopResult                 string = "loopResult"
+	NumberOfInstances          string = "nrOfInstances"
+	NumberOfActiveInstances    string = "nrOfActiveInstances"
+	NumberOfCompletedInstances string = "nrOfCompletedInstances"
+	// end region
+
+	// region others
+	SeqEntityStateMachine     string = "STATE_MACHINE"
+	SeqEntityStateMachineInst string = "STATE_MACHINE_INST"
+	SeqEntityStateInst        string = "STATE_INST"
+	OperationNameForward      string = "forward"
+	LoopStateNamePattern      string = "-loop-"
+	SagaTransNamePrefix       string = "$Saga_"
+	// end region
+
+	SeperatorParentId string = ":"
+
+	// Machine execution timeout error code
+	FrameworkErrorCodeStateMachineExecutionTimeout                  = "StateMachineExecutionTimeout"
+	ConnectException                               NetExceptionType = "CONNECT_EXCEPTION"
+	ConnectTimeoutException                        NetExceptionType = "CONNECT_TIMEOUT_EXCEPTION"
+	ReadTimeoutException                           NetExceptionType = "READ_TIMEOUT_EXCEPTION"
+	NotNetException                                NetExceptionType = "NOT_NET_EXCEPTION"
+)
diff --git a/pkg/saga/statemachine/engine/config/bootstrap.go b/pkg/saga/statemachine/engine/config/bootstrap.go
new file mode 100644
index 00000000..ca18b92f
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/bootstrap.go
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"fmt"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/pcext"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl/handlers"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl/process"
+)
+
+// bootstrapProcessWiring wires default handlers/routers and router handler into BusinessProcessor
+func (c *DefaultStateMachineConfig) bootstrapProcessWiring() error {
+	// Process handler for state machine
+	smHandler := pcext.NewStateMachineProcessHandler()
+	// Register ServiceTask handler by default
+	smHandler.RegistryStateHandler(constant.StateTypeServiceTask, handlers.NewServiceTaskStateHandler())
+
+	// Router for state machine
+	smRouter := &pcext.StateMachineProcessRouter{}
+	smRouter.InitDefaultStateRouters()
+
+	// Default router handler binds event publisher and process routers
+	drh := &process_ctrl.DefaultRouterHandler{}
+	drh.SetEventPublisher(c.EventPublisher())
+	drh.SetProcessRouters(map[string]process_ctrl.ProcessRouter{
+		string(process.StateLang): smRouter,
+	})
+
+	// Register into BusinessProcessor
+	pcImpl, ok := c.processController.(*process_ctrl.ProcessControllerImpl)
+	if !ok {
+		return fmt.Errorf("ProcessController is not an instance of ProcessControllerImpl")
+	}
+	bp := pcImpl.BusinessProcessor()
+	// need concrete DefaultBusinessProcessor to call Registry APIs
+	dbp, ok := bp.(*process_ctrl.DefaultBusinessProcessor)
+	if !ok {
+		return fmt.Errorf("BusinessProcessor is not DefaultBusinessProcessor, got %T", bp)
+	}
+	dbp.RegistryProcessHandler(process.StateLang, smHandler)
+	dbp.RegistryRouterHandler(process.StateLang, drh)
+	return nil
+}
diff --git a/pkg/saga/statemachine/engine/config/default_statemachine_config.go b/pkg/saga/statemachine/engine/config/default_statemachine_config.go
new file mode 100644
index 00000000..2b865502
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/default_statemachine_config.go
@@ -0,0 +1,824 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+
+	"gopkg.in/yaml.v3"
+
+	"seata.apache.org/seata-go/pkg/protocol/branch"
+	baserm "seata.apache.org/seata-go/pkg/rm"
+	sagarm "seata.apache.org/seata-go/pkg/saga/rm"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/expr"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/invoker"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/repo"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/repo/repository"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/sequence"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/strategy"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/store"
+)
+
+const (
+	DefaultTransOperTimeout                      = 60000 * 30
+	DefaultServiceInvokeTimeout                  = 60000 * 5
+	DefaultClientSagaRetryPersistModeUpdate      = false
+	DefaultClientSagaCompensatePersistModeUpdate = false
+	DefaultClientReportSuccessEnable             = false
+	DefaultClientSagaBranchRegisterEnable        = true
+)
+
+type DefaultStateMachineConfig struct {
+	// Configuration
+	transOperationTimeout           int
+	serviceInvokeTimeout            int
+	charset                         string
+	defaultTenantId                 string
+	sagaRetryPersistModeUpdate      bool
+	sagaCompensatePersistModeUpdate bool
+	sagaBranchRegisterEnable        bool
+	rmReportSuccessEnable           bool
+	stateMachineResources           []string
+
+	// Components
+	processController process_ctrl.ProcessController
+
+	// Event Bus
+	syncEventBus  process_ctrl.EventBus
+	asyncEventBus process_ctrl.EventBus
+
+	// Event publisher
+	syncProcessCtrlEventPublisher  process_ctrl.EventPublisher
+	asyncProcessCtrlEventPublisher process_ctrl.EventPublisher
+
+	// Store related components
+	stateLogRepository     repo.StateLogRepository
+	stateLogStore          store.StateLogStore
+	stateLangStore         store.StateLangStore
+	stateMachineRepository repo.StateMachineRepository
+
+	// Expression related components
+	expressionFactoryManager *expr.ExpressionFactoryManager
+	expressionResolver       expr.ExpressionResolver
+
+	// Invoker related components
+	serviceInvokerManager invoker.ServiceInvokerManager
+	scriptInvokerManager  invoker.ScriptInvokerManager
+
+	// Other components
+	statusDecisionStrategy engine.StatusDecisionStrategy
+	seqGenerator           sequence.SeqGenerator
+	componentLock          *sync.Mutex
+
+	enableAsync bool
+
+	// runtime store & tc options
+	storeEnabled bool
+	storeType    string
+	storeDSN     string
+	tcEnabled    bool
+}
+
+func (c *DefaultStateMachineConfig) ComponentLock() *sync.Mutex {
+	return c.componentLock
+}
+
+func (c *DefaultStateMachineConfig) SetComponentLock(componentLock *sync.Mutex) {
+	c.componentLock = componentLock
+}
+
+func (c *DefaultStateMachineConfig) SetTransOperationTimeout(transOperationTimeout int) {
+	c.transOperationTimeout = transOperationTimeout
+}
+
+func (c *DefaultStateMachineConfig) SetServiceInvokeTimeout(serviceInvokeTimeout int) {
+	c.serviceInvokeTimeout = serviceInvokeTimeout
+}
+
+func (c *DefaultStateMachineConfig) SetCharset(charset string) {
+	c.charset = charset
+}
+
+func (c *DefaultStateMachineConfig) SetDefaultTenantId(defaultTenantId string) {
+	c.defaultTenantId = defaultTenantId
+}
+
+func (c *DefaultStateMachineConfig) SetSyncEventBus(syncEventBus process_ctrl.EventBus) {
+	c.syncEventBus = syncEventBus
+}
+
+func (c *DefaultStateMachineConfig) SetAsyncEventBus(asyncEventBus process_ctrl.EventBus) {
+	c.asyncEventBus = asyncEventBus
+}
+
+func (c *DefaultStateMachineConfig) SetSyncProcessCtrlEventPublisher(syncProcessCtrlEventPublisher process_ctrl.EventPublisher) {
+	c.syncProcessCtrlEventPublisher = syncProcessCtrlEventPublisher
+}
+
+func (c *DefaultStateMachineConfig) SetAsyncProcessCtrlEventPublisher(asyncProcessCtrlEventPublisher process_ctrl.EventPublisher) {
+	c.asyncProcessCtrlEventPublisher = asyncProcessCtrlEventPublisher
+}
+
+func (c *DefaultStateMachineConfig) SetStateLogRepository(stateLogRepository repo.StateLogRepository) {
+	c.stateLogRepository = stateLogRepository
+}
+
+func (c *DefaultStateMachineConfig) SetStateLogStore(stateLogStore store.StateLogStore) {
+	c.stateLogStore = stateLogStore
+}
+
+func (c *DefaultStateMachineConfig) SetStateLangStore(stateLangStore store.StateLangStore) {
+	c.stateLangStore = stateLangStore
+}
+
+func (c *DefaultStateMachineConfig) SetStateMachineRepository(stateMachineRepository repo.StateMachineRepository) {
+	c.stateMachineRepository = stateMachineRepository
+}
+
+func (c *DefaultStateMachineConfig) SetExpressionFactoryManager(expressionFactoryManager *expr.ExpressionFactoryManager) {
+	c.expressionFactoryManager = expressionFactoryManager
+}
+
+func (c *DefaultStateMachineConfig) SetExpressionResolver(expressionResolver expr.ExpressionResolver) {
+	c.expressionResolver = expressionResolver
+}
+
+func (c *DefaultStateMachineConfig) SetServiceInvokerManager(serviceInvokerManager invoker.ServiceInvokerManager) {
+	c.serviceInvokerManager = serviceInvokerManager
+}
+
+func (c *DefaultStateMachineConfig) SetScriptInvokerManager(scriptInvokerManager invoker.ScriptInvokerManager) {
+	c.scriptInvokerManager = scriptInvokerManager
+}
+
+func (c *DefaultStateMachineConfig) SetStatusDecisionStrategy(statusDecisionStrategy engine.StatusDecisionStrategy) {
+	c.statusDecisionStrategy = statusDecisionStrategy
+}
+
+func (c *DefaultStateMachineConfig) SetSeqGenerator(seqGenerator sequence.SeqGenerator) {
+	c.seqGenerator = seqGenerator
+}
+
+func (c *DefaultStateMachineConfig) StateLogRepository() repo.StateLogRepository {
+	return c.stateLogRepository
+}
+
+func (c *DefaultStateMachineConfig) StateMachineRepository() repo.StateMachineRepository {
+	return c.stateMachineRepository
+}
+
+func (c *DefaultStateMachineConfig) StateLogStore() store.StateLogStore {
+	return c.stateLogStore
+}
+
+func (c *DefaultStateMachineConfig) StateLangStore() store.StateLangStore {
+	return c.stateLangStore
+}
+
+func (c *DefaultStateMachineConfig) ExpressionFactoryManager() *expr.ExpressionFactoryManager {
+	return c.expressionFactoryManager
+}
+
+func (c *DefaultStateMachineConfig) ExpressionResolver() expr.ExpressionResolver {
+	return c.expressionResolver
+}
+
+func (c *DefaultStateMachineConfig) SeqGenerator() sequence.SeqGenerator {
+	return c.seqGenerator
+}
+
+func (c *DefaultStateMachineConfig) StatusDecisionStrategy() engine.StatusDecisionStrategy {
+	return c.statusDecisionStrategy
+}
+
+func (c *DefaultStateMachineConfig) SyncEventBus() process_ctrl.EventBus {
+	return c.syncEventBus
+}
+
+func (c *DefaultStateMachineConfig) AsyncEventBus() process_ctrl.EventBus {
+	return c.asyncEventBus
+}
+
+func (c *DefaultStateMachineConfig) EventPublisher() process_ctrl.EventPublisher {
+	return c.syncProcessCtrlEventPublisher
+}
+
+func (c *DefaultStateMachineConfig) AsyncEventPublisher() process_ctrl.EventPublisher {
+	return c.asyncProcessCtrlEventPublisher
+}
+
+func (c *DefaultStateMachineConfig) ServiceInvokerManager() invoker.ServiceInvokerManager {
+	return c.serviceInvokerManager
+}
+
+func (c *DefaultStateMachineConfig) ScriptInvokerManager() invoker.ScriptInvokerManager {
+	return c.scriptInvokerManager
+}
+
+func (c *DefaultStateMachineConfig) CharSet() string {
+	return c.charset
+}
+
+func (c *DefaultStateMachineConfig) SetCharSet(charset string) {
+	c.charset = charset
+}
+
+func (c *DefaultStateMachineConfig) GetDefaultTenantId() string {
+	return c.defaultTenantId
+}
+
+func (c *DefaultStateMachineConfig) GetTransOperationTimeout() int {
+	return c.transOperationTimeout
+}
+
+func (c *DefaultStateMachineConfig) GetServiceInvokeTimeout() int {
+	return c.serviceInvokeTimeout
+}
+
+func (c *DefaultStateMachineConfig) EnableAsync() bool {
+	return c.enableAsync
+}
+
+func (c *DefaultStateMachineConfig) SetEnableAsync(enable bool) {
+	c.enableAsync = enable
+}
+
+func (c *DefaultStateMachineConfig) IsSagaRetryPersistModeUpdate() bool {
+	return c.sagaRetryPersistModeUpdate
+}
+
+func (c *DefaultStateMachineConfig) SetSagaRetryPersistModeUpdate(sagaRetryPersistModeUpdate bool) {
+	c.sagaRetryPersistModeUpdate = sagaRetryPersistModeUpdate
+}
+
+func (c *DefaultStateMachineConfig) IsSagaCompensatePersistModeUpdate() bool {
+	return c.sagaCompensatePersistModeUpdate
+}
+
+func (c *DefaultStateMachineConfig) SetSagaCompensatePersistModeUpdate(sagaCompensatePersistModeUpdate bool) {
+	c.sagaCompensatePersistModeUpdate = sagaCompensatePersistModeUpdate
+}
+
+func (c *DefaultStateMachineConfig) IsSagaBranchRegisterEnable() bool {
+	return c.sagaBranchRegisterEnable
+}
+
+func (c *DefaultStateMachineConfig) SetSagaBranchRegisterEnable(sagaBranchRegisterEnable bool) {
+	c.sagaBranchRegisterEnable = sagaBranchRegisterEnable
+}
+
+func (c *DefaultStateMachineConfig) IsRmReportSuccessEnable() bool {
+	return c.rmReportSuccessEnable
+}
+
+func (c *DefaultStateMachineConfig) SetRmReportSuccessEnable(rmReportSuccessEnable bool) {
+	c.rmReportSuccessEnable = rmReportSuccessEnable
+}
+
+func (c *DefaultStateMachineConfig) GetStateMachineConfig() engine.StateMachineConfig {
+	return c
+}
+
+func (c *DefaultStateMachineConfig) GetExpressionFactory(expressionType string) expr.ExpressionFactory {
+	return c.expressionFactoryManager.GetExpressionFactory(expressionType)
+}
+
+func (c *DefaultStateMachineConfig) GetServiceInvoker(serviceType string) (invoker.ServiceInvoker, error) {
+	if serviceType == "" {
+		serviceType = "local"
+	}
+
+	invoker := c.serviceInvokerManager.ServiceInvoker(serviceType)
+	if invoker == nil {
+		return nil, fmt.Errorf("service invoker not found for type: %s", serviceType)
+	}
+
+	return invoker, nil
+}
+
+func (c *DefaultStateMachineConfig) RegisterStateMachineDef(resources []string) error {
+	var allFiles []string
+
+	for _, pattern := range resources {
+		matches, err := filepath.Glob(pattern)
+		if err != nil {
+			return fmt.Errorf("failed to expand glob pattern: pattern=%s, err=%w", pattern, err)
+		}
+		if len(matches) == 0 {
+			return fmt.Errorf("open resource file failed: pattern=%s", pattern)
+		}
+		allFiles = append(allFiles, matches...)
+	}
+
+	for _, realPath := range allFiles {
+		file, err := os.Open(realPath)
+		if err != nil {
+			return fmt.Errorf("open resource file failed: path=%s, err=%w", realPath, err)
+		}
+		defer file.Close()
+
+		if err := c.stateMachineRepository.RegistryStateMachineByReader(file); err != nil {
+			return fmt.Errorf("register state machine from file failed: path=%s, err=%w", realPath, err)
+		}
+	}
+
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) RegisterExpressionFactory(expressionType string, factory expr.ExpressionFactory) {
+	c.expressionFactoryManager.PutExpressionFactory(expressionType, factory)
+}
+
+func (c *DefaultStateMachineConfig) RegisterServiceInvoker(serviceType string, invoker invoker.ServiceInvoker) {
+	c.serviceInvokerManager.PutServiceInvoker(serviceType, invoker)
+}
+
+type ConfigFileParams struct {
+	TransOperationTimeout           int      `json:"trans_operation_timeout" yaml:"trans_operation_timeout"`
+	ServiceInvokeTimeout            int      `json:"service_invoke_timeout" yaml:"service_invoke_timeout"`
+	Charset                         string   `json:"charset" yaml:"charset"`
+	DefaultTenantId                 string   `json:"default_tenant_id" yaml:"default_tenant_id"`
+	EnableAsync                     bool     `json:"enable_async" yaml:"enable_async"`
+	SagaRetryPersistModeUpdate      bool     `json:"saga_retry_persist_mode_update" yaml:"saga_retry_persist_mode_update"`
+	SagaCompensatePersistModeUpdate bool     `json:"saga_compensate_persist_mode_update" yaml:"saga_compensate_persist_mode_update"`
+	SagaBranchRegisterEnable        bool     `json:"saga_branch_register_enable" yaml:"saga_branch_register_enable"`
+	RmReportSuccessEnable           bool     `json:"rm_report_success_enable" yaml:"rm_report_success_enable"`
+	StateMachineResources           []string `json:"state_machine_resources" yaml:"state_machine_resources"`
+	StoreEnabled                    bool     `json:"store_enabled" yaml:"store_enabled"`
+	StoreType                       string   `json:"store_type" yaml:"store_type"`
+	StoreDSN                        string   `json:"store_dsn" yaml:"store_dsn"`
+	TCEnabled                       bool     `json:"tc_enabled" yaml:"tc_enabled"`
+}
+
+func (c *DefaultStateMachineConfig) LoadConfig(configPath string) error {
+	if c.seqGenerator == nil {
+		c.seqGenerator = sequence.NewUUIDSeqGenerator()
+	}
+
+	content, err := os.ReadFile(configPath)
+	if err != nil {
+		return fmt.Errorf("failed to read config file: path=%s, error=%w", configPath, err)
+	}
+
+	var configFileParams ConfigFileParams
+	ext := strings.ToLower(filepath.Ext(configPath))
+
+	switch ext {
+	case ".json":
+		if err := json.Unmarshal(content, &configFileParams); err != nil {
+			return fmt.Errorf("failed to unmarshal config file as JSON: %w", err)
+		}
+	case ".yaml", ".yml":
+		if err := yaml.Unmarshal(content, &configFileParams); err != nil {
+			return fmt.Errorf("failed to unmarshal config file as YAML: %w", err)
+		}
+	default:
+		return fmt.Errorf("unsupported config file type: path=%s, ext=%s (only .json/.yaml/.yml are supported)", configPath, ext)
+	}
+
+	c.applyConfigFileParams(&configFileParams)
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) applyConfigFileParams(rc *ConfigFileParams) {
+	if rc.TransOperationTimeout > 0 {
+		c.transOperationTimeout = rc.TransOperationTimeout
+	}
+	if rc.ServiceInvokeTimeout > 0 {
+		c.serviceInvokeTimeout = rc.ServiceInvokeTimeout
+	}
+	if rc.Charset != "" {
+		c.charset = rc.Charset
+	}
+	if rc.DefaultTenantId != "" {
+		c.defaultTenantId = rc.DefaultTenantId
+	}
+	c.enableAsync = rc.EnableAsync
+	c.sagaRetryPersistModeUpdate = rc.SagaRetryPersistModeUpdate
+	c.sagaCompensatePersistModeUpdate = rc.SagaCompensatePersistModeUpdate
+	c.sagaBranchRegisterEnable = rc.SagaBranchRegisterEnable
+	c.rmReportSuccessEnable = rc.RmReportSuccessEnable
+	if len(rc.StateMachineResources) > 0 {
+		c.stateMachineResources = rc.StateMachineResources
+	}
+	c.storeEnabled = rc.StoreEnabled
+	if rc.StoreType != "" {
+		c.storeType = rc.StoreType
+	}
+	if rc.StoreDSN != "" {
+		c.storeDSN = rc.StoreDSN
+	}
+	c.tcEnabled = rc.TCEnabled
+}
+
+func (c *DefaultStateMachineConfig) registerEventConsumers() error {
+	if c.processController == nil {
+		return fmt.Errorf("ProcessController is not initialized")
+	}
+
+	pcImpl, ok := c.processController.(*process_ctrl.ProcessControllerImpl)
+	if !ok {
+		return fmt.Errorf("ProcessController is not an instance of ProcessControllerImpl")
+	}
+
+	if pcImpl.BusinessProcessor() == nil {
+		return fmt.Errorf("BusinessProcessor in ProcessController is not initialized")
+	}
+
+	consumer := process_ctrl.NewProcessCtrlEventConsumer(c.processController)
+
+	c.syncEventBus.RegisterEventConsumer(consumer)
+	c.asyncEventBus.RegisterEventConsumer(consumer)
+
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) Init() error {
+	if err := c.initExpressionComponents(); err != nil {
+		return fmt.Errorf("initialize expression components failed: %w", err)
+	}
+
+	if err := c.initServiceInvokers(); err != nil {
+		return fmt.Errorf("initialize service invokers failed: %w", err)
+	}
+
+	if err := c.bootstrapProcessWiring(); err != nil {
+		return fmt.Errorf("bootstrap wiring failed: %w", err)
+	}
+
+	if err := c.SetupStoresFromConfig(); err != nil {
+		return fmt.Errorf("setup stores from config failed: %w", err)
+	}
+
+	if err := c.registerEventConsumers(); err != nil {
+		return fmt.Errorf("register event consumers failed: %w", err)
+	}
+
+	if c.stateMachineRepository != nil && len(c.stateMachineResources) > 0 {
+		if err := c.RegisterStateMachineDef(c.stateMachineResources); err != nil {
+			return fmt.Errorf("register state machine def failed: %w", err)
+		}
+	}
+
+	if c.tcEnabled {
+		sagarm.InitSaga()
+		app, group := baserm.GetRmAppAndGroup()
+		if app != "" && group != "" {
+			if mgr := baserm.GetRmCacheInstance().GetResourceManager(branch.BranchTypeSAGA); mgr != nil {
+				resource := &sagarm.SagaResource{}
+				resource.SetApplicationId(app)
+				resource.SetResourceGroupId(group)
+				_ = mgr.RegisterResource(resource)
+			}
+		}
+	}
+
+	if err := c.Validate(); err != nil {
+		return fmt.Errorf("configuration validation failed: %w", err)
+	}
+
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) initExpressionComponents() error {
+	if c.expressionFactoryManager == nil {
+		c.expressionFactoryManager = expr.NewExpressionFactoryManager()
+	}
+
+	defaultType := expr.DefaultExpressionType
+	if defaultType == "" {
+		defaultType = "Default"
+	}
+
+	if factory := c.expressionFactoryManager.GetExpressionFactory(defaultType); factory == nil {
+		c.RegisterExpressionFactory(defaultType, expr.NewCELExpressionFactory())
+	}
+
+	if factory := c.expressionFactoryManager.GetExpressionFactory("CEL"); factory == nil {
+		c.RegisterExpressionFactory("CEL", expr.NewCELExpressionFactory())
+	}
+
+	if factory := c.expressionFactoryManager.GetExpressionFactory("el"); factory == nil {
+		c.RegisterExpressionFactory("el", expr.NewCELExpressionFactory())
+	}
+
+	if c.seqGenerator != nil {
+		sequenceFactory := expr.NewSequenceExpressionFactory(c.seqGenerator)
+		c.RegisterExpressionFactory("SEQUENCE", sequenceFactory)
+		c.RegisterExpressionFactory("SEQ", sequenceFactory)
+	}
+
+	if c.expressionResolver == nil {
+		resolver := &expr.DefaultExpressionResolver{}
+		resolver.SetExpressionFactoryManager(*c.expressionFactoryManager)
+		c.expressionResolver = resolver
+	}
+
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) initServiceInvokers() error {
+	if c.serviceInvokerManager == nil {
+		c.serviceInvokerManager = invoker.NewServiceInvokerManagerImpl()
+	}
+
+	if existing := c.serviceInvokerManager.ServiceInvoker("local"); existing == nil {
+		c.RegisterServiceInvoker("local", invoker.NewLocalServiceInvoker())
+	}
+
+	if existing := c.serviceInvokerManager.ServiceInvoker("http"); existing == nil {
+		c.RegisterServiceInvoker("http", invoker.NewHTTPInvoker())
+	}
+
+	if existing := c.serviceInvokerManager.ServiceInvoker("grpc"); existing == nil {
+		c.RegisterServiceInvoker("grpc", invoker.NewGRPCInvoker())
+	}
+
+	if existing := c.serviceInvokerManager.ServiceInvoker("func"); existing == nil {
+		c.RegisterServiceInvoker("func", invoker.NewFuncInvoker())
+	}
+
+	if c.scriptInvokerManager == nil {
+		c.scriptInvokerManager = invoker.NewScriptInvokerManager()
+	}
+
+	if jsInvoker, err := c.scriptInvokerManager.GetInvoker("javascript"); err != nil || jsInvoker == nil {
+		c.scriptInvokerManager.RegisterInvoker(invoker.NewJavaScriptScriptInvoker())
+	}
+
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) Validate() error {
+	var errs []error
+
+	if c.expressionFactoryManager == nil {
+		errs = append(errs, fmt.Errorf("expression factory manager is nil"))
+	}
+	if c.expressionResolver == nil {
+		errs = append(errs, fmt.Errorf("expression resolver is nil"))
+	}
+	if c.serviceInvokerManager == nil {
+		errs = append(errs, fmt.Errorf("service invoker manager is nil"))
+	}
+
+	if c.scriptInvokerManager == nil {
+		errs = append(errs, fmt.Errorf("script invoker manager is nil"))
+	}
+
+	if c.transOperationTimeout <= 0 {
+		errs = append(errs, fmt.Errorf("invalid trans operation timeout: %d", c.transOperationTimeout))
+	}
+	if c.serviceInvokeTimeout <= 0 {
+		errs = append(errs, fmt.Errorf("invalid service invoke timeout: %d", c.serviceInvokeTimeout))
+	}
+	if c.charset == "" {
+		errs = append(errs, fmt.Errorf("charset is empty"))
+	}
+
+	if c.stateMachineRepository != nil {
+		if c.stateLogStore == nil {
+			errs = append(errs, fmt.Errorf("state log store is nil"))
+		}
+		if c.stateLangStore == nil {
+			errs = append(errs, fmt.Errorf("state lang store is nil"))
+		}
+		if c.stateLogRepository == nil {
+			errs = append(errs, fmt.Errorf("state log repository is nil"))
+		}
+	}
+
+	if c.statusDecisionStrategy == nil {
+		errs = append(errs, fmt.Errorf("status decision strategy is nil"))
+	}
+	if c.syncEventBus == nil {
+		errs = append(errs, fmt.Errorf("sync event bus is nil"))
+	}
+	if c.asyncEventBus == nil {
+		errs = append(errs, fmt.Errorf("async event bus is nil"))
+	}
+
+	if len(errs) > 0 {
+		return fmt.Errorf("configuration validation failed with %d errors: %v", len(errs), errs)
+	}
+	return nil
+}
+
+func (c *DefaultStateMachineConfig) EvaluateExpression(expressionStr string, context any) (any, error) {
+	if c.expressionResolver == nil {
+		return nil, fmt.Errorf("expression resolver not initialized")
+	}
+
+	expression := c.expressionResolver.Expression(expressionStr)
+	if expression == nil {
+		return nil, fmt.Errorf("failed to parse expression: %s", expressionStr)
+	}
+
+	var result any
+	var evalErr error
+
+	func() {
+		defer func() {
+			if r := recover(); r != nil {
+				evalErr = fmt.Errorf("expression evaluation panicked: %v", r)
+			}
+		}()
+
+		result = expression.Value(context)
+	}()
+
+	if evalErr != nil {
+		return nil, evalErr
+	}
+
+	if err, ok := result.(error); ok {
+		return nil, fmt.Errorf("expression evaluation returned error: %w", err)
+	}
+
+	return result, nil
+}
+
+func NewDefaultStateMachineConfig(opts ...Option) (*DefaultStateMachineConfig, error) {
+	ctx := context.Background()
+	defaultBP := process_ctrl.NewBusinessProcessor()
+
+	c := &DefaultStateMachineConfig{
+		transOperationTimeout:           DefaultTransOperTimeout,
+		serviceInvokeTimeout:            DefaultServiceInvokeTimeout,
+		charset:                         "UTF-8",
+		defaultTenantId:                 "000001",
+		stateMachineResources:           parseEnvResources(),
+		sagaRetryPersistModeUpdate:      DefaultClientSagaRetryPersistModeUpdate,
+		sagaCompensatePersistModeUpdate: DefaultClientSagaCompensatePersistModeUpdate,
+		sagaBranchRegisterEnable:        DefaultClientSagaBranchRegisterEnable,
+		rmReportSuccessEnable:           DefaultClientReportSuccessEnable,
+		componentLock:                   &sync.Mutex{},
+		seqGenerator:                    sequence.NewUUIDSeqGenerator(),
+		statusDecisionStrategy:          strategy.NewDefaultStatusDecisionStrategy(),
+		processController: func() process_ctrl.ProcessController {
+			pc := &process_ctrl.ProcessControllerImpl{}
+			pc.SetBusinessProcessor(defaultBP)
+			return pc
+		}(),
+		syncEventBus:  process_ctrl.NewDirectEventBus(),
+		asyncEventBus: process_ctrl.NewAsyncEventBus(ctx, 1000, 5),
+
+		syncProcessCtrlEventPublisher:  nil,
+		asyncProcessCtrlEventPublisher: nil,
+
+		stateLogStore:  &NoopStateLogStore{},
+		stateLangStore: &NoopStateLangStore{},
+	}
+
+	c.stateMachineRepository = repository.GetStateMachineRepositoryImpl()
+	c.stateLogRepository = repository.NewStateLogRepositoryImpl()
+	repository.GetStateMachineRepositoryImpl().SetDefaultTenantId(c.defaultTenantId)
+
+	c.syncProcessCtrlEventPublisher = process_ctrl.NewProcessCtrlEventPublisher(c.syncEventBus)
+	c.asyncProcessCtrlEventPublisher = process_ctrl.NewProcessCtrlEventPublisher(c.asyncEventBus)
+
+	for _, opt := range opts {
+		opt(c)
+	}
+	repository.GetStateMachineRepositoryImpl().SetDefaultTenantId(c.defaultTenantId)
+
+	if _, statErr := os.Stat("config.yaml"); statErr == nil {
+		if err := c.LoadConfig("config.yaml"); err == nil {
+			repository.GetStateMachineRepositoryImpl().SetDefaultTenantId(c.defaultTenantId)
+			log.Printf("Successfully loaded config from config.yaml")
+		} else {
+			log.Printf("Failed to load config file (using default/env values): %v", err)
+		}
+	}
+
+	if err := c.Init(); err != nil {
+		return nil, fmt.Errorf("failed to initialize state machine config: %w", err)
+	}
+
+	return c, nil
+}
+
+func parseEnvResources() []string {
+	if env := os.Getenv("SEATA_STATE_MACHINE_RESOURCES"); env != "" {
+		parts := strings.Split(env, ",")
+		var res []string
+		for _, p := range parts {
+			if p = strings.TrimSpace(p); p != "" {
+				res = append(res, p)
+			}
+		}
+		return res
+	}
+	return nil
+}
+
+type Option func(*DefaultStateMachineConfig)
+
+func WithStatusDecisionStrategy(strategy engine.StatusDecisionStrategy) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.statusDecisionStrategy = strategy
+	}
+}
+
+func WithSeqGenerator(gen sequence.SeqGenerator) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.seqGenerator = gen
+	}
+}
+
+func WithProcessController(ctrl process_ctrl.ProcessController) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.processController = ctrl
+	}
+}
+
+func WithBusinessProcessor(bp process_ctrl.BusinessProcessor) Option {
+	return func(c *DefaultStateMachineConfig) {
+		if pc, ok := c.processController.(*process_ctrl.ProcessControllerImpl); ok {
+			pc.SetBusinessProcessor(bp)
+		} else {
+			log.Printf("ProcessController is not of type *ProcessControllerImpl, unable to set BusinessProcessor")
+		}
+	}
+}
+
+func WithStateMachineResources(paths []string) Option {
+	return func(c *DefaultStateMachineConfig) {
+		if len(paths) > 0 {
+			c.stateMachineResources = paths
+		}
+	}
+}
+
+func WithEnableAsync(enable bool) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.enableAsync = enable
+	}
+}
+
+func WithStateLogRepository(logRepo repo.StateLogRepository) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.stateLogRepository = logRepo
+	}
+}
+
+func WithStateLogStore(logStore store.StateLogStore) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.stateLogStore = logStore
+	}
+}
+
+func WithStateLangStore(langStore store.StateLangStore) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.stateLangStore = langStore
+	}
+}
+
+func WithStateMachineRepository(machineRepo repo.StateMachineRepository) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.stateMachineRepository = machineRepo
+	}
+}
+
+func WithConfigPath(path string) Option {
+	return func(c *DefaultStateMachineConfig) {
+		if path == "" {
+			return
+		}
+		if err := c.LoadConfig(path); err != nil {
+			log.Printf("Failed to load config from %s: %v", path, err)
+		} else {
+			log.Printf("Successfully loaded config from %s", path)
+		}
+	}
+}
+
+func WithScriptInvokerManager(scriptManager invoker.ScriptInvokerManager) Option {
+	return func(c *DefaultStateMachineConfig) {
+		c.scriptInvokerManager = scriptManager
+	}
+}
diff --git a/pkg/saga/statemachine/engine/config/default_statemachine_config_test.go b/pkg/saga/statemachine/engine/config/default_statemachine_config_test.go
new file mode 100644
index 00000000..653952e6
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/default_statemachine_config_test.go
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"io"
+	"os"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/pkg/errors"
+
+	"github.com/stretchr/testify/assert"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+)
+
+type TestStateMachineRepositoryMock struct {
+}
+
+func (m *TestStateMachineRepositoryMock) GetStateMachineById(stateMachineId string) (statelang.StateMachine, error) {
+	return nil, errors.New("mock repository error")
+}
+
+func (m *TestStateMachineRepositoryMock) GetStateMachineByNameAndTenantId(stateMachineName string, tenantId string) (statelang.StateMachine, error) {
+	return nil, errors.New("mock repository error")
+}
+
+func (m *TestStateMachineRepositoryMock) GetLastVersionStateMachine(stateMachineName string, tenantId string) (statelang.StateMachine, error) {
+	return nil, errors.New("mock repository error")
+}
+
+func (m *TestStateMachineRepositoryMock) RegistryStateMachine(stateMachine statelang.StateMachine) error {
+	return errors.New("mock registration error")
+}
+
+func (m *TestStateMachineRepositoryMock) RegistryStateMachineByReader(reader io.Reader) error {
+	return errors.New("mock registration error")
+}
+
+func TestDefaultStateMachineConfig_LoadValidJSON(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	testFile := filepath.Join("testdata", "saga_config.json")
+	config, err := NewDefaultStateMachineConfig(WithConfigPath(testFile))
+	assert.NoError(t, err, "Failed to initialize config")
+	assert.NotNil(t, config, "config is nil")
+
+	smo, err := config.stateMachineRepository.GetStateMachineByNameAndTenantId("OrderSaga", config.GetDefaultTenantId())
+	assert.NoError(t, err)
+	assert.NotNil(t, smo, "State machine definition should not be nil")
+
+	assert.Equal(t, "CreateOrder", smo.StartState(), "The start state should be correct")
+	assert.Contains(t, smo.States(), "CreateOrder", "The state node should exist")
+	assert.Equal(t, 30000, config.transOperationTimeout, "The timeout should be read correctly")
+}
+
+func TestDefaultStateMachineConfig_LoadValidYAML(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	testFile := filepath.Join("testdata", "saga_config.yaml")
+	config, err := NewDefaultStateMachineConfig(WithConfigPath(testFile))
+	assert.NoError(t, err, "Failed to initialize config")
+	assert.NotNil(t, config, "config is nil")
+
+	smo, err := config.stateMachineRepository.GetStateMachineByNameAndTenantId("OrderSaga", config.GetDefaultTenantId())
+	assert.NoError(t, err)
+	assert.NotNil(t, smo, "State machine definition should not be nil (YAML)")
+
+	assert.Equal(t, "CreateOrder", smo.StartState(), "The start state should be correct (YAML)")
+	assert.Contains(t, smo.States(), "CreateOrder", "The state node should exist (YAML)")
+	assert.Equal(t, 30000, config.transOperationTimeout, "The timeout should be read correctly (YAML)")
+}
+
+func TestLoadNonExistentFile(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig(WithConfigPath("non_existent.json"))
+	err := config.LoadConfig("non_existent.json")
+	assert.Error(t, err, "Loading a non-existent file should report an error")
+	assert.Contains(t, err.Error(), "failed to read config file")
+}
+
+func TestGetStateMachineDefinition_Exists(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig(WithConfigPath(filepath.Join("testdata", "saga_config.json")))
+
+	smo, err := config.stateMachineRepository.GetStateMachineByNameAndTenantId("OrderSaga", config.GetDefaultTenantId())
+	assert.NoError(t, err)
+	assert.NotNil(t, smo)
+	assert.Equal(t, "1.0", smo.Version(), "The version number should be correct")
+}
+
+func TestGetNonExistentStateMachine(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	smo, err := config.stateMachineRepository.GetStateMachineByNameAndTenantId("NonExistent", config.GetDefaultTenantId())
+	assert.Error(t, err)
+	assert.True(t, smo == nil || reflect.ValueOf(smo).IsZero(), "An unloaded state machine should return nil/zero")
+}
+
+func TestLoadDuplicateStateMachine(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	testFile := filepath.Join("testdata", "saga_config.json")
+	config, err := NewDefaultStateMachineConfig(WithConfigPath(testFile))
+	assert.NoError(t, err)
+
+	err = config.LoadConfig(testFile)
+	assert.NoError(t, err, "First load failed")
+
+	err = config.LoadConfig(testFile)
+	assert.NoError(t, err, "Duplicate load of identical config should not error")
+
+	v2File := filepath.Join("testdata", "saga_config_v2.json")
+	err = config.LoadConfig(v2File)
+	assert.NoError(t, err, "Load of different version should succeed")
+}
+
+func TestRuntimeConfig_OverrideDefaults(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	assert.Equal(t, "UTF-8", config.charset, "The default character set should be UTF-8")
+
+	_, _ = NewDefaultStateMachineConfig(WithConfigPath(filepath.Join("testdata", "order_saga.json")))
+	assert.Equal(t, "UTF-8", config.charset, "If the configuration does not specify, the default value should be used")
+
+	customConfig := &ConfigFileParams{
+		Charset: "GBK",
+	}
+	config.applyConfigFileParams(customConfig)
+	assert.Equal(t, "GBK", config.charset, "Runtime parameters should be correctly overridden")
+}
+
+func TestGetDefaultExpressionFactory(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+
+	factory := config.GetExpressionFactory("el")
+	assert.NotNil(t, factory, "The default EL factory should exist")
+
+	unknownFactory := config.GetExpressionFactory("unknown")
+	assert.Nil(t, unknownFactory, "An unknown expression type should return nil")
+}
+
+func TestGetServiceInvoker(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig(WithConfigPath(filepath.Join("testdata", "saga_config.json")))
+
+	invoker, _ := config.GetServiceInvoker("local")
+	if invoker == nil {
+		t.Errorf("expected non-nil invoker, got nil")
+	}
+}
+
+func TestLoadConfig_InvalidJSON(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	testFile := filepath.Join("testdata", "invalid.json")
+
+	err := config.LoadConfig(testFile)
+	assert.Error(t, err, "Loading an invalid JSON configuration should report an error")
+	assert.Contains(t, err.Error(), "JSON", "The error message should indicate JSON parsing failure")
+}
+
+func TestLoadConfig_InvalidYAML(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	testFile := filepath.Join("testdata", "invalid.yaml")
+
+	err := config.LoadConfig(testFile)
+	assert.Error(t, err, "Loading an invalid YAML configuration should report an error")
+	assert.Contains(t, err.Error(), "yaml", "The error message should indicate YAML parsing failure")
+}
+
+func TestRegisterStateMachineDef_Fail(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	invalidResource := []string{"invalid_path.json"}
+
+	err := config.RegisterStateMachineDef(invalidResource)
+	assert.Error(t, err, "Registering an invalid resource should report an error")
+	assert.Contains(t, err.Error(), "open resource file failed", "The error message should contain file opening failure")
+}
+
+func TestInit_ExpressionFactoryManagerNil(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	config.expressionFactoryManager = nil
+
+	err := config.Init()
+	assert.NoError(t, err, "Initialization should succeed when the expression factory manager is nil")
+}
+
+func TestInit_ServiceInvokerManagerNil(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	config.serviceInvokerManager = nil
+
+	err := config.Init()
+	assert.NoError(t, err, "Initialization should succeed when the service invoker manager is nil")
+}
+
+func TestInit_StateMachineRepositoryNil(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	config.stateMachineRepository = nil
+
+	err := config.Init()
+	assert.NoError(t, err, "Initialization should succeed when the state machine repository is nil")
+}
+
+func TestApplyRuntimeConfig_BoundaryValues(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig()
+	customConfig := &ConfigFileParams{
+		TransOperationTimeout: 1,
+		ServiceInvokeTimeout:  1,
+	}
+	config.applyConfigFileParams(customConfig)
+	assert.Equal(t, 1, config.transOperationTimeout, "The minimum transaction operation timeout should be correctly applied")
+	assert.Equal(t, 1, config.serviceInvokeTimeout, "The minimum service invocation timeout should be correctly applied")
+
+	maxTimeout := int(^uint(0) >> 1)
+	customConfig = &ConfigFileParams{
+		TransOperationTimeout: maxTimeout,
+		ServiceInvokeTimeout:  maxTimeout,
+	}
+	config.applyConfigFileParams(customConfig)
+	assert.Equal(t, maxTimeout, config.transOperationTimeout, "The maximum transaction operation timeout should be correctly applied")
+	assert.Equal(t, maxTimeout, config.serviceInvokeTimeout, "The maximum service invocation timeout should be correctly applied")
+}
+
+func TestRegisterStateMachineDef_RepositoryError(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, _ := NewDefaultStateMachineConfig(WithStateMachineRepository(&TestStateMachineRepositoryMock{}))
+	resource := []string{filepath.Join("testdata", "order_saga.json")}
+
+	err := config.RegisterStateMachineDef(resource)
+	assert.Error(t, err, "Registration should fail when the state machine repository reports an error")
+	assert.Contains(t, err.Error(), "register state machine from file failed", "The error message should contain registration failure")
+}
+
+func TestAllComponentsInitialization(t *testing.T) {
+	os.Unsetenv("SEATA_STATE_MACHINE_RESOURCES")
+
+	config, err := NewDefaultStateMachineConfig()
+	assert.NoError(t, err, "Failed to create config instance")
+	assert.NotNil(t, config, "Config instance is nil")
+
+	err = config.Init()
+	assert.NoError(t, err, "Failed to initialize config")
+
+	t.Run("ProcessController", func(t *testing.T) {
+		assert.NotNil(t, config.processController, "Process controller is not initialized")
+	})
+
+	t.Run("EventBusAndPublisher", func(t *testing.T) {
+		assert.NotNil(t, config.syncEventBus, "Sync event bus is not initialized")
+		assert.NotNil(t, config.asyncEventBus, "Async event bus is not initialized")
+		assert.NotNil(t, config.syncProcessCtrlEventPublisher, "Sync event publisher is not initialized")
+		assert.NotNil(t, config.asyncProcessCtrlEventPublisher, "Async event publisher is not initialized")
+	})
+
+	t.Run("StoreComponents", func(t *testing.T) {
+		assert.NotNil(t, config.stateLogRepository, "State log repository is not initialized")
+		assert.NotNil(t, config.stateLogStore, "State log store is not initialized")
+		assert.NotNil(t, config.stateLangStore, "State language store is not initialized")
+		assert.NotNil(t, config.stateMachineRepository, "State machine repository is not initialized")
+	})
+
+	t.Run("ExpressionComponents", func(t *testing.T) {
+		assert.NotNil(t, config.expressionFactoryManager, "Expression factory manager is not initialized")
+		assert.NotNil(t, config.expressionResolver, "Expression resolver is not initialized")
+
+		elFactory := config.expressionFactoryManager.GetExpressionFactory("el")
+		assert.NotNil(t, elFactory, "EL expression factory is not registered")
+	})
+
+	t.Run("InvokerComponents", func(t *testing.T) {
+		assert.NotNil(t, config.serviceInvokerManager, "Service invoker manager is not initialized")
+		assert.NotNil(t, config.scriptInvokerManager, "Script invoker manager is not initialized")
+
+		localInvoker := config.serviceInvokerManager.ServiceInvoker("local")
+		assert.NotNil(t, localInvoker, "Local service invoker is not registered")
+	})
+
+	t.Run("OtherCoreComponents", func(t *testing.T) {
+		assert.NotNil(t, config.statusDecisionStrategy, "Status decision strategy is not initialized")
+		assert.NotNil(t, config.seqGenerator, "Sequence generator is not initialized")
+		assert.NotNil(t, config.componentLock, "Component lock is not initialized")
+
+		testID := config.seqGenerator.GenerateId("test-machine", "test-tenant")
+		assert.NotEmpty(t, testID, "Sequence generator failed to generate ID")
+	})
+}
diff --git a/pkg/saga/statemachine/engine/config/noop_store.go b/pkg/saga/statemachine/engine/config/noop_store.go
new file mode 100644
index 00000000..e2fc7676
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/noop_store.go
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"context"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+)
+
+// NoopStateLogStore is a no-op implementation of StateLogStore for out-of-the-box scenarios.
+// All methods perform no actual operations and return nil or zero values to ensure validation passes.
+type NoopStateLogStore struct{}
+
+func (s *NoopStateLogStore) RecordStateMachineStarted(ctx context.Context, machineInstance statelang.StateMachineInstance, pc process_ctrl.ProcessContext) error {
+	return nil
+}
+
+func (s *NoopStateLogStore) RecordStateMachineFinished(ctx context.Context, machineInstance statelang.StateMachineInstance, pc process_ctrl.ProcessContext) error {
+	return nil
+}
+
+func (s *NoopStateLogStore) RecordStateMachineRestarted(ctx context.Context, machineInstance statelang.StateMachineInstance, pc process_ctrl.ProcessContext) error {
+	return nil
+}
+
+func (s *NoopStateLogStore) RecordStateStarted(ctx context.Context, stateInstance statelang.StateInstance, pc process_ctrl.ProcessContext) error {
+	return nil
+}
+
+func (s *NoopStateLogStore) RecordStateFinished(ctx context.Context, stateInstance statelang.StateInstance, pc process_ctrl.ProcessContext) error {
+	return nil
+}
+
+func (s *NoopStateLogStore) GetStateMachineInstance(stateMachineInstanceId string) (statelang.StateMachineInstance, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLogStore) GetStateMachineInstanceByBusinessKey(businessKey string, tenantId string) (statelang.StateMachineInstance, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLogStore) GetStateMachineInstanceByParentId(parentId string) ([]statelang.StateMachineInstance, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLogStore) GetStateInstance(stateInstanceId string, stateMachineInstanceId string) (statelang.StateInstance, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLogStore) GetStateInstanceListByMachineInstanceId(stateMachineInstanceId string) ([]statelang.StateInstance, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLogStore) ClearUp(pc process_ctrl.ProcessContext) {
+	// no-op
+}
+
+type NoopStateLangStore struct{}
+
+func (s *NoopStateLangStore) GetStateMachineById(stateMachineId string) (statelang.StateMachine, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLangStore) GetLastVersionStateMachine(stateMachineName string, tenantId string) (statelang.StateMachine, error) {
+	return nil, nil
+}
+
+func (s *NoopStateLangStore) StoreStateMachine(stateMachine statelang.StateMachine) error {
+	return nil
+}
diff --git a/pkg/saga/statemachine/engine/config/store_bootstrap.go b/pkg/saga/statemachine/engine/config/store_bootstrap.go
new file mode 100644
index 00000000..16d6b259
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/store_bootstrap.go
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"database/sql"
+	"fmt"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/repo/repository"
+	dbstore "seata.apache.org/seata-go/pkg/saga/statemachine/store/db"
+	sagaTm "seata.apache.org/seata-go/pkg/saga/tm"
+)
+
+// SetupStoresFromConfig wires DB-backed StateLogStore/StateLangStore and Saga TM template
+// according to runtime options loaded into DefaultStateMachineConfig.
+// It keeps Go style (no DI/SPI), and is safe to call multiple times.
+func (c *DefaultStateMachineConfig) SetupStoresFromConfig() error {
+	if !c.storeEnabled {
+		// keep Noop stores for in-memory usage
+		return nil
+	}
+	if c.storeType == "" || c.storeDSN == "" {
+		return fmt.Errorf("store_enabled=true but store_type/dsn not provided")
+	}
+
+	driver := c.storeType
+	if driver == "sqlite" || driver == "sqlite3" {
+		driver = "sqlite3"
+	}
+
+	db, err := sql.Open(driver, c.storeDSN)
+	if err != nil {
+		return err
+	}
+	if err := db.Ping(); err != nil {
+		return fmt.Errorf("db ping failed: %w", err)
+	}
+
+	// build stores with default table prefix `seata_`
+	lang := dbstore.NewStateLangStore(db, "seata_")
+	logStore := dbstore.NewStateLogStore(db, "seata_")
+
+	// inject transactional template only when tc is enabled
+	if c.tcEnabled {
+		// keep minimal default template; client init is handled externally by user
+		var tmpl sagaTm.SagaTransactionalTemplate = &sagaTm.DefaultSagaTransactionalTemplate{}
+		logStore.SetSagaTransactionalTemplate(tmpl)
+	}
+
+	// set into config & repository
+	c.SetStateLangStore(lang)
+	c.SetStateLogStore(logStore)
+	repository.GetStateMachineRepositoryImpl().SetStateLangStore(lang)
+
+	return nil
+}
diff --git a/pkg/saga/statemachine/engine/config/testdata/invalid.json b/pkg/saga/statemachine/engine/config/testdata/invalid.json
new file mode 100644
index 00000000..7f171d97
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/invalid.json
@@ -0,0 +1,3 @@
+{
+  "name": "John",
+  "age": 30,
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/invalid.yaml b/pkg/saga/statemachine/engine/config/testdata/invalid.yaml
new file mode 100644
index 00000000..872937fa
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/invalid.yaml
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+parent:
+  child1: value1
+  child2: value2
+    child3: value3
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/order_saga.json b/pkg/saga/statemachine/engine/config/testdata/order_saga.json
new file mode 100644
index 00000000..6c4eb4c8
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/order_saga.json
@@ -0,0 +1,274 @@
+{
+  "Name": "OrderSaga",
+  "Version": "1.0",
+  "StartState": "CreateOrder",
+  "trans_operation_timeout": 30000,
+  "States": {
+    "CreateOrder": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "orderService",
+      "ServiceMethod": "createOrder",
+      "CompensateState": "CancelOrder",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "OrderCreationException",
+            "InventoryUnavailableException"
+          ],
+          "IntervalSeconds": 2,
+          "MaxAttempts": 3,
+          "BackoffRate": 1.5
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "OrderCreationException",
+            "InventoryUnavailableException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'SUCCESS'": "SUCCEEDED",
+        "return.code == 'FAIL'": "FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderInfo": "$.orderInfo"
+        }
+      ],
+      "Output": {
+        "orderId": "$.#root"
+      },
+      "Next": "CheckStock",
+      "Loop": {
+        "Parallel": 1,
+        "Collection": "$.orderItems",
+        "ElementVariableName": "item",
+        "ElementIndexName": "index",
+        "CompletionCondition": "[nrOfInstances] == [nrOfCompletedInstances]"
+      }
+    },
+    "CheckStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "checkAvailability",
+      "CompensateState": "RollbackStock",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "StockCheckException"
+          ],
+          "IntervalSeconds": 2,
+          "MaxAttempts": 2,
+          "BackoffRate": 1.2
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "StockCheckException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.available == true": "IN_STOCK",
+        "return.available == false": "OUT_OF_STOCK",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "itemsList": "$.orderItems"
+        }
+      ],
+      "Output": {
+        "stockAvailable": "$.#root"
+      },
+      "Next": "DecideStock"
+    },
+    "DecideStock": {
+      "Type": "Choice",
+      "Choices": [
+        {
+          "Expression": "stockAvailable == true",
+          "Next": "ReserveStock"
+        },
+        {
+          "Expression": "stockAvailable == false",
+          "Next": "CancelOrder"
+        }
+      ],
+      "Default": "ErrorHandler"
+    },
+    "ReserveStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "reserveItems",
+      "CompensateState": "RollbackStock",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "StockReservationException"
+          ],
+          "IntervalSeconds": 2,
+          "MaxAttempts": 2,
+          "BackoffRate": 1.2
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "StockReservationException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'RESERVED'": "STOCK_RESERVED",
+        "return.code == 'FAILED'": "FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "itemList": "$.orderItems"
+        }
+      ],
+      "Output": {
+        "stockReservationId": "$.#root"
+      },
+      "Next": "ProcessPayment"
+    },
+    "ProcessPayment": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "paymentService",
+      "ServiceMethod": "processPayment",
+      "CompensateState": "RefundPayment",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "PaymentProcessingException"
+          ],
+          "IntervalSeconds": 3,
+          "MaxAttempts": 3,
+          "BackoffRate": 1.5
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "PaymentProcessingException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'PAID'": "PAYMENT_SUCCESS",
+        "return.code == 'DECLINED'": "PAYMENT_FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "amount": "$.orderTotal"
+        }
+      ],
+      "Output": {
+        "paymentTransactionId": "$.#root"
+      },
+      "Next": "CompleteOrder"
+    },
+    "CompleteOrder": {
+      "Type": "Succeed"
+    },
+    "CancelOrder": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "orderService",
+      "ServiceMethod": "cancelOrder",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        }
+      ],
+      "Output": {
+        "cancelResult": "$.#root"
+      },
+      "Next": "RollbackStock"
+    },
+    "RollbackStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "releaseItems",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "stockReservationId": "$.stockReservationId"
+        }
+      ],
+      "Output": {
+        "rollbackResult": "$.#root"
+      },
+      "Next": "RefundPayment"
+    },
+    "RefundPayment": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "paymentService",
+      "ServiceMethod": "refundPayment",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "paymentTransactionId": "$.paymentTransactionId"
+        }
+      ],
+      "Output": {
+        "refundResult": "$.#root"
+      },
+      "Next": "FailState"
+    },
+    "ErrorHandler": {
+      "Type": "Fail",
+      "ErrorCode": "ORDER_PROCESSING_ERROR",
+      "Message": "An unrecoverable error occurred during order processing."
+    },
+    "FailState": {
+      "Type": "Fail",
+      "ErrorCode": "ORDER_CANCELLED",
+      "Message": "The order has been cancelled and compensation actions have been completed."
+    }
+  }
+}
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/order_saga.yaml b/pkg/saga/statemachine/engine/config/testdata/order_saga.yaml
new file mode 100644
index 00000000..6f29ec6d
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/order_saga.yaml
@@ -0,0 +1,204 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+Name: "OrderSaga"
+Version: "1.0"
+StartState: "CreateOrder"
+trans_operation_timeout: 30000
+States:
+  CreateOrder:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "orderService"
+    ServiceMethod: "createOrder"
+    CompensateState: "CancelOrder"
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - "OrderCreationException"
+          - "InventoryUnavailableException"
+        IntervalSeconds: 2
+        MaxAttempts: 3
+        BackoffRate: 1.5
+    Catches:
+      - Exceptions:
+          - "OrderCreationException"
+          - "InventoryUnavailableException"
+        Next: "ErrorHandler"
+    Status:
+      "return.code == 'SUCCESS'": "SUCCEEDED"
+      "return.code == 'FAIL'": "FAILED"
+      "$exception{*}": "UNKNOWN"
+    Input:
+      - orderInfo: "$.orderInfo"
+    Output:
+      orderId: "$.#root"
+    Next: "CheckStock"
+    Loop:
+      Parallel: 1
+      Collection: "$.orderItems"
+      ElementVariableName: "item"
+      ElementIndexName: "index"
+      CompletionCondition: "[nrOfInstances] == [nrOfCompletedInstances]"
+
+  CheckStock:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "inventoryService"
+    ServiceMethod: "checkAvailability"
+    CompensateState: "RollbackStock"
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - "StockCheckException"
+        IntervalSeconds: 2
+        MaxAttempts: 2
+        BackoffRate: 1.2
+    Catches:
+      - Exceptions:
+          - "StockCheckException"
+        Next: "ErrorHandler"
+    Status:
+      "return.available == true": "IN_STOCK"
+      "return.available == false": "OUT_OF_STOCK"
+      "$exception{*}": "UNKNOWN"
+    Input:
+      - orderId: "$.orderId"
+      - itemsList: "$.orderItems"
+    Output:
+      stockAvailable: "$.#root"
+    Next: "DecideStock"
+
+  DecideStock:
+    Type: "Choice"
+    Choices:
+      - Expression: "stockAvailable == true"
+        Next: "ReserveStock"
+      - Expression: "stockAvailable == false"
+        Next: "CancelOrder"
+    Default: "ErrorHandler"
+
+  ReserveStock:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "inventoryService"
+    ServiceMethod: "reserveItems"
+    CompensateState: "RollbackStock"
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - "StockReservationException"
+        IntervalSeconds: 2
+        MaxAttempts: 2
+        BackoffRate: 1.2
+    Catches:
+      - Exceptions:
+          - "StockReservationException"
+        Next: "ErrorHandler"
+    Status:
+      "return.code == 'RESERVED'": "STOCK_RESERVED"
+      "return.code == 'FAILED'": "FAILED"
+      "$exception{*}": "UNKNOWN"
+    Input:
+      - orderId: "$.orderId"
+      - itemList: "$.orderItems"
+    Output:
+      stockReservationId: "$.#root"
+    Next: "ProcessPayment"
+
+  ProcessPayment:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "paymentService"
+    ServiceMethod: "processPayment"
+    CompensateState: "RefundPayment"
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - "PaymentProcessingException"
+        IntervalSeconds: 3
+        MaxAttempts: 3
+        BackoffRate: 1.5
+    Catches:
+      - Exceptions:
+          - "PaymentProcessingException"
+        Next: "ErrorHandler"
+    Status:
+      "return.code == 'PAID'": "PAYMENT_SUCCESS"
+      "return.code == 'DECLINED'": "PAYMENT_FAILED"
+      "$exception{*}": "UNKNOWN"
+    Input:
+      - orderId: "$.orderId"
+      - amount: "$.orderTotal"
+    Output:
+      paymentTransactionId: "$.#root"
+    Next: "CompleteOrder"
+
+  CompleteOrder:
+    Type: "Succeed"
+
+  CancelOrder:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "orderService"
+    ServiceMethod: "cancelOrder"
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: "$.orderId"
+    Output:
+      cancelResult: "$.#root"
+    Next: "RollbackStock"
+
+  RollbackStock:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "inventoryService"
+    ServiceMethod: "releaseItems"
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: "$.orderId"
+      - stockReservationId: "$.stockReservationId"
+    Output:
+      rollbackResult: "$.#root"
+    Next: "RefundPayment"
+
+  RefundPayment:
+    Type: "ServiceTask"
+    ServiceType: "local"
+    ServiceName: "paymentService"
+    ServiceMethod: "refundPayment"  
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: "$.orderId"
+      - paymentTransactionId: "$.paymentTransactionId"
+    Output:
+      refundResult: "$.#root"
+    Next: "FailState"
+
+  ErrorHandler:
+    Type: "Fail"
+    ErrorCode: "ORDER_PROCESSING_ERROR"
+    Message: "An unrecoverable error occurred during order processing."
+
+  FailState:
+    Type: "Fail"
+    ErrorCode: "ORDER_CANCELLED"
+    Message: "The order has been cancelled and compensation actions have been completed."
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.json b/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.json
new file mode 100644
index 00000000..e6a3dd07
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.json
@@ -0,0 +1,322 @@
+{
+  "Name": "OrderSaga",
+  "Version": "2.0",
+  "StartState": "ValidateOrder",
+  "trans_operation_timeout": 45000,
+  "States": {
+    "ValidateOrder": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "validationService",
+      "ServiceMethod": "validateOrderParams",
+      "CompensateState": "SkipValidation",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Catches": [
+        {
+          "Exceptions": [
+            "InvalidOrderParamsException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.valid == true": "VALID",
+        "return.valid == false": "INVALID",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderInfo": "$.orderInfo"
+        }
+      ],
+      "Output": {
+        "validationResult": "$.#root"
+      },
+      "Next": "CreateOrder"
+    },
+    "CreateOrder": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "orderService",
+      "ServiceMethod": "createOrder",
+      "CompensateState": "CancelOrder",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "OrderCreationException",
+            "InventoryUnavailableException"
+          ],
+          "IntervalSeconds": 3,
+          "MaxAttempts": 4,
+          "BackoffRate": 1.5
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "OrderCreationException",
+            "InventoryUnavailableException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'SUCCESS'": "SUCCEEDED",
+        "return.code == 'FAIL'": "FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderInfo": "$.orderInfo"
+        }
+      ],
+      "Output": {
+        "orderId": "$.#root"
+      },
+      "Next": "CheckStock",
+      "Loop": {
+        "Parallel": 1,
+        "Collection": "$.orderItems",
+        "ElementVariableName": "item",
+        "ElementIndexName": "index",
+        "CompletionCondition": "[nrOfInstances] == [nrOfCompletedInstances]"
+      }
+    },
+    "CheckStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "checkAvailability",
+      "CompensateState": "RollbackStock",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "StockCheckException"
+          ],
+          "IntervalSeconds": 2,
+          "MaxAttempts": 2,
+          "BackoffRate": 1.2
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "StockCheckException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.available == true": "IN_STOCK",
+        "return.available == false": "OUT_OF_STOCK",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "itemsList": "$.orderItems"
+        }
+      ],
+      "Output": {
+        "stockAvailable": "$.#root"
+      },
+      "Next": "DecideStock"
+    },
+    "DecideStock": {
+      "Type": "Choice",
+      "Choices": [
+        {
+          "Expression": "stockAvailable == true",
+          "Next": "ReserveStock"
+        },
+        {
+          "Expression": "stockAvailable == false",
+          "Next": "CancelOrder"
+        }
+      ],
+      "Default": "ErrorHandler"
+    },
+    "ReserveStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "reserveItems",
+      "CompensateState": "RollbackStock",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "StockReservationException"
+          ],
+          "IntervalSeconds": 2,
+          "MaxAttempts": 2,
+          "BackoffRate": 1.2
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "StockReservationException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'RESERVED'": "STOCK_RESERVED",
+        "return.code == 'FAILED'": "FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "itemList": "$.orderItems"
+        }
+      ],
+      "Output": {
+        "stockReservationId": "$.#root"
+      },
+      "Next": "ProcessPayment"
+    },
+    "ProcessPayment": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "paymentService",
+      "ServiceMethod": "processPayment",
+      "CompensateState": "RefundPayment",
+      "ForCompensation": false,
+      "ForUpdate": false,
+      "Retry": [
+        {
+          "Exceptions": [
+            "PaymentProcessingException"
+          ],
+          "IntervalSeconds": 3,
+          "MaxAttempts": 3,
+          "BackoffRate": 1.5
+        }
+      ],
+      "Catches": [
+        {
+          "Exceptions": [
+            "PaymentProcessingException"
+          ],
+          "Next": "ErrorHandler"
+        }
+      ],
+      "Status": {
+        "return.code == 'PAID'": "PAYMENT_SUCCESS",
+        "return.code == 'DECLINED'": "PAYMENT_FAILED",
+        "$exception{*}": "UNKNOWN"
+      },
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "amount": "$.orderTotal"
+        }
+      ],
+      "Output": {
+        "paymentTransactionId": "$.#root"
+      },
+      "Next": "CompleteOrder"
+    },
+    "CompleteOrder": {
+      "Type": "Succeed"
+    },
+    "CancelOrder": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "orderService",
+      "ServiceMethod": "cancelOrder",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        }
+      ],
+      "Output": {
+        "cancelResult": "$.#root"
+      },
+      "Next": "RollbackStock"
+    },
+    "RollbackStock": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "inventoryService",
+      "ServiceMethod": "releaseItems",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "stockReservationId": "$.stockReservationId"
+        }
+      ],
+      "Output": {
+        "rollbackResult": "$.#root"
+      },
+      "Next": "RefundPayment"
+    },
+    "RefundPayment": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "paymentService",
+      "ServiceMethod": "refundPayment",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        },
+        {
+          "paymentTransactionId": "$.paymentTransactionId"
+        }
+      ],
+      "Output": {
+        "refundResult": "$.#root"
+      },
+      "Next": "FailState"
+    },
+    "ErrorHandler": {
+      "Type": "Fail",
+      "ErrorCode": "ORDER_PROCESSING_ERROR_V2",
+      "Message": "v2版本:订单处理发生不可恢复错误"
+    },
+    "FailState": {
+      "Type": "Fail",
+      "ErrorCode": "ORDER_CANCELLED",
+      "Message": "The order has been cancelled and compensation actions have been completed."
+    },
+    "SkipValidation": {
+      "Type": "ServiceTask",
+      "ServiceType": "local",
+      "ServiceName": "validationService",
+      "ServiceMethod": "skipValidation",
+      "ForCompensation": true,
+      "ForUpdate": true,
+      "Input": [
+        {
+          "orderId": "$.orderId"
+        }
+      ],
+      "Output": {
+        "skipResult": "Validation compensation skipped"
+      },
+      "Next": "CancelOrder"
+    }
+  }
+}
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.yaml b/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.yaml
new file mode 100644
index 00000000..7ce7bc01
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/order_saga_v2.yaml
@@ -0,0 +1,228 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Name: OrderSaga
+Version: "2.0"
+StartState: ValidateOrder
+trans_operation_timeout: 45000
+States:
+  ValidateOrder:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: validationService
+    ServiceMethod: validateOrderParams
+    CompensateState: SkipValidation
+    ForCompensation: false
+    ForUpdate: false
+    Catches:
+      - Exceptions:
+          - InvalidOrderParamsException
+        Next: ErrorHandler
+    Status:
+      return.valid == true: VALID
+      return.valid == false: INVALID
+      $exception{*}: UNKNOWN
+    Input:
+      - orderInfo: $.orderInfo
+    Output:
+      validationResult: "$.#root"
+    Next: CreateOrder
+  CreateOrder:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: orderService
+    ServiceMethod: createOrder
+    CompensateState: CancelOrder
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - OrderCreationException
+          - InventoryUnavailableException
+        IntervalSeconds: 3
+        MaxAttempts: 4
+        BackoffRate: 1.5
+    Catches:
+      - Exceptions:
+          - OrderCreationException
+          - InventoryUnavailableException
+        Next: ErrorHandler
+    Status:
+      return.code == 'SUCCESS': SUCCEEDED
+      return.code == 'FAIL': FAILED
+      $exception{*}: UNKNOWN
+    Input:
+      - orderInfo: $.orderInfo
+    Output:
+      orderId: "$.#root"
+    Next: CheckStock
+    Loop:
+      Parallel: 1
+      Collection: $.orderItems
+      ElementVariableName: item
+      ElementIndexName: index
+      CompletionCondition: "[nrOfInstances] == [nrOfCompletedInstances]"
+  CheckStock:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: inventoryService
+    ServiceMethod: checkAvailability
+    CompensateState: RollbackStock
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - StockCheckException
+        IntervalSeconds: 2
+        MaxAttempts: 2
+        BackoffRate: 1.2
+    Catches:
+      - Exceptions:
+          - StockCheckException
+        Next: ErrorHandler
+    Status:
+      return.available == true: IN_STOCK
+      return.available == false: OUT_OF_STOCK
+      $exception{*}: UNKNOWN
+    Input:
+      - orderId: $.orderId
+      - itemsList: $.orderItems
+    Output:
+      stockAvailable: "$.#root"
+    Next: DecideStock
+  DecideStock:
+    Type: Choice
+    Choices:
+      - Expression: stockAvailable == true
+        Next: ReserveStock
+      - Expression: stockAvailable == false
+        Next: CancelOrder
+    Default: ErrorHandler
+  ReserveStock:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: inventoryService
+    ServiceMethod: reserveItems
+    CompensateState: RollbackStock
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - StockReservationException
+        IntervalSeconds: 2
+        MaxAttempts: 2
+        BackoffRate: 1.2
+    Catches:
+      - Exceptions:
+          - StockReservationException
+        Next: ErrorHandler
+    Status:
+      return.code == 'RESERVED': STOCK_RESERVED
+      return.code == 'FAILED': FAILED
+      $exception{*}: UNKNOWN
+    Input:
+      - orderId: $.orderId
+      - itemList: $.orderItems
+    Output:
+      stockReservationId: "$.#root"
+    Next: ProcessPayment
+  ProcessPayment:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: paymentService
+    ServiceMethod: processPayment
+    CompensateState: RefundPayment
+    ForCompensation: false
+    ForUpdate: false
+    Retry:
+      - Exceptions:
+          - PaymentProcessingException
+        IntervalSeconds: 3
+        MaxAttempts: 3
+        BackoffRate: 1.5
+    Catches:
+      - Exceptions:
+          - PaymentProcessingException
+        Next: ErrorHandler
+    Status:
+      return.code == 'PAID': PAYMENT_SUCCESS
+      return.code == 'DECLINED': PAYMENT_FAILED
+      $exception{*}: UNKNOWN
+    Input:
+      - orderId: $.orderId
+      - amount: $.orderTotal
+    Output:
+      paymentTransactionId: "$.#root"
+    Next: CompleteOrder
+  CompleteOrder:
+    Type: Succeed
+  CancelOrder:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: orderService
+    ServiceMethod: cancelOrder
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: $.orderId
+    Output:
+      cancelResult: "$.#root"
+    Next: RollbackStock
+  RollbackStock:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: inventoryService
+    ServiceMethod: releaseItems
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: $.orderId
+      - stockReservationId: $.stockReservationId
+    Output:
+      rollbackResult: "$.#root"
+    Next: RefundPayment
+  RefundPayment:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: paymentService
+    ServiceMethod: refundPayment
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: $.orderId
+      - paymentTransactionId: $.paymentTransactionId
+    Output:
+      refundResult: "$.#root"
+    Next: FailState
+  ErrorHandler:
+    Type: Fail
+    ErrorCode: ORDER_PROCESSING_ERROR_V2
+    Message: v2版本:订单处理发生不可恢复错误
+  FailState:
+    Type: Fail
+    ErrorCode: ORDER_CANCELLED
+    Message: The order has been cancelled and compensation actions have been completed.
+  SkipValidation:
+    Type: ServiceTask
+    ServiceType: local
+    ServiceName: validationService
+    ServiceMethod: skipValidation
+    ForCompensation: true
+    ForUpdate: true
+    Input:
+      - orderId: $.orderId
+    Output:
+      skipResult: Validation compensation skipped
+    Next: CancelOrder
diff --git a/pkg/saga/statemachine/engine/config/testdata/saga_config.json b/pkg/saga/statemachine/engine/config/testdata/saga_config.json
new file mode 100644
index 00000000..e87a3eb6
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/saga_config.json
@@ -0,0 +1,13 @@
+{
+  "trans_operation_timeout": 30000,
+  "service_invoke_timeout": 30000,
+  "charset": "UTF-8",
+  "default_tenant_id": "tenant_1",
+  "saga_retry_persist_mode_update": true,
+  "saga_compensate_persist_mode_update": true,
+  "saga_branch_register_enable": true,
+  "rm_report_success_enable": true,
+  "state_machine_resources": [
+    "testdata/order_saga.json"
+  ]
+}
diff --git a/pkg/saga/statemachine/engine/config/testdata/saga_config.yaml b/pkg/saga/statemachine/engine/config/testdata/saga_config.yaml
new file mode 100644
index 00000000..a11ed4f6
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/saga_config.yaml
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trans_operation_timeout: 30000
+service_invoke_timeout: 30000
+charset: "UTF-8"
+default_tenant_id: "tenant_1"
+saga_retry_persist_mode_update: true
+saga_compensate_persist_mode_update: true
+saga_branch_register_enable: true
+rm_report_success_enable: true
+state_machine_resources:
+  - "testdata/order_saga.json"  
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.json b/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.json
new file mode 100644
index 00000000..5a5b2dd5
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.json
@@ -0,0 +1,13 @@
+{
+  "trans_operation_timeout": 30000,
+  "service_invoke_timeout": 30000,
+  "charset": "UTF-8",
+  "default_tenant_id": "tenant_1",  
+  "saga_retry_persist_mode_update": true,
+  "saga_compensate_persist_mode_update": true,
+  "saga_branch_register_enable": true,
+  "rm_report_success_enable": true,
+  "state_machine_resources": [
+    "testdata/order_saga_v2.json"
+  ]
+}
\ No newline at end of file
diff --git a/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.yaml b/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.yaml
new file mode 100644
index 00000000..4288389a
--- /dev/null
+++ b/pkg/saga/statemachine/engine/config/testdata/saga_config_v2.yaml
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+trans_operation_timeout: 30000
+service_invoke_timeout: 30000
+charset: UTF-8
+default_tenant_id: tenant_1
+saga_retry_persist_mode_update: true
+saga_compensate_persist_mode_update: true
+saga_branch_register_enable: true
+rm_report_success_enable: true
+state_machine_resources:
+  - testdata/order_saga_v2.json
diff --git a/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine.go b/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine.go
new file mode 100644
index 00000000..6fc81f08
--- /dev/null
+++ b/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine.go
@@ -0,0 +1,747 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package core
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"seata.apache.org/seata-go/pkg/saga/runtime"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/config"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/exception"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/pcext"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/utils"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl/process"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	tmctx "seata.apache.org/seata-go/pkg/tm"
+	seataErrors "seata.apache.org/seata-go/pkg/util/errors"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+type ProcessCtrlStateMachineEngine struct {
+	StateMachineConfig engine.StateMachineConfig
+}
+
+func NewProcessCtrlStateMachineEngine() (*ProcessCtrlStateMachineEngine, error) {
+	cfg, err := config.NewDefaultStateMachineConfig()
+
+	if err != nil {
+		return nil, fmt.Errorf("failed to create state machine configuration: %w", err)
+	}
+
+	engine := &ProcessCtrlStateMachineEngine{
+		StateMachineConfig: cfg,
+	}
+
+	runtime.SetEngine(engine)
+
+	return engine, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) Start(ctx context.Context, stateMachineName string, tenantId string,
+	startParams map[string]interface{}) (statelang.StateMachineInstance, error) {
+	return p.startInternal(ctx, stateMachineName, tenantId, "", startParams, false, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) StartAsync(ctx context.Context, stateMachineName string, tenantId string,
+	startParams map[string]interface{}, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	return p.startInternal(ctx, stateMachineName, tenantId, "", startParams, true, callback)
+}
+
+func (p ProcessCtrlStateMachineEngine) StartWithBusinessKey(ctx context.Context, stateMachineName string,
+	tenantId string, businessKey string, startParams map[string]interface{}) (statelang.StateMachineInstance, error) {
+	return p.startInternal(ctx, stateMachineName, tenantId, businessKey, startParams, false, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) StartWithBusinessKeyAsync(ctx context.Context, stateMachineName string,
+	tenantId string, businessKey string, startParams map[string]interface{}, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	return p.startInternal(ctx, stateMachineName, tenantId, businessKey, startParams, true, callback)
+}
+
+func (p ProcessCtrlStateMachineEngine) Forward(ctx context.Context, stateMachineInstId string,
+	replaceParams map[string]interface{}) (statelang.StateMachineInstance, error) {
+	return p.forwardInternal(ctx, stateMachineInstId, replaceParams, false, false, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) ForwardAsync(ctx context.Context, stateMachineInstId string, replaceParams map[string]interface{}, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	return p.forwardInternal(ctx, stateMachineInstId, replaceParams, false, true, callback)
+}
+
+func (p ProcessCtrlStateMachineEngine) Compensate(ctx context.Context, stateMachineInstId string,
+	replaceParams map[string]any) (statelang.StateMachineInstance, error) {
+	return p.compensateInternal(ctx, stateMachineInstId, replaceParams, false, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) CompensateAsync(ctx context.Context, stateMachineInstId string, replaceParams map[string]interface{}, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	return p.compensateInternal(ctx, stateMachineInstId, replaceParams, true, callback)
+}
+
+func (p ProcessCtrlStateMachineEngine) SkipAndForward(ctx context.Context, stateMachineInstId string, replaceParams map[string]interface{}) (statelang.StateMachineInstance, error) {
+	return p.forwardInternal(ctx, stateMachineInstId, replaceParams, true, false, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) SkipAndForwardAsync(ctx context.Context, stateMachineInstId string, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	return p.forwardInternal(ctx, stateMachineInstId, nil, true, true, callback)
+}
+
+func (p ProcessCtrlStateMachineEngine) GetStateMachineConfig() engine.StateMachineConfig {
+	return p.StateMachineConfig
+}
+
+func (p ProcessCtrlStateMachineEngine) ReloadStateMachineInstance(ctx context.Context, instId string) (statelang.StateMachineInstance, error) {
+	inst, err := p.StateMachineConfig.StateLogStore().GetStateMachineInstance(instId)
+	if err != nil {
+		return nil, err
+	}
+	if inst != nil {
+		stateMachine := inst.StateMachine()
+		if stateMachine == nil {
+			stateMachine, err = p.StateMachineConfig.StateMachineRepository().GetStateMachineById(inst.MachineID())
+			if err != nil {
+				return nil, err
+			}
+			inst.SetStateMachine(stateMachine)
+		}
+		if stateMachine == nil {
+			return nil, exception.NewEngineExecutionException(seataErrors.ObjectNotExists,
+				"StateMachine[id:"+inst.MachineID()+"] not exist.", nil)
+		}
+
+		stateList := inst.StateList()
+		if len(stateList) == 0 {
+			stateList, err = p.StateMachineConfig.StateLogStore().GetStateInstanceListByMachineInstanceId(instId)
+			if err != nil {
+				return nil, err
+			}
+			if len(stateList) > 0 {
+				for _, tmpStateInstance := range stateList {
+					inst.PutState(tmpStateInstance.ID(), tmpStateInstance)
+				}
+			}
+		}
+
+		if len(inst.EndParams()) == 0 {
+			endParams, err := p.replayContextVariables(ctx, inst)
+			if err != nil {
+				return nil, err
+			}
+			inst.SetEndParams(endParams)
+		}
+	}
+	return inst, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) startInternal(ctx context.Context, stateMachineName string, tenantId string,
+	businessKey string, startParams map[string]interface{}, async bool, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	if !tmctx.IsSeataContext(ctx) {
+		ctx = tmctx.InitSeataContext(ctx)
+	}
+
+	if async && !p.StateMachineConfig.EnableAsync() {
+		return nil, exception.NewEngineExecutionException(seataErrors.AsynchronousStartDisabled,
+			"asynchronous start is disabled by configuration (enable_async=false)", nil)
+	}
+
+	if tenantId == "" {
+		tenantId = p.StateMachineConfig.GetDefaultTenantId()
+	}
+
+	stateMachineInstance, err := p.createMachineInstance(stateMachineName, tenantId, businessKey, startParams)
+	if err != nil {
+		return nil, err
+	}
+
+	// Build the process_ctrl context.
+	processContextBuilder := utils.NewProcessContextBuilder().
+		WithProcessType(process.StateLang).
+		WithOperationName(constant.OperationNameStart).
+		WithAsyncCallback(callback).
+		WithInstruction(pcext.NewStateInstruction(stateMachineName, tenantId)).
+		WithStateMachineInstance(stateMachineInstance).
+		WithStateMachineConfig(p.StateMachineConfig).
+		WithStateMachineEngine(p).
+		WithIsAsyncExecution(async)
+
+	contextMap := p.copyMap(startParams)
+
+	stateMachineInstance.SetContext(contextMap)
+
+	processContext := processContextBuilder.WithStateMachineContextVariables(contextMap).Build()
+
+	if stateMachineInstance.StateMachine().IsPersist() && p.StateMachineConfig.StateLogStore() != nil {
+		err := p.StateMachineConfig.StateLogStore().RecordStateMachineStarted(ctx, stateMachineInstance, processContext)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	if stateMachineInstance.ID() == "" {
+		stateMachineInstance.SetID(p.StateMachineConfig.SeqGenerator().GenerateId(constant.SeqEntityStateMachineInst, ""))
+	}
+
+	var eventPublisher process_ctrl.EventPublisher
+	if async {
+		eventPublisher = p.StateMachineConfig.AsyncEventPublisher()
+	} else {
+		eventPublisher = p.StateMachineConfig.EventPublisher()
+	}
+
+	_, err = eventPublisher.PushEvent(ctx, processContext)
+	if err != nil {
+		return nil, err
+	}
+
+	return stateMachineInstance, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) forwardInternal(ctx context.Context, stateMachineInstId string,
+	replaceParams map[string]interface{}, skip bool, async bool, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	stateMachineInstance, err := p.reloadStateMachineInstance(ctx, stateMachineInstId)
+	if err != nil {
+		return nil, err
+	}
+
+	if stateMachineInstance == nil {
+		return nil, exception.NewEngineExecutionException(seataErrors.StateMachineInstanceNotExists, "StateMachineInstance is not exists", nil)
+	}
+
+	if stateMachineInstance.Status() == statelang.SU && stateMachineInstance.CompensationStatus() == "" {
+		return stateMachineInstance, nil
+	}
+
+	acceptStatus := []statelang.ExecutionStatus{statelang.FA, statelang.UN, statelang.RU}
+	if _, err := p.checkStatus(ctx, stateMachineInstance, acceptStatus, nil, stateMachineInstance.Status(), "", "forward"); err != nil {
+		return nil, err
+	}
+
+	actList := stateMachineInstance.StateList()
+	if len(actList) == 0 {
+		return nil, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+			fmt.Sprintf("StateMachineInstance[id:%s] has no stateInstance, please start a new StateMachine execution instead", stateMachineInstId), nil)
+	}
+
+	lastForwardState, err := p.findOutLastForwardStateInstance(actList)
+	if err != nil {
+		return nil, err
+	}
+	if lastForwardState == nil {
+		return nil, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+			fmt.Sprintf("StateMachineInstance[id:%s] Cannot find last forward execution stateInstance", stateMachineInstId), nil)
+	}
+
+	contextBuilder := utils.NewProcessContextBuilder().
+		WithProcessType(process.StateLang).
+		WithOperationName(constant.OperationNameForward).
+		WithAsyncCallback(callback).
+		WithStateMachineInstance(stateMachineInstance).
+		WithStateInstance(lastForwardState).
+		WithStateMachineConfig(p.StateMachineConfig).
+		WithStateMachineEngine(p).
+		WithIsAsyncExecution(async)
+
+	context := contextBuilder.Build()
+
+	contextVariables, err := p.getStateMachineContextVariables(ctx, stateMachineInstance)
+	if err != nil {
+		return nil, err
+	}
+
+	if replaceParams != nil {
+		for k, v := range replaceParams {
+			contextVariables[k] = v
+		}
+	}
+	p.putBusinesskeyToContextariables(stateMachineInstance, contextVariables)
+
+	concurrentContextVariables := p.copyMap(contextVariables)
+
+	context.SetVariable(constant.VarNameStateMachineContext, concurrentContextVariables)
+	stateMachineInstance.SetContext(concurrentContextVariables)
+
+	originStateName := pcext.GetOriginStateName(lastForwardState)
+	lastState := stateMachineInstance.StateMachine().State(originStateName)
+	loop := pcext.GetLoopConfig(ctx, context, lastState)
+	if loop != nil && lastForwardState.Status() == statelang.SU {
+		lastForwardState = p.findOutLastNeedForwardStateInstance(ctx, context)
+	}
+
+	context.SetVariable(lastForwardState.Name()+constant.VarNameRetriedStateInstId, lastForwardState.ID())
+	if lastForwardState.Type() == constant.StateTypeSubStateMachine && lastForwardState.CompensationStatus() != statelang.SU {
+		context.SetVariable(constant.VarNameIsForSubStatMachineForward, true)
+	}
+
+	if lastForwardState.Status() != statelang.SU {
+		lastForwardState.SetIgnoreStatus(true)
+	}
+
+	inst := pcext.NewStateInstruction(stateMachineInstance.StateMachine().Name(), stateMachineInstance.TenantID())
+	if skip || lastForwardState.Status() == statelang.SU {
+		next := ""
+		curState := stateMachineInstance.StateMachine().State(pcext.GetOriginStateName(lastForwardState))
+		if taskState, ok := curState.(*state.AbstractTaskState); ok {
+			next = taskState.Next()
+		}
+		if next == "" {
+			log.Warn(fmt.Sprintf("Last Forward execution StateInstance was succeed, and it has not Next State, skip forward operation"))
+			return stateMachineInstance, nil
+		}
+		inst.SetStateName(next)
+	} else {
+		if lastForwardState.Status() == statelang.RU && !pcext.IsTimeout(lastForwardState.StartedTime(), p.StateMachineConfig.GetServiceInvokeTimeout()) {
+			return nil, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+				fmt.Sprintf("State [%s] is running, operation[forward] denied", lastForwardState.Name()), nil)
+		}
+		inst.SetStateName(pcext.GetOriginStateName(lastForwardState))
+	}
+	context.SetInstruction(inst)
+
+	stateMachineInstance.SetStatus(statelang.RU)
+	stateMachineInstance.SetRunning(true)
+
+	log.Info(fmt.Sprintf("Operation [forward] started  stateMachineInstance[id:%s]", stateMachineInstance.ID()))
+
+	if stateMachineInstance.StateMachine().IsPersist() {
+		if err := p.StateMachineConfig.StateLogStore().RecordStateMachineRestarted(ctx, stateMachineInstance, context); err != nil {
+			return nil, err
+		}
+	}
+
+	curState, err := inst.GetState(context)
+	if err != nil {
+		return nil, err
+	}
+	loop = pcext.GetLoopConfig(ctx, context, curState)
+	if loop != nil {
+		inst.SetTemporaryState(state.NewLoopStartStateImpl())
+	}
+
+	if async {
+		if _, err := p.StateMachineConfig.AsyncEventPublisher().PushEvent(ctx, context); err != nil {
+			return nil, err
+		}
+	} else {
+		if _, err := p.StateMachineConfig.EventPublisher().PushEvent(ctx, context); err != nil {
+			return nil, err
+		}
+	}
+
+	return stateMachineInstance, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) findOutLastForwardStateInstance(stateInstanceList []statelang.StateInstance) (statelang.StateInstance, error) {
+	var lastForwardStateInstance statelang.StateInstance
+	var err error
+	for i := len(stateInstanceList) - 1; i >= 0; i-- {
+		stateInstance := stateInstanceList[i]
+		if !stateInstance.IsForCompensation() {
+			if stateInstance.CompensationStatus() == statelang.SU {
+				continue
+			}
+
+			if stateInstance.Type() == constant.StateTypeSubStateMachine {
+				finalState := stateInstance
+				for finalState.StateIDRetriedFor() != "" {
+					if finalState, err = p.StateMachineConfig.StateLogStore().GetStateInstance(finalState.StateIDRetriedFor(),
+						finalState.MachineInstanceID()); err != nil {
+						return nil, err
+					}
+				}
+
+				subInst, _ := p.StateMachineConfig.StateLogStore().GetStateMachineInstanceByParentId(pcext.GenerateParentId(finalState))
+				if len(subInst) > 0 {
+					if subInst[0].CompensationStatus() == statelang.SU {
+						continue
+					}
+
+					if subInst[0].CompensationStatus() == statelang.UN {
+						return nil, exception.NewEngineExecutionException(seataErrors.ForwardInvalid,
+							"Last forward execution state instance is SubStateMachine and compensation status is [UN], Operation[forward] denied, stateInstanceId:"+stateInstance.ID(),
+							nil)
+					}
+				}
+			} else if stateInstance.CompensationStatus() == statelang.UN {
+				return nil, exception.NewEngineExecutionException(seataErrors.ForwardInvalid,
+					"Last forward execution state instance compensation status is [UN], Operation[forward] denied, stateInstanceId:"+stateInstance.ID(),
+					nil)
+			}
+
+			lastForwardStateInstance = stateInstance
+			break
+		}
+	}
+	return lastForwardStateInstance, nil
+}
+
+// copyMap not deep copy, so best practice: Don’t pass by reference
+func (p ProcessCtrlStateMachineEngine) copyMap(startParams map[string]interface{}) map[string]interface{} {
+	copyMap := make(map[string]interface{}, len(startParams))
+	for k, v := range startParams {
+		copyMap[k] = v
+	}
+	return copyMap
+}
+
+func (p ProcessCtrlStateMachineEngine) createMachineInstance(stateMachineName string, tenantId string, businessKey string, startParams map[string]interface{}) (statelang.StateMachineInstance, error) {
+	stateMachine, err := p.StateMachineConfig.StateMachineRepository().GetLastVersionStateMachine(stateMachineName, tenantId)
+	if err != nil {
+		return nil, err
+	}
+
+	if stateMachine == nil {
+		return nil, exception.NewEngineExecutionException(seataErrors.ObjectNotExists,
+			"StateMachine ["+stateMachineName+"] is not exists", nil)
+	}
+
+	stateMachineInstance := statelang.NewStateMachineInstanceImpl()
+	stateMachineInstance.SetStateMachine(stateMachine)
+	stateMachineInstance.SetTenantID(tenantId)
+	stateMachineInstance.SetBusinessKey(businessKey)
+	stateMachineInstance.SetStartParams(startParams)
+	if startParams != nil {
+		if businessKey != "" {
+			startParams[constant.VarNameBusinesskey] = businessKey
+		}
+
+		if parentRaw, exists := startParams[constant.VarNameParentId]; exists {
+			parentId, ok := parentRaw.(string)
+			if !ok {
+				return nil, fmt.Errorf("parentId must be string")
+			}
+			stateMachineInstance.SetParentID(parentId)
+			delete(startParams, constant.VarNameParentId)
+		}
+	}
+
+	stateMachineInstance.SetStatus(statelang.RU)
+	stateMachineInstance.SetRunning(true)
+
+	now := time.Now()
+	stateMachineInstance.SetStartedTime(now)
+	stateMachineInstance.SetUpdatedTime(now)
+	return stateMachineInstance, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) compensateInternal(ctx context.Context, stateMachineInstId string, replaceParams map[string]any,
+	async bool, callback engine.CallBack) (statelang.StateMachineInstance, error) {
+	stateMachineInstance, err := p.reloadStateMachineInstance(ctx, stateMachineInstId)
+	if err != nil {
+		return nil, err
+	}
+
+	if stateMachineInstance == nil {
+		return nil, exception.NewEngineExecutionException(seataErrors.StateMachineInstanceNotExists,
+			"StateMachineInstance is not exits", nil)
+	}
+
+	if statelang.SU == stateMachineInstance.CompensationStatus() {
+		return stateMachineInstance, nil
+	}
+
+	if stateMachineInstance.CompensationStatus() != "" {
+		denyStatus := make([]statelang.ExecutionStatus, 0)
+		denyStatus = append(denyStatus, statelang.SU)
+		p.checkStatus(ctx, stateMachineInstance, nil, denyStatus, "", stateMachineInstance.CompensationStatus(),
+			"compensate")
+	}
+
+	if replaceParams != nil {
+		for key, value := range replaceParams {
+			stateMachineInstance.EndParams()[key] = value
+		}
+	}
+
+	contextBuilder := utils.NewProcessContextBuilder().WithProcessType(process.StateLang).
+		WithOperationName(constant.OperationNameCompensate).WithAsyncCallback(callback).
+		WithStateMachineInstance(stateMachineInstance).
+		WithStateMachineConfig(p.StateMachineConfig).WithStateMachineEngine(p).WithIsAsyncExecution(async)
+
+	context := contextBuilder.Build()
+
+	contextVariables, err := p.getStateMachineContextVariables(ctx, stateMachineInstance)
+	if err != nil {
+		return nil, err
+	}
+
+	if replaceParams != nil {
+		for key, value := range replaceParams {
+			contextVariables[key] = value
+		}
+	}
+
+	p.putBusinesskeyToContextariables(stateMachineInstance, contextVariables)
+
+	// TODO: Here is not use sync.map, make sure whether to use it
+	concurrentContextVariables := make(map[string]any)
+	p.nullSafeCopy(contextVariables, concurrentContextVariables)
+
+	context.SetVariable(constant.VarNameStateMachineContext, concurrentContextVariables)
+	stateMachineInstance.SetContext(concurrentContextVariables)
+
+	tempCompensationTriggerState := state.NewCompensationTriggerStateImpl()
+	tempCompensationTriggerState.SetStateMachine(stateMachineInstance.StateMachine())
+
+	stateMachineInstance.SetRunning(true)
+
+	log.Info("Operation [compensate] start.  stateMachineInstance[id:" + stateMachineInstance.ID() + "]")
+
+	if stateMachineInstance.StateMachine().IsPersist() {
+		err := p.StateMachineConfig.StateLogStore().RecordStateMachineRestarted(ctx, stateMachineInstance, context)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	inst := pcext.NewStateInstruction(stateMachineInstance.TenantID(), stateMachineInstance.StateMachine().Name())
+	inst.SetTemporaryState(tempCompensationTriggerState)
+	context.SetInstruction(inst)
+
+	if async {
+		_, err := p.StateMachineConfig.AsyncEventPublisher().PushEvent(ctx, context)
+		if err != nil {
+			return nil, err
+		}
+	} else {
+		_, err := p.StateMachineConfig.EventPublisher().PushEvent(ctx, context)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return stateMachineInstance, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) reloadStateMachineInstance(ctx context.Context, instId string) (statelang.StateMachineInstance, error) {
+	instance, err := p.StateMachineConfig.StateLogStore().GetStateMachineInstance(instId)
+	if err != nil {
+		return nil, err
+	}
+	if instance != nil {
+		stateMachine := instance.StateMachine()
+		if stateMachine == nil {
+			stateMachine, err = p.StateMachineConfig.StateMachineRepository().GetStateMachineById(instance.MachineID())
+			if err != nil {
+				return nil, err
+			}
+			instance.SetStateMachine(stateMachine)
+		}
+		if stateMachine == nil {
+			return nil, exception.NewEngineExecutionException(seataErrors.ObjectNotExists,
+				"StateMachine[id:"+instance.MachineID()+"] not exist.", nil)
+		}
+
+		stateList := instance.StateList()
+		if stateList == nil || len(stateList) == 0 {
+			stateList, err = p.StateMachineConfig.StateLogStore().GetStateInstanceListByMachineInstanceId(instId)
+			if err != nil {
+				return nil, err
+			}
+			if stateList != nil && len(stateList) > 0 {
+				for _, tmpStateInstance := range stateList {
+					instance.PutState(tmpStateInstance.ID(), tmpStateInstance)
+				}
+			}
+		}
+
+		if instance.EndParams() == nil || len(instance.EndParams()) == 0 {
+			variables, err := p.replayContextVariables(ctx, instance)
+			if err != nil {
+				return nil, err
+			}
+			instance.SetEndParams(variables)
+		}
+	}
+	return instance, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) replayContextVariables(ctx context.Context, stateMachineInstance statelang.StateMachineInstance) (map[string]any, error) {
+	contextVariables := make(map[string]any)
+	if stateMachineInstance.StartParams() != nil {
+		for key, value := range stateMachineInstance.StartParams() {
+			contextVariables[key] = value
+		}
+	}
+
+	stateInstanceList := stateMachineInstance.StateList()
+	if stateInstanceList == nil || len(stateInstanceList) == 0 {
+		return contextVariables, nil
+	}
+
+	for _, stateInstance := range stateInstanceList {
+		serviceOutputParams := stateInstance.OutputParams()
+		if serviceOutputParams != nil {
+			serviceTaskStateImpl, ok := stateMachineInstance.StateMachine().State(pcext.GetOriginStateName(stateInstance)).(*state.ServiceTaskStateImpl)
+			if !ok {
+				return nil, exception.NewEngineExecutionException(seataErrors.ObjectNotExists,
+					"Cannot find State by state name ["+stateInstance.Name()+"], may be this is a bug", nil)
+			}
+
+			if serviceTaskStateImpl.Output() != nil && len(serviceTaskStateImpl.Output()) != 0 {
+				outputVariablesToContext, err := pcext.CreateOutputParams(p.StateMachineConfig,
+					p.StateMachineConfig.ExpressionResolver(), serviceTaskStateImpl.AbstractTaskState, serviceOutputParams)
+				if err != nil {
+					return nil, exception.NewEngineExecutionException(seataErrors.ObjectNotExists,
+						"Context variable replay failed", err)
+				}
+				if outputVariablesToContext != nil && len(outputVariablesToContext) != 0 {
+					for key, value := range outputVariablesToContext {
+						contextVariables[key] = value
+					}
+				}
+				if len(stateInstance.BusinessKey()) > 0 {
+					contextVariables[serviceTaskStateImpl.Name()+constant.VarNameBusinesskey] = stateInstance.BusinessKey()
+				}
+			}
+		}
+	}
+
+	return contextVariables, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) checkStatus(ctx context.Context, stateMachineInstance statelang.StateMachineInstance,
+	acceptStatus []statelang.ExecutionStatus, denyStatus []statelang.ExecutionStatus, status statelang.ExecutionStatus,
+	compenStatus statelang.ExecutionStatus, operation string) (bool, error) {
+	if status != "" && compenStatus != "" {
+		return false, exception.NewEngineExecutionException(seataErrors.InvalidParameter,
+			"status and compensationStatus are not supported at the same time", nil)
+	}
+	if status == "" && compenStatus == "" {
+		return false, exception.NewEngineExecutionException(seataErrors.InvalidParameter,
+			"status and compensationStatus must input at least one", nil)
+	}
+	if statelang.SU == compenStatus {
+		message := p.buildExceptionMessage(stateMachineInstance, nil, nil, "", statelang.SU, operation)
+		return false, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+			message, nil)
+	}
+
+	if stateMachineInstance.IsRunning() &&
+		!pcext.IsTimeout(stateMachineInstance.UpdatedTime(), p.StateMachineConfig.GetTransOperationTimeout()) {
+		return false, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+			"StateMachineInstance [id:"+stateMachineInstance.ID()+"] is running, operation["+operation+
+				"] denied", nil)
+	}
+
+	if (denyStatus == nil || len(denyStatus) == 0) && (acceptStatus == nil || len(acceptStatus) == 0) {
+		return false, exception.NewEngineExecutionException(seataErrors.InvalidParameter,
+			"StateMachineInstance[id:"+stateMachineInstance.ID()+
+				"], acceptable status and deny status must input at least one", nil)
+	}
+
+	currentStatus := compenStatus
+	if status != "" {
+		currentStatus = status
+	}
+
+	if denyStatus != nil && len(denyStatus) == 0 {
+		for _, tempDenyStatus := range denyStatus {
+			if tempDenyStatus == currentStatus {
+				message := p.buildExceptionMessage(stateMachineInstance, acceptStatus, denyStatus, status,
+					compenStatus, operation)
+				return false, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+					message, nil)
+			}
+		}
+	}
+
+	if acceptStatus == nil || len(acceptStatus) == 0 {
+		return true, nil
+	} else {
+		for _, tempStatus := range acceptStatus {
+			if tempStatus == currentStatus {
+				return true, nil
+			}
+		}
+	}
+
+	message := p.buildExceptionMessage(stateMachineInstance, acceptStatus, denyStatus, status, compenStatus,
+		operation)
+	return false, exception.NewEngineExecutionException(seataErrors.OperationDenied,
+		message, nil)
+}
+
+func (p ProcessCtrlStateMachineEngine) getStateMachineContextVariables(ctx context.Context,
+	stateMachineInstance statelang.StateMachineInstance) (map[string]any, error) {
+	contextVariables := stateMachineInstance.EndParams()
+	if contextVariables == nil || len(contextVariables) == 0 {
+		return p.replayContextVariables(ctx, stateMachineInstance)
+	}
+	return contextVariables, nil
+}
+
+func (p ProcessCtrlStateMachineEngine) buildExceptionMessage(instance statelang.StateMachineInstance,
+	acceptStatus []statelang.ExecutionStatus, denyStatus []statelang.ExecutionStatus, status statelang.ExecutionStatus,
+	compenStatus statelang.ExecutionStatus, operation string) string {
+	message := fmt.Sprintf("StateMachineInstance[id:%s]", instance.ID())
+	if len(acceptStatus) > 0 {
+		message += ",acceptable status :"
+		for _, tempStatus := range acceptStatus {
+			message += string(tempStatus) + " "
+		}
+	}
+
+	if len(denyStatus) > 0 {
+		message += ",deny status:"
+		for _, tempStatus := range denyStatus {
+			message += string(tempStatus) + " "
+		}
+	}
+
+	if status != "" {
+		message += ",current status:" + string(status)
+	}
+
+	if compenStatus != "" {
+		message += ",current compensation status:" + string(compenStatus)
+	}
+
+	message += fmt.Sprintf(",so operation [%s] denied", operation)
+	return message
+}
+
+func (p ProcessCtrlStateMachineEngine) putBusinesskeyToContextariables(instance statelang.StateMachineInstance, variables map[string]any) {
+	if instance.BusinessKey() != "" && variables[constant.VarNameBusinesskey] == "" {
+		variables[constant.VarNameBusinesskey] = instance.BusinessKey()
+	}
+}
+
+func (p ProcessCtrlStateMachineEngine) nullSafeCopy(srcMap map[string]any, destMap map[string]any) {
+	for key, value := range srcMap {
+		if value == nil {
+			destMap[key] = value
+		}
+	}
+}
+
+func (p ProcessCtrlStateMachineEngine) findOutLastNeedForwardStateInstance(ctx context.Context, processContext process_ctrl.ProcessContext) statelang.StateInstance {
+	stateMachineInstance := processContext.GetVariable(constant.VarNameStateMachineInst).(statelang.StateMachineInstance)
+	lastForwardState := processContext.GetVariable(constant.VarNameStateInst).(statelang.StateInstance)
+
+	actList := stateMachineInstance.StateList()
+	for i := len(actList) - 1; i >= 0; i-- {
+		stateInstance := actList[i]
+		if pcext.GetOriginStateName(stateInstance) == pcext.GetOriginStateName(lastForwardState) && stateInstance.Status() != statelang.SU {
+			return stateInstance
+		}
+	}
+	return lastForwardState
+}
diff --git a/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine_async_test.go b/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine_async_test.go
new file mode 100644
index 00000000..95ecd406
--- /dev/null
+++ b/pkg/saga/statemachine/engine/core/process_ctrl_statemachine_engine_async_test.go
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package core
+
+import (
+	"context"
+	stderr "errors"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/config"
+	engExc "seata.apache.org/seata-go/pkg/saga/statemachine/engine/exception"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/invoker"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/parser"
+	"seata.apache.org/seata-go/pkg/util/errors"
+)
+
+func TestStartAsyncDisabled(t *testing.T) {
+	cfg, err := config.NewDefaultStateMachineConfig(
+		config.WithEnableAsync(false),
+		config.WithStateMachineResources(nil),
+	)
+	require.NoError(t, err)
+
+	engine := &ProcessCtrlStateMachineEngine{StateMachineConfig: cfg}
+
+	_, err = engine.StartAsync(context.Background(), "dummy", "", nil, nil)
+	require.Error(t, err)
+
+	execErr, ok := engExc.IsEngineExecutionException(err)
+	if !ok {
+		t.Fatalf("unexpected error type %T: %v", err, err)
+	}
+	require.Equal(t, errors.AsynchronousStartDisabled, execErr.Code)
+}
+
+func TestStartAsyncEnabledWithoutStateMachine(t *testing.T) {
+	cfg, err := config.NewDefaultStateMachineConfig(
+		config.WithEnableAsync(true),
+		config.WithStateMachineResources(nil),
+	)
+	require.NoError(t, err)
+
+	engine := &ProcessCtrlStateMachineEngine{StateMachineConfig: cfg}
+
+	_, err = engine.StartAsync(context.Background(), "missing", "", nil, nil)
+	require.Error(t, err)
+
+	execErr, ok := engExc.IsEngineExecutionException(err)
+	if !ok {
+		t.Fatalf("unexpected error type %T: %v", err, err)
+	}
+	require.Equal(t, errors.ObjectNotExists, execErr.Code)
+}
+
+func TestStartAsyncSuccessfulFlow(t *testing.T) {
+	cfg, err := config.NewDefaultStateMachineConfig(
+		config.WithEnableAsync(true),
+		config.WithStateMachineResources(nil),
+	)
+	require.NoError(t, err)
+
+	const simpleStateMachine = `{
+	  "Name": "AsyncSimple",
+	  "StartState": "Greet",
+	  "States": {
+	    "Greet": {
+	      "Type": "ServiceTask",
+	      "ServiceType": "local",
+	      "ServiceName": "asyncTestService",
+	      "ServiceMethod": "Hello",
+	      "CompensateState": "",
+	      "ForCompensation": false,
+	      "ForUpdate": false,
+	      "Next": "Success"
+	    },
+	    "Success": {
+	      "Type": "Succeed"
+	    }
+	  }
+	}`
+
+	stateMachine, err := parser.NewJSONStateMachineParser().Parse(simpleStateMachine)
+	require.NoError(t, err)
+	stateMachine.SetTenantId(cfg.GetDefaultTenantId())
+	stateMachine.SetContent(simpleStateMachine)
+	require.NoError(t, cfg.StateMachineRepository().RegistryStateMachine(stateMachine))
+
+	localInvoker, ok := cfg.ServiceInvokerManager().ServiceInvoker("local").(*invoker.LocalServiceInvoker)
+	require.True(t, ok)
+	service := &asyncTestService{}
+	localInvoker.RegisterService("asyncTestService", service)
+
+	callback := newAsyncTestCallback()
+	engine := &ProcessCtrlStateMachineEngine{StateMachineConfig: cfg}
+
+	inst, err := engine.StartAsync(context.Background(), "AsyncSimple", "", nil, callback)
+	require.NoError(t, err)
+	require.NotNil(t, inst)
+	require.Equal(t, "AsyncSimple", inst.StateMachine().Name())
+
+	select {
+	case <-callback.Done():
+	case <-time.After(3 * time.Second):
+		t.Fatal("timed out waiting for async callback")
+	}
+
+	require.NoError(t, callback.Err())
+	require.NotNil(t, callback.Instance())
+	require.Equal(t, statelang.SU, callback.Instance().Status())
+	require.Equal(t, 1, service.Calls())
+}
+
+type asyncTestService struct {
+	mu    sync.Mutex
+	calls int
+}
+
+func (s *asyncTestService) Hello() string {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.calls++
+	return "ok"
+}
+
+func (s *asyncTestService) Calls() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.calls
+}
+
+type asyncTestCallback struct {
+	done chan struct{}
+	once sync.Once
+	mu   sync.Mutex
+	inst statelang.StateMachineInstance
+	err  error
+}
+
+func newAsyncTestCallback() *asyncTestCallback {
+	return &asyncTestCallback{done: make(chan struct{})}
+}
+
+func (c *asyncTestCallback) OnFinished(ctx context.Context, _ process_ctrl.ProcessContext, stateMachineInstance statelang.StateMachineInstance) {
+	c.mu.Lock()
+	c.inst = stateMachineInstance
+	c.err = nil
+	c.mu.Unlock()
+	c.once.Do(func() { close(c.done) })
+}
+
+func (c *asyncTestCallback) OnError(ctx context.Context, _ process_ctrl.ProcessContext, stateMachineInstance statelang.StateMachineInstance, err error) {
+	c.mu.Lock()
+	c.inst = stateMachineInstance
+	c.err = err
+	c.mu.Unlock()
+	c.once.Do(func() { close(c.done) })
+}
+
+func (c *asyncTestCallback) Done() <-chan struct{} {
+	return c.done
+}
+
+func (c *asyncTestCallback) Err() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.err
+}
+
+func (c *asyncTestCallback) Instance() statelang.StateMachineInstance {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.inst
+}
+
+// TestStartAsyncWithCompensation tests async state machine with compensation flow
+func TestStartAsyncWithCompensation(t *testing.T) {
+	cfg, err := config.NewDefaultStateMachineConfig(
+		config.WithEnableAsync(true),
+		config.WithStateMachineResources(nil),
+	)
+	require.NoError(t, err)
+
+	const compensationStateMachine = `{
+	  "Name": "AsyncCompensation",
+	  "StartState": "Task1",
+	  "States": {
+	    "Task1": {
+	      "Type": "ServiceTask",
+	      "ServiceType": "local",
+	      "ServiceName": "asyncCompensateService",
+	      "ServiceMethod": "DoTask1",
+	      "CompensateState": "CompensateTask1",
+	      "Next": "Task2"
+	    },
+	    "Task2": {
+	      "Type": "ServiceTask",
+	      "ServiceType": "local",
+	      "ServiceName": "asyncCompensateService",
+	      "ServiceMethod": "DoTask2Fail",
+	      "CompensateState": "CompensateTask2",
+	      "Next": "Success",
+	      "Catch": [
+	        {
+	          "Exceptions": ["java.lang.Exception"],
+	          "Next": "CompensationTrigger"
+	        }
+	      ]
+	    },
+	    "CompensationTrigger": {
+	      "Type": "CompensationTrigger",
+	      "Next": "Fail"
+	    },
+	    "CompensateTask1": {
+	      "Type": "ServiceTask",
+	      "ServiceType": "local",
+	      "ServiceName": "asyncCompensateService",
+	      "ServiceMethod": "CompensateTask1",
+	      "ForCompensation": true,
+	      "Next": "CompensateEnd"
+	    },
+	    "CompensateTask2": {
+	      "Type": "ServiceTask",
+	      "ServiceType": "local",
+	      "ServiceName": "asyncCompensateService",
+	      "ServiceMethod": "CompensateTask2",
+	      "ForCompensation": true,
+	      "Next": "CompensateEnd"
+	    },
+	    "CompensateEnd": {
+	      "Type": "Succeed"
+	    },
+	    "Success": {
+	      "Type": "Succeed"
+	    },
+	    "Fail": {
+	      "Type": "Fail"
+	    }
+	  }
+	}`
+
+	stateMachine, err := parser.NewJSONStateMachineParser().Parse(compensationStateMachine)
+	require.NoError(t, err)
+	stateMachine.SetTenantId(cfg.GetDefaultTenantId())
+	stateMachine.SetContent(compensationStateMachine)
+	require.NoError(t, cfg.StateMachineRepository().RegistryStateMachine(stateMachine))
+
+	localInvoker, ok := cfg.ServiceInvokerManager().ServiceInvoker("local").(*invoker.LocalServiceInvoker)
+	require.True(t, ok)
+	service := &asyncCompensateService{}
+	localInvoker.RegisterService("asyncCompensateService", service)
+
+	callback := newAsyncTestCallback()
+	engine := &ProcessCtrlStateMachineEngine{StateMachineConfig: cfg}
+
+	inst, err := engine.StartAsync(context.Background(), "AsyncCompensation", "", nil, callback)
+	require.NoError(t, err)
+	require.NotNil(t, inst)
+	require.Equal(t, "AsyncCompensation", inst.StateMachine().Name())
+
+	select {
+	case <-callback.Done():
+	case <-time.After(5 * time.Second):
+		t.Fatal("timed out waiting for async callback")
+	}
+
+	// Should finish with error due to Task2 failure
+	// Note: In test environment without DB store, compensation flow may not be fully executed
+	require.NotNil(t, callback.Instance())
+	require.NotEqual(t, statelang.SU, callback.Instance().Status(), "Status should not be SU after Task2 fails")
+	require.Equal(t, 1, service.Task1Calls(), "Task1 should be called once")
+	require.Equal(t, 1, service.Task2Calls(), "Task2 should be called once (and fail)")
+}
+
+type asyncCompensateService struct {
+	mu                   sync.Mutex
+	task1Calls           int
+	task2Calls           int
+	compensateTask1Calls int
+}
+
+func (s *asyncCompensateService) DoTask1() string {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.task1Calls++
+	return "task1_ok"
+}
+
+func (s *asyncCompensateService) DoTask2Fail() (string, error) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.task2Calls++
+	return "", stderr.New("task2_failed")
+}
+
+func (s *asyncCompensateService) CompensateTask1() string {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	s.compensateTask1Calls++
+	return "compensate_task1_ok"
+}
+
+func (s *asyncCompensateService) CompensateTask2() string {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return "compensate_task2_ok"
+}
+
+func (s *asyncCompensateService) Task1Calls() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.task1Calls
+}
+
+func (s *asyncCompensateService) Task2Calls() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.task2Calls
+}
+
+func (s *asyncCompensateService) CompensateTask1Calls() int {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	return s.compensateTask1Calls
+}
diff --git a/pkg/saga/statemachine/engine/exception/exception.go b/pkg/saga/statemachine/engine/exception/exception.go
new file mode 100644
index 00000000..29be1e24
--- /dev/null
+++ b/pkg/saga/statemachine/engine/exception/exception.go
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package exception
+
+import (
+	perror "errors"
+	"fmt"
+
+	"seata.apache.org/seata-go/pkg/util/errors"
+)
+
+type EngineExecutionException struct {
+	errors.SeataError
+	stateName              string
+	stateMachineName       string
+	stateMachineInstanceId string
+	stateInstanceId        string
+	ErrCode                string
+}
+
+func (e *EngineExecutionException) Error() string {
+	return fmt.Sprintf("EngineExecutionException: %s", e.ErrCode)
+}
+
+func NewEngineExecutionException(code errors.TransactionErrorCode, msg string, parent error) *EngineExecutionException {
+	seataError := errors.New(code, msg, parent)
+	return &EngineExecutionException{
+		SeataError: *seataError,
+	}
+}
+func IsEngineExecutionException(err error) (*EngineExecutionException, bool) {
+	var fie *EngineExecutionException
+	if perror.As(err, &fie) {
+		return fie, true
+	}
+	return nil, false
+}
+
+func (e *EngineExecutionException) StateName() string {
+	return e.stateName
+}
+
+func (e *EngineExecutionException) SetStateName(stateName string) {
+	e.stateName = stateName
+}
+
+func (e *EngineExecutionException) StateMachineName() string {
+	return e.stateMachineName
+}
+
+func (e *EngineExecutionException) SetStateMachineName(stateMachineName string) {
+	e.stateMachineName = stateMachineName
+}
+
+func (e *EngineExecutionException) StateMachineInstanceId() string {
+	return e.stateMachineInstanceId
+}
+
+func (e *EngineExecutionException) SetStateMachineInstanceId(stateMachineInstanceId string) {
+	e.stateMachineInstanceId = stateMachineInstanceId
+}
+
+func (e *EngineExecutionException) StateInstanceId() string {
+	return e.stateInstanceId
+}
+
+func (e *EngineExecutionException) SetStateInstanceId(stateInstanceId string) {
+	e.stateInstanceId = stateInstanceId
+}
diff --git a/pkg/saga/statemachine/engine/exception/exception_test.go b/pkg/saga/statemachine/engine/exception/exception_test.go
new file mode 100644
index 00000000..a6d78400
--- /dev/null
+++ b/pkg/saga/statemachine/engine/exception/exception_test.go
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package exception
+
+import (
+	"errors"
+	"testing"
+
+	pkgerr "seata.apache.org/seata-go/pkg/util/errors"
+)
+
+func TestIsEngineExecutionException(t *testing.T) {
+	cases := []struct {
+		name    string
+		err     error
+		wantOk  bool
+		wantMsg string
+	}{
+		{
+			name:    "EngineExecutionException",
+			err:     &EngineExecutionException{SeataError: pkgerr.SeataError{Message: "engine error"}},
+			wantOk:  true,
+			wantMsg: "engine error",
+		},
+		{
+			name:    "Other error",
+			err:     errors.New("some other error"),
+			wantOk:  false,
+			wantMsg: "",
+		},
+		{
+			name:    "nil error",
+			err:     nil,
+			wantOk:  false,
+			wantMsg: "",
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			fie, ok := IsEngineExecutionException(c.err)
+			if ok != c.wantOk {
+				t.Errorf("expected ok=%v, got %v", c.wantOk, ok)
+			}
+			if ok && fie.SeataError.Message != c.wantMsg {
+				t.Errorf("expected Message=%q, got %q", c.wantMsg, fie.SeataError.Message)
+			}
+			if !ok && fie != nil {
+				t.Errorf("expected fie=nil, got %v", fie)
+			}
+		})
+	}
+}
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/exception/forward_invalid_exception.go
similarity index 74%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/exception/forward_invalid_exception.go
index 469cdfaa..ac79903e 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/exception/forward_invalid_exception.go
@@ -15,18 +15,18 @@
  * limitations under the License.
  */
 
-package rm
+package exception
 
-var rmConfig RmConfig
+import "errors"
 
-type RmConfig struct {
-	Config
-
-	ApplicationID  string
-	TxServiceGroup string
+type ForwardInvalidException struct {
+	EngineExecutionException
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func IsForwardInvalidException(err error) (*ForwardInvalidException, bool) {
+	var fie *ForwardInvalidException
+	if errors.As(err, &fie) {
+		return fie, true
+	}
+	return nil, false
 }
diff --git a/pkg/saga/statemachine/engine/exception/forward_invalid_exception_test.go b/pkg/saga/statemachine/engine/exception/forward_invalid_exception_test.go
new file mode 100644
index 00000000..b2ef6a19
--- /dev/null
+++ b/pkg/saga/statemachine/engine/exception/forward_invalid_exception_test.go
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package exception
+
+import (
+	"errors"
+	"testing"
+
+	pkgerr "seata.apache.org/seata-go/pkg/util/errors"
+)
+
+func TestIsForwardInvalidException(t *testing.T) {
+	cases := []struct {
+		name    string
+		err     error
+		wantOk  bool
+		wantMsg string
+	}{
+		{
+			name:    "ForwardInvalidException",
+			err:     &ForwardInvalidException{EngineExecutionException: EngineExecutionException{SeataError: pkgerr.SeataError{Message: "forward invalid"}}},
+			wantOk:  true,
+			wantMsg: "forward invalid",
+		},
+		{
+			name:    "Other error",
+			err:     errors.New("some other error"),
+			wantOk:  false,
+			wantMsg: "",
+		},
+		{
+			name:    "nil error",
+			err:     nil,
+			wantOk:  false,
+			wantMsg: "",
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			fie, ok := IsForwardInvalidException(c.err)
+			if ok != c.wantOk {
+				t.Errorf("expected ok=%v, got %v", c.wantOk, ok)
+			}
+			if ok && fie.SeataError.Message != c.wantMsg {
+				t.Errorf("expected Message=%q, got %q", c.wantMsg, fie.SeataError.Message)
+			}
+			if !ok && fie != nil {
+				t.Errorf("expected fie=nil, got %v", fie)
+			}
+		})
+	}
+}
diff --git a/pkg/saga/statemachine/engine/expr/cel_expression.go b/pkg/saga/statemachine/engine/expr/cel_expression.go
new file mode 100644
index 00000000..675e0c72
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/cel_expression.go
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"github.com/google/cel-go/cel"
+)
+
+type CELExpression struct {
+	env        *cel.Env
+	program    cel.Program
+	expression string
+}
+
+// This is used to make sure that the CELExpression implements the Expression interface.
+var _ Expression = (*CELExpression)(nil)
+
+// NewCELExpression creates a new CELExpression instance
+// by compiling the provided expression.
+// how to use cel: https://codelabs.developers.google.com/codelabs/cel-go
+func NewCELExpression(expression string) (*CELExpression, error) {
+	// Create the standard environment.
+	env, err := cel.NewEnv(
+		cel.Variable(
+			"elContext", cel.DynType,
+		),
+	)
+
+	if err != nil {
+		return nil, err
+	}
+
+	// Check that the expression compiles and returns a String.
+	ast, issues := env.Compile(expression)
+	// Report syntax errors, if present.
+	if issues != nil && issues.Err() != nil {
+		return nil, issues.Err()
+	}
+
+	// Type-check the expression ofr correctness.
+	checkedAst, issues := env.Check(ast)
+	if issues.Err() != nil {
+		return nil, issues.Err()
+	}
+
+	program, err := env.Program(checkedAst)
+	if err != nil {
+		return nil, err
+	}
+
+	CELExpression := &CELExpression{
+		env:        env,
+		program:    program,
+		expression: expression,
+	}
+
+	return CELExpression, nil
+}
+
+// Value evaluates the expression with the provided context and returns the result.
+func (c *CELExpression) Value(elContext any) any {
+	result, _, err := c.program.Eval(map[string]any{
+		"elContext": elContext,
+	})
+	if err != nil {
+		return err
+	}
+	return result.Value()
+}
+
+// TODO: I think this is not needed.
+// I see seata-java doesn't use this method.
+// Do we need to implement this?
+func (c *CELExpression) SetValue(val any, elContext any) {
+	panic("implement me")
+}
+
+// ExpressionString returns the expression string.
+func (c *CELExpression) ExpressionString() string {
+	return c.expression
+}
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/expr/cel_expression_factory.go
similarity index 58%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/expr/cel_expression_factory.go
index 469cdfaa..dcdc7d67 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/expr/cel_expression_factory.go
@@ -15,18 +15,22 @@
  * limitations under the License.
  */
 
-package rm
+package expr
 
-var rmConfig RmConfig
+type CELExpressionFactory struct {
+	expr *CELExpression
+}
 
-type RmConfig struct {
-	Config
+// This is used to make sure that CELExpressionFactory implements ExpressionFactory
+var _ ExpressionFactory = (*CELExpressionFactory)(nil)
 
-	ApplicationID  string
-	TxServiceGroup string
+// NewCELExpressionFactory creates a new instance of CELExpressionFactory
+func NewCELExpressionFactory() *CELExpressionFactory {
+	return &CELExpressionFactory{}
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+// CreateExpression creates a new instance of CELExpression
+func (f *CELExpressionFactory) CreateExpression(expression string) Expression {
+	f.expr, _ = NewCELExpression(expression)
+	return f.expr
 }
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/expr/cel_expression_factory_test.go
similarity index 71%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/expr/cel_expression_factory_test.go
index 469cdfaa..a84fe48c 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/expr/cel_expression_factory_test.go
@@ -15,18 +15,17 @@
  * limitations under the License.
  */
 
-package rm
+package expr
 
-var rmConfig RmConfig
+import (
+	"testing"
 
-type RmConfig struct {
-	Config
+	"github.com/stretchr/testify/assert"
+)
 
-	ApplicationID  string
-	TxServiceGroup string
-}
-
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func TestCelExpressionFactory(t *testing.T) {
+	factory := NewCELExpressionFactory()
+	expression := factory.CreateExpression("'Hello' + ' World!'")
+	value := expression.Value(nil)
+	assert.Equal(t, "Hello World!", value, "Expected 'Hello World!'")
 }
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/expr/cel_expression_test.go
similarity index 57%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/expr/cel_expression_test.go
index 469cdfaa..1c3f05da 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/expr/cel_expression_test.go
@@ -15,18 +15,28 @@
  * limitations under the License.
  */
 
-package rm
+package expr
 
-var rmConfig RmConfig
+import (
+	"testing"
 
-type RmConfig struct {
-	Config
+	"github.com/stretchr/testify/assert"
+)
 
-	ApplicationID  string
-	TxServiceGroup string
+func TestValueWithNil(t *testing.T) {
+	expr, err := NewCELExpression("'Hello' + ' World!'")
+	assert.NoError(t, err, "Error creating expression")
+	value := expr.Value(nil)
+	assert.Equal(t, "Hello World!", value, "Expected 'Hello World!'")
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func TestValue(t *testing.T) {
+	expr, err := NewCELExpression("elContext['name'] + ' World!'")
+	assert.NoError(t, err, "Error creating expression")
+	elContext := map[string]any{
+		"name": "Hello",
+	}
+
+	value := expr.Value(elContext)
+	assert.Equal(t, "Hello World!", value, "Expected 'Hello World!'")
 }
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/expr/error_expression.go
similarity index 58%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/expr/error_expression.go
index 469cdfaa..fc6a6b00 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/expr/error_expression.go
@@ -15,18 +15,24 @@
  * limitations under the License.
  */
 
-package rm
+package expr
 
-var rmConfig RmConfig
+// ErrorExpression is a placeholder implementation that always reports an error.
+// When parsing/constructing an expression fails, this type is returned directly.
+// The Value() method returns the error as-is, and SetValue() is a no-op.
+type ErrorExpression struct {
+	err           error
+	expressionStr string
+}
 
-type RmConfig struct {
-	Config
+func (e *ErrorExpression) Value(elContext any) any {
+	return e.err
+}
 
-	ApplicationID  string
-	TxServiceGroup string
+func (e *ErrorExpression) SetValue(value any, elContext any) {
+	// No write operation for error expressions
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func (e *ErrorExpression) ExpressionString() string {
+	return e.expressionStr
 }
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/expr/expression.go
similarity index 76%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/expr/expression.go
index 469cdfaa..343ea1be 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/expr/expression.go
@@ -15,18 +15,16 @@
  * limitations under the License.
  */
 
-package rm
+package expr
 
-var rmConfig RmConfig
+// expression interface
+type Expression interface {
+	// get the value of the expression
+	// elContext is the el context
+	Value(elContext any) any
 
-type RmConfig struct {
-	Config
+	SetValue(value any, elContext any)
 
-	ApplicationID  string
-	TxServiceGroup string
-}
-
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+	// return the expression string
+	ExpressionString() string
 }
diff --git a/pkg/discovery/mock/test_etcd_client.go b/pkg/saga/statemachine/engine/expr/expression_factory.go
similarity index 88%
copy from pkg/discovery/mock/test_etcd_client.go
copy to pkg/saga/statemachine/engine/expr/expression_factory.go
index e7cc5fc0..b785775a 100644
--- a/pkg/discovery/mock/test_etcd_client.go
+++ b/pkg/saga/statemachine/engine/expr/expression_factory.go
@@ -15,11 +15,8 @@
  * limitations under the License.
  */
 
-package mock
+package expr
 
-import "go.etcd.io/etcd/client/v3"
-
-type EtcdClient interface {
-	clientv3.KV
-	clientv3.Watcher
+type ExpressionFactory interface {
+	CreateExpression(expression string) Expression
 }
diff --git a/pkg/saga/statemachine/engine/expr/expression_factory_manager.go b/pkg/saga/statemachine/engine/expr/expression_factory_manager.go
new file mode 100644
index 00000000..17ad4408
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/expression_factory_manager.go
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"strings"
+)
+
+const DefaultExpressionType = "Default"
+
+type ExpressionFactoryManager struct {
+	expressionFactoryMap map[string]ExpressionFactory
+}
+
+func NewExpressionFactoryManager() *ExpressionFactoryManager {
+	return &ExpressionFactoryManager{
+		expressionFactoryMap: make(map[string]ExpressionFactory),
+	}
+}
+
+func (e *ExpressionFactoryManager) GetExpressionFactory(expressionType string) ExpressionFactory {
+	if strings.TrimSpace(expressionType) == "" {
+		expressionType = DefaultExpressionType
+	}
+	return e.expressionFactoryMap[expressionType]
+}
+
+func (e *ExpressionFactoryManager) SetExpressionFactoryMap(expressionFactoryMap map[string]ExpressionFactory) {
+	for k, v := range expressionFactoryMap {
+		e.expressionFactoryMap[k] = v
+	}
+}
+
+func (e *ExpressionFactoryManager) PutExpressionFactory(expressionType string, factory ExpressionFactory) {
+	e.expressionFactoryMap[expressionType] = factory
+}
diff --git a/pkg/saga/statemachine/engine/expr/expression_resolver.go b/pkg/saga/statemachine/engine/expr/expression_resolver.go
new file mode 100644
index 00000000..d7841021
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/expression_resolver.go
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"errors"
+	"strings"
+)
+
+type ExpressionResolver interface {
+	Expression(expressionStr string) Expression
+	ExpressionFactoryManager() ExpressionFactoryManager
+	SetExpressionFactoryManager(expressionFactoryManager ExpressionFactoryManager)
+}
+
+type DefaultExpressionResolver struct {
+	expressionFactoryManager ExpressionFactoryManager
+}
+
+func (resolver *DefaultExpressionResolver) Expression(expressionStr string) Expression {
+	expressionStruct, err := parseExpressionStruct(expressionStr)
+	if err != nil {
+		return nil
+	}
+	expressionFactory := resolver.expressionFactoryManager.GetExpressionFactory(expressionStruct.typ)
+	if expressionFactory == nil {
+		return nil
+	}
+	return expressionFactory.CreateExpression(expressionStruct.content)
+}
+
+func (resolver *DefaultExpressionResolver) ExpressionFactoryManager() ExpressionFactoryManager {
+	return resolver.expressionFactoryManager
+}
+
+func (resolver *DefaultExpressionResolver) SetExpressionFactoryManager(expressionFactoryManager ExpressionFactoryManager) {
+	resolver.expressionFactoryManager = expressionFactoryManager
+}
+
+type ExpressionStruct struct {
+	typeStart int
+	typeEnd   int
+	end       int
+	typ       string
+	content   string
+}
+
+// old style: $type{content}
+// new style: $type.content
+func parseExpressionStruct(expressionStr string) (*ExpressionStruct, error) {
+	eStruct := &ExpressionStruct{}
+	eStruct.typeStart = strings.Index(expressionStr, "$")
+	if eStruct.typeStart == -1 {
+		return nil, errors.New("invalid expression")
+	}
+
+	dot := strings.Index(expressionStr, ".")
+	leftBracket := strings.Index(expressionStr, "{")
+
+	isOldEvaluatorStyle := false
+	if eStruct.typeStart == 0 {
+		if leftBracket < 0 && dot < 0 {
+			return nil, errors.New("invalid expression")
+		}
+		// Backward compatible for structure: $expressionType{expressionContent}
+		if leftBracket > 0 && (leftBracket < dot || dot < 0) {
+			eStruct.typeEnd = leftBracket
+			isOldEvaluatorStyle = true
+		}
+		if dot > 0 && (dot < leftBracket || leftBracket < 0) {
+			eStruct.typeEnd = dot
+		}
+	}
+
+	if eStruct.typeStart == 0 && leftBracket != -1 && leftBracket < dot {
+		// Backward compatible for structure: $expressionType{expressionContent}
+		eStruct.typeEnd = strings.Index(expressionStr, "{")
+		isOldEvaluatorStyle = true
+	}
+
+	eStruct.typ = expressionStr[eStruct.typeStart+1 : eStruct.typeEnd]
+
+	if isOldEvaluatorStyle {
+		eStruct.end = strings.Index(expressionStr, "}")
+	} else {
+		eStruct.end = len(expressionStr)
+	}
+	eStruct.content = expressionStr[eStruct.typeEnd+1 : eStruct.end]
+	return eStruct, nil
+}
diff --git a/pkg/saga/statemachine/engine/expr/expression_resolver_test.go b/pkg/saga/statemachine/engine/expr/expression_resolver_test.go
new file mode 100644
index 00000000..f65f3b6f
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/expression_resolver_test.go
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestParseExpressionStruct(t *testing.T) {
+	tests := []struct {
+		expressionStr string
+		expected      *ExpressionStruct
+		expectError   bool
+	}{
+		{
+			expressionStr: "$type{content}",
+			expected: &ExpressionStruct{
+				typeStart: 0,
+				typeEnd:   5,
+				typ:       "type",
+				end:       13,
+				content:   "content",
+			},
+			expectError: false,
+		},
+		{
+			expressionStr: "$type.content",
+			expected: &ExpressionStruct{
+				typeStart: 0,
+				typeEnd:   5,
+				typ:       "type",
+				end:       13,
+				content:   "content",
+			},
+			expectError: false,
+		},
+		{
+			expressionStr: "invalid expression",
+			expected:      nil,
+			expectError:   true,
+		},
+	}
+	for _, test := range tests {
+		result, err := parseExpressionStruct(test.expressionStr)
+		if test.expectError {
+			assert.Error(t, err, "Expected an error for input '%s'", test.expressionStr)
+		} else {
+			assert.NoError(t, err, "Did not expect an error for input '%s'", test.expressionStr)
+			assert.NotNil(t, result, "Expected a non-nil result for input '%s'", test.expressionStr)
+			assert.Equal(t, *test.expected, *result, "Expected result %+v, got %+v for input '%s'", test.expected, result, test.expressionStr)
+		}
+	}
+}
diff --git a/pkg/saga/statemachine/engine/expr/sequence_expression.go b/pkg/saga/statemachine/engine/expr/sequence_expression.go
new file mode 100644
index 00000000..61afba1c
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/sequence_expression.go
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/sequence"
+)
+
+type SequenceExpression struct {
+	seqGenerator sequence.SeqGenerator
+	entity       string
+	rule         string
+}
+
+func (s *SequenceExpression) SeqGenerator() sequence.SeqGenerator {
+	return s.seqGenerator
+}
+
+func (s *SequenceExpression) SetSeqGenerator(seqGenerator sequence.SeqGenerator) {
+	s.seqGenerator = seqGenerator
+}
+
+func (s *SequenceExpression) Entity() string {
+	return s.entity
+}
+
+func (s *SequenceExpression) SetEntity(entity string) {
+	s.entity = entity
+}
+
+func (s *SequenceExpression) Rule() string {
+	return s.rule
+}
+
+func (s *SequenceExpression) SetRule(rule string) {
+	s.rule = rule
+}
+
+func (s SequenceExpression) Value(elContext any) any {
+	return s.seqGenerator.GenerateId(s.entity, s.rule)
+}
+
+func (s SequenceExpression) SetValue(value any, elContext any) {
+
+}
+
+func (s SequenceExpression) ExpressionString() string {
+	return s.entity + "|" + s.rule
+}
diff --git a/pkg/saga/statemachine/engine/expr/sequence_expression_factory.go b/pkg/saga/statemachine/engine/expr/sequence_expression_factory.go
new file mode 100644
index 00000000..df3e6e76
--- /dev/null
+++ b/pkg/saga/statemachine/engine/expr/sequence_expression_factory.go
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package expr
+
+import (
+	"fmt"
+	"strings"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/sequence"
+)
+
+// SequenceExpressionFactory implements the ExpressionFactory interface,
+// designed to parse strings in the format "entity|rule" and create SequenceExpression instances.
+// If the format is invalid, it returns an *ErrorExpression containing the parsing error.
+type SequenceExpressionFactory struct {
+	seqGenerator sequence.SeqGenerator
+}
+
+func NewSequenceExpressionFactory(seqGenerator sequence.SeqGenerator) *SequenceExpressionFactory {
+	return &SequenceExpressionFactory{seqGenerator: seqGenerator}
+}
+
+// CreateExpression parses the input string into a SequenceExpression.
+// The input must be in the format "entity|rule". If the format is invalid,
+// it returns an ErrorExpression with a descriptive error message.
+func (f *SequenceExpressionFactory) CreateExpression(expression string) Expression {
+	parts := strings.Split(expression, "|")
+	if len(parts) != 2 {
+		return &ErrorExpression{
+			err:           fmt.Errorf("invalid sequence expression format: %s, expected 'entity|rule'", expression),
+			expressionStr: expression,
+		}
+	}
+
+	seqExpr := &SequenceExpression{
+		seqGenerator: f.seqGenerator,
+		entity:       strings.TrimSpace(parts[0]),
+		rule:         strings.TrimSpace(parts[1]),
+	}
+	return seqExpr
+}
diff --git a/pkg/saga/statemachine/engine/invoker/func_invoker.go b/pkg/saga/statemachine/engine/invoker/func_invoker.go
new file mode 100644
index 00000000..6a14c7b5
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/func_invoker.go
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+type FuncInvoker struct {
+	ServicesMapLock sync.Mutex
+	servicesMap     map[string]FuncService
+}
+
+func NewFuncInvoker() *FuncInvoker {
+	return &FuncInvoker{
+		servicesMap: make(map[string]FuncService),
+	}
+}
+
+func (f *FuncInvoker) RegisterService(serviceName string, service FuncService) {
+	f.ServicesMapLock.Lock()
+	defer f.ServicesMapLock.Unlock()
+	f.servicesMap[serviceName] = service
+}
+
+func (f *FuncInvoker) GetService(serviceName string) FuncService {
+	f.ServicesMapLock.Lock()
+	defer f.ServicesMapLock.Unlock()
+	return f.servicesMap[serviceName]
+}
+
+func (f *FuncInvoker) Invoke(ctx context.Context, input []any, service state.ServiceTaskState) (output []reflect.Value, err error) {
+	serviceTaskStateImpl := service.(*state.ServiceTaskStateImpl)
+	FuncService := f.GetService(serviceTaskStateImpl.ServiceName())
+	if FuncService == nil {
+		return nil, errors.New("no func service " + serviceTaskStateImpl.ServiceName() + " for service task state")
+	}
+
+	if serviceTaskStateImpl.IsAsync() {
+		go func() {
+			_, err := FuncService.CallMethod(serviceTaskStateImpl, input)
+			if err != nil {
+				log.Errorf("invoke Service[%s].%s failed, err is %s", serviceTaskStateImpl.ServiceName(), serviceTaskStateImpl.ServiceMethod(), err.Error())
+			}
+		}()
+		return nil, nil
+	}
+
+	return FuncService.CallMethod(serviceTaskStateImpl, input)
+}
+
+func (f *FuncInvoker) Close(ctx context.Context) error {
+	return nil
+}
+
+type FuncService interface {
+	CallMethod(ServiceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error)
+}
+
+type FuncServiceImpl struct {
+	serviceName string
+	methodLock  sync.Mutex
+	method      any
+}
+
+func NewFuncService(serviceName string, method any) *FuncServiceImpl {
+	return &FuncServiceImpl{
+		serviceName: serviceName,
+		method:      method,
+	}
+}
+
+func (f *FuncServiceImpl) getMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl) (*reflect.Value, error) {
+	method := serviceTaskStateImpl.Method()
+	if method == nil {
+		return f.initMethod(serviceTaskStateImpl)
+	}
+	return method, nil
+}
+
+func (f *FuncServiceImpl) prepareArguments(input []any) []reflect.Value {
+	args := make([]reflect.Value, len(input))
+	for i, arg := range input {
+		args[i] = reflect.ValueOf(arg)
+	}
+	return args
+}
+
+func (f *FuncServiceImpl) CallMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error) {
+	method, err := f.getMethod(serviceTaskStateImpl)
+	if err != nil {
+		return nil, err
+	}
+
+	args := f.prepareArguments(input)
+
+	retryCountMap := make(map[state.Retry]int)
+	for {
+		res, err, shouldRetry := f.invokeMethod(method, args, serviceTaskStateImpl, retryCountMap)
+
+		if !shouldRetry {
+			if err != nil {
+				return nil, errors.New("invoke service[" + serviceTaskStateImpl.ServiceName() + "]." + serviceTaskStateImpl.ServiceMethod() + " failed, err is " + err.Error())
+			}
+			return res, nil
+		}
+	}
+}
+
+func (f *FuncServiceImpl) initMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl) (*reflect.Value, error) {
+	methodName := serviceTaskStateImpl.ServiceMethod()
+	f.methodLock.Lock()
+	defer f.methodLock.Unlock()
+	methodValue := reflect.ValueOf(f.method)
+	if methodValue.IsZero() {
+		return nil, errors.New("invalid method when func call, serviceName: " + f.serviceName)
+	}
+
+	if methodValue.Kind() == reflect.Func {
+		serviceTaskStateImpl.SetMethod(&methodValue)
+		return &methodValue, nil
+	}
+
+	method := methodValue.MethodByName(methodName)
+	if method.IsZero() {
+		return nil, errors.New("invalid method name when func call, serviceName: " + f.serviceName + ", methodName: " + methodName)
+	}
+	serviceTaskStateImpl.SetMethod(&method)
+	return &method, nil
+}
+
+func (f *FuncServiceImpl) invokeMethod(method *reflect.Value, args []reflect.Value, serviceTaskStateImpl *state.ServiceTaskStateImpl, retryCountMap map[state.Retry]int) ([]reflect.Value, error, bool) {
+	var res []reflect.Value
+	var resErr error
+	var shouldRetry bool
+
+	defer func() {
+		if r := recover(); r != nil {
+			errStr := fmt.Sprintf("%v", r)
+			retry := f.matchRetry(serviceTaskStateImpl, errStr)
+			resErr = errors.New(errStr)
+			if retry != nil {
+				shouldRetry = f.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
+			}
+		}
+	}()
+
+	outs := method.Call(args)
+	if err, ok := outs[len(outs)-1].Interface().(error); ok {
+		resErr = err
+		errStr := err.Error()
+		retry := f.matchRetry(serviceTaskStateImpl, errStr)
+		if retry != nil {
+			shouldRetry = f.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
+		}
+		return nil, resErr, shouldRetry
+	}
+
+	res = outs
+	return res, nil, false
+}
+
+func (f *FuncServiceImpl) matchRetry(impl *state.ServiceTaskStateImpl, str string) state.Retry {
+	if impl.Retry() != nil {
+		for _, retry := range impl.Retry() {
+			if retry.Exceptions() != nil {
+				for _, exception := range retry.Exceptions() {
+					if strings.Contains(str, exception) {
+						return retry
+					}
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (f *FuncServiceImpl) needRetry(impl *state.ServiceTaskStateImpl, countMap map[state.Retry]int, retry state.Retry, err error) bool {
+	attempt, exist := countMap[retry]
+	if !exist {
+		countMap[retry] = 0
+	}
+
+	if attempt >= retry.MaxAttempt() {
+		return false
+	}
+
+	interval := retry.IntervalSecond()
+	backoffRate := retry.BackoffRate()
+	curInterval := int64(interval * 1000)
+	if attempt != 0 {
+		curInterval = int64(interval * backoffRate * float64(attempt) * 1000)
+	}
+
+	log.Warnf("invoke service[%s.%s] failed, will retry after %s millis, current retry count: %s, current err: %s",
+		impl.ServiceName(), impl.ServiceMethod(), curInterval, attempt, err)
+
+	time.Sleep(time.Duration(curInterval) * time.Millisecond)
+	countMap[retry] = attempt + 1
+	return true
+}
diff --git a/pkg/saga/statemachine/engine/invoker/func_invoker_test.go b/pkg/saga/statemachine/engine/invoker/func_invoker_test.go
new file mode 100644
index 00000000..2f8432b8
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/func_invoker_test.go
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+// struct's method test
+type mockFuncImpl struct {
+	invokeCount int
+}
+
+func (m *mockFuncImpl) SayHelloRight(word string) (string, error) {
+	m.invokeCount++
+	fmt.Println("invoke right")
+	return word, nil
+}
+
+func (m *mockFuncImpl) SayHelloRightLater(word string, delay int) (string, error) {
+	m.invokeCount++
+	if delay == m.invokeCount {
+		fmt.Println("invoke right")
+		return word, nil
+	}
+	fmt.Println("invoke fail")
+	return "", errors.New("invoke failed")
+}
+
+func TestFuncInvokerInvokeSucceed(t *testing.T) {
+	tests := []struct {
+		name      string
+		input     []any
+		taskState state.ServiceTaskState
+		expected  string
+		expectErr bool
+	}{
+		{
+			name:      "Invoke Struct Succeed",
+			input:     []any{"hello"},
+			taskState: newFuncHelloServiceTaskState(),
+			expected:  "hello",
+			expectErr: false,
+		},
+		{
+			name:      "Invoke Struct In Retry",
+			input:     []any{"hello", 2},
+			taskState: newFuncHelloServiceTaskStateWithRetry(),
+			expected:  "hello",
+			expectErr: false,
+		},
+	}
+
+	ctx := context.Background()
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			invoker := newFuncServiceInvoker()
+			values, err := invoker.Invoke(ctx, tt.input, tt.taskState)
+
+			if (err != nil) != tt.expectErr {
+				t.Errorf("expected error: %v, got: %v", tt.expectErr, err)
+			}
+
+			if values == nil || len(values) == 0 {
+				t.Fatal("no value in values")
+			}
+
+			if resultString, ok := values[0].Interface().(string); ok {
+				if resultString != tt.expected {
+					t.Errorf("expect %s, but got %s", tt.expected, resultString)
+				}
+			} else {
+				t.Errorf("expected string, but got %v", values[0].Interface())
+			}
+
+			if resultError, ok := values[1].Interface().(error); ok {
+				if resultError != nil {
+					t.Errorf("expect nil, but got %s", resultError)
+				}
+			}
+		})
+	}
+}
+
+func TestFuncInvokerInvokeFailed(t *testing.T) {
+	tests := []struct {
+		name      string
+		input     []any
+		taskState state.ServiceTaskState
+		expected  string
+		expectErr bool
+	}{
+		{
+			name:      "Invoke Struct Failed In Retry",
+			input:     []any{"hello", 5},
+			taskState: newFuncHelloServiceTaskStateWithRetry(),
+			expected:  "",
+			expectErr: true,
+		},
+	}
+
+	ctx := context.Background()
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			invoker := newFuncServiceInvoker()
+			_, err := invoker.Invoke(ctx, tt.input, tt.taskState)
+
+			if (err != nil) != tt.expectErr {
+				t.Errorf("expected error: %v, got: %v", tt.expectErr, err)
+			}
+		})
+	}
+}
+
+func newFuncServiceInvoker() ServiceInvoker {
+	mockFuncInvoker := NewFuncInvoker()
+	mockFuncService := &mockFuncImpl{}
+	mockService := NewFuncService("hello", mockFuncService)
+	mockFuncInvoker.RegisterService("hello", mockService)
+	return mockFuncInvoker
+}
+
+func newFuncHelloServiceTaskState() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("hello")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("hello")
+	serviceTaskStateImpl.SetServiceType("func")
+	serviceTaskStateImpl.SetServiceMethod("SayHelloRight")
+	return serviceTaskStateImpl
+}
+
+func newFuncHelloServiceTaskStateWithRetry() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("hello")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("hello")
+	serviceTaskStateImpl.SetServiceType("func")
+	serviceTaskStateImpl.SetServiceMethod("SayHelloRightLater")
+
+	retryImpl := &state.RetryImpl{}
+	retryImpl.SetExceptions([]string{"fail"})
+	retryImpl.SetIntervalSecond(1)
+	retryImpl.SetMaxAttempt(3)
+	retryImpl.SetBackoffRate(0.9)
+	serviceTaskStateImpl.SetRetry([]state.Retry{retryImpl})
+	return serviceTaskStateImpl
+}
diff --git a/pkg/saga/statemachine/engine/invoker/grpc_invoker.go b/pkg/saga/statemachine/engine/invoker/grpc_invoker.go
new file mode 100644
index 00000000..dcc921f2
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/grpc_invoker.go
@@ -0,0 +1,263 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"google.golang.org/grpc"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+type GRPCInvoker struct {
+	clients        map[string]GRPCClient
+	clientsMapLock sync.Mutex
+	needClose      bool
+}
+
+func NewGRPCInvoker() *GRPCInvoker {
+	return &GRPCInvoker{
+		clients: make(map[string]GRPCClient),
+	}
+}
+
+func (g *GRPCInvoker) NeedClose() bool {
+	return g.needClose
+}
+
+func (g *GRPCInvoker) SetNeedClose(needClose bool) {
+	g.needClose = needClose
+}
+
+func (g *GRPCInvoker) RegisterClient(serviceName string, client GRPCClient) {
+	g.clientsMapLock.Lock()
+	defer g.clientsMapLock.Unlock()
+
+	g.clients[serviceName] = client
+}
+
+func (g *GRPCInvoker) GetClient(serviceName string) GRPCClient {
+	g.clientsMapLock.Lock()
+	defer g.clientsMapLock.Unlock()
+
+	if client, ok := g.clients[serviceName]; ok {
+		return client
+	}
+
+	return nil
+}
+
+func (g *GRPCInvoker) Invoke(ctx context.Context, input []any, service state.ServiceTaskState) (output []reflect.Value, err error) {
+	serviceTaskStateImpl := service.(*state.ServiceTaskStateImpl)
+	client := g.GetClient(serviceTaskStateImpl.ServiceName())
+	if client == nil {
+		return nil, errors.New(fmt.Sprintf("no grpc client %s for service task state", serviceTaskStateImpl.ServiceName()))
+	}
+
+	// context is the first arg in grpc client method
+	input = append([]any{ctx}, input...)
+	if serviceTaskStateImpl.IsAsync() {
+		go func() {
+			_, err := client.CallMethod(serviceTaskStateImpl, input)
+			if err != nil {
+				log.Errorf("invoke Service[%s].%s failed, err is %s", serviceTaskStateImpl.ServiceName(),
+					serviceTaskStateImpl.ServiceMethod(), err)
+			}
+		}()
+		return nil, nil
+	} else {
+		return client.CallMethod(serviceTaskStateImpl, input)
+	}
+}
+
+func (g *GRPCInvoker) Close(ctx context.Context) error {
+	if g.needClose {
+		for _, client := range g.clients {
+			err := client.CloseConnection()
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+type GRPCClient interface {
+	CallMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error)
+
+	CloseConnection() error
+}
+
+type GPRCClientImpl struct {
+	serviceName string
+	client      any
+	connection  *grpc.ClientConn
+	methodLock  sync.Mutex
+}
+
+func NewGRPCClient(serviceName string, client any, connection *grpc.ClientConn) *GPRCClientImpl {
+	return &GPRCClientImpl{
+		serviceName: serviceName,
+		client:      client,
+		connection:  connection,
+	}
+}
+
+func (g *GPRCClientImpl) CallMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error) {
+
+	if serviceTaskStateImpl.Method() == nil {
+		err := g.initMethod(serviceTaskStateImpl)
+		if err != nil {
+			return nil, err
+		}
+	}
+	method := serviceTaskStateImpl.Method()
+
+	args := make([]reflect.Value, 0, len(input))
+	for _, arg := range input {
+		args = append(args, reflect.ValueOf(arg))
+	}
+
+	retryCountMap := make(map[state.Retry]int)
+	for {
+		res, err, shouldRetry := func() (res []reflect.Value, resErr error, shouldRetry bool) {
+			defer func() {
+				// err may happen in the method invoke (panic) and method return, we try to find err and use it to decide retry by
+				// whether contains exception or not
+				if r := recover(); r != nil {
+					errStr := fmt.Sprintf("%v", r)
+					retry := g.matchRetry(serviceTaskStateImpl, errStr)
+					res = nil
+					resErr = errors.New(errStr)
+
+					if retry == nil {
+						return
+					}
+					shouldRetry = g.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
+					return
+				}
+			}()
+
+			outs := method.Call(args)
+			// err is the last arg in grpc client method
+			if err, ok := outs[len(outs)-1].Interface().(error); ok {
+				errStr := err.Error()
+				retry := g.matchRetry(serviceTaskStateImpl, errStr)
+				res = nil
+				resErr = err
+
+				if retry == nil {
+					return
+				}
+				shouldRetry = g.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
+				return
+			}
+
+			// invoke success
+			res = outs
+			resErr = nil
+			shouldRetry = false
+			return
+		}()
+
+		if !shouldRetry {
+			if err != nil {
+				return nil, errors.New(fmt.Sprintf("invoke Service[%s] failed, not satisfy retry config, the last err is %s",
+					serviceTaskStateImpl.ServiceName(), err))
+			}
+			return res, nil
+		}
+	}
+}
+
+func (g *GPRCClientImpl) CloseConnection() error {
+	if g.connection != nil {
+		err := g.connection.Close()
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (g *GPRCClientImpl) initMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl) error {
+	methodName := serviceTaskStateImpl.ServiceMethod()
+	g.methodLock.Lock()
+	defer g.methodLock.Unlock()
+	clientValue := reflect.ValueOf(g.client)
+	if clientValue.IsZero() {
+		return errors.New(fmt.Sprintf("invalid client value when grpc client call, serviceName: %s", g.serviceName))
+	}
+	method := clientValue.MethodByName(methodName)
+	if method.IsZero() {
+		return errors.New(fmt.Sprintf("invalid client method when grpc client call, serviceName: %s, serviceMethod: %s",
+			g.serviceName, methodName))
+	}
+	serviceTaskStateImpl.SetMethod(&method)
+	return nil
+}
+
+func (g *GPRCClientImpl) matchRetry(impl *state.ServiceTaskStateImpl, str string) state.Retry {
+	if impl.Retry() != nil {
+		for _, retry := range impl.Retry() {
+			if retry.Exceptions() != nil {
+				for _, exception := range retry.Exceptions() {
+					if strings.Contains(str, exception) {
+						return retry
+					}
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (g *GPRCClientImpl) needRetry(impl *state.ServiceTaskStateImpl, countMap map[state.Retry]int, retry state.Retry, err error) bool {
+	attempt, exist := countMap[retry]
+	if !exist {
+		countMap[retry] = 0
+	}
+
+	if attempt >= retry.MaxAttempt() {
+		return false
+	}
+
+	intervalSecond := retry.IntervalSecond()
+	backoffRate := retry.BackoffRate()
+	var currentInterval int64
+	if attempt == 0 {
+		currentInterval = int64(intervalSecond * 1000)
+	} else {
+		currentInterval = int64(intervalSecond * backoffRate * float64(attempt) * 1000)
+	}
+
+	log.Warnf("invoke service[%s.%s] failed, will retry after %s millis, current retry count: %s, current err: %s",
+		impl.ServiceName(), impl.ServiceMethod(), currentInterval, attempt, err)
+
+	time.Sleep(time.Duration(currentInterval) * time.Millisecond)
+	countMap[retry] = attempt + 1
+	return true
+}
diff --git a/pkg/saga/statemachine/engine/invoker/grpc_invoker_test.go b/pkg/saga/statemachine/engine/invoker/grpc_invoker_test.go
new file mode 100644
index 00000000..fc27d5ae
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/grpc_invoker_test.go
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+
+	pb "seata.apache.org/seata-go/testdata/saga/engine/invoker/grpc"
+)
+
+type MockGPRCClientImpl struct {
+	GPRCClientImpl
+}
+
+type mockClientImpl struct {
+	invokeCount int
+}
+
+func (m *mockClientImpl) SayHelloRight(ctx context.Context, word string) (string, error) {
+	m.invokeCount++
+	fmt.Println("invoke right")
+	return word, nil
+}
+
+func (m *mockClientImpl) SayHelloRightLater(ctx context.Context, word string, delay int) (string, error) {
+	m.invokeCount++
+	if delay == m.invokeCount {
+		fmt.Println("invoke right")
+		return word, nil
+	}
+	fmt.Println("invoke fail")
+	return "", errors.New("invoke failed")
+}
+
+func TestGRPCInvokerInvokeSucceedWithOutRetry(t *testing.T) {
+	ctx := context.Background()
+	invoker := newGRPCServiceInvoker()
+	values, err := invoker.Invoke(ctx, []any{"hello"}, newHelloServiceTaskState())
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if values == nil || len(values) == 0 {
+		t.Error("no value in values")
+		return
+	}
+	if values[0].Interface().(string) != "hello" {
+		t.Errorf("expect hello, but got %v", values[0].Interface())
+	}
+	if _, ok := values[1].Interface().(error); ok {
+		t.Errorf("expect nil, but got %v", values[1].Interface())
+	}
+}
+
+func TestGRPCInvokerInvokeSucceedInRetry(t *testing.T) {
+	ctx := context.Background()
+	invoker := newGRPCServiceInvoker()
+	values, err := invoker.Invoke(ctx, []any{"hello", 2}, newHelloServiceTaskStateWithRetry())
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if values == nil || len(values) == 0 {
+		t.Error("no value in values")
+		return
+	}
+	if values[0].Interface().(string) != "hello" {
+		t.Errorf("expect hello, but got %v", values[0].Interface())
+	}
+	if _, ok := values[1].Interface().(error); ok {
+		t.Errorf("expect nil, but got %v", values[1].Interface())
+	}
+}
+
+func TestGRPCInvokerInvokeFailedInRetry(t *testing.T) {
+	ctx := context.Background()
+	invoker := newGRPCServiceInvoker()
+	_, err := invoker.Invoke(ctx, []any{"hello", 5}, newHelloServiceTaskStateWithRetry())
+	if err != nil {
+		assert.Error(t, err)
+	}
+}
+
+func TestGRPCInvokerInvokeE2E(t *testing.T) {
+	go func() {
+		pb.StartProductServer()
+	}()
+	time.Sleep(3000 * time.Millisecond)
+	conn, err := grpc.Dial("localhost:8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		t.Fatalf("did not connect: %v", err)
+	}
+	c := pb.NewProductInfoClient(conn)
+	grpcClient := NewGRPCClient("product", c, conn)
+
+	invoker := NewGRPCInvoker()
+	invoker.RegisterClient("product", grpcClient)
+	ctx := context.Background()
+	values, err := invoker.Invoke(ctx, []any{&pb.Product{Id: "123"}}, newProductServiceTaskState())
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	t.Log(values)
+	err = invoker.Close(ctx)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+}
+
+func newGRPCServiceInvoker() ServiceInvoker {
+	mockGRPCInvoker := NewGRPCInvoker()
+	mockGRPCClient := &mockClientImpl{}
+	mockClient := NewGRPCClient("hello", mockGRPCClient, &grpc.ClientConn{})
+	mockGRPCInvoker.RegisterClient("hello", mockClient)
+	return mockGRPCInvoker
+}
+
+func newProductServiceTaskState() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("product")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("product")
+	serviceTaskStateImpl.SetServiceType("GRPC")
+	serviceTaskStateImpl.SetServiceMethod("AddProduct")
+
+	retryImpl := &state.RetryImpl{}
+	retryImpl.SetExceptions([]string{"fail"})
+	retryImpl.SetIntervalSecond(1)
+	retryImpl.SetMaxAttempt(3)
+	retryImpl.SetBackoffRate(0.9)
+	serviceTaskStateImpl.SetRetry([]state.Retry{retryImpl})
+	return serviceTaskStateImpl
+}
+
+func newHelloServiceTaskState() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("hello")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("hello")
+	serviceTaskStateImpl.SetServiceType("GRPC")
+	serviceTaskStateImpl.SetServiceMethod("SayHelloRight")
+	return serviceTaskStateImpl
+}
+
+func newHelloServiceTaskStateWithRetry() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("hello")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("hello")
+	serviceTaskStateImpl.SetServiceType("GRPC")
+	serviceTaskStateImpl.SetServiceMethod("SayHelloRightLater")
+
+	retryImpl := &state.RetryImpl{}
+	retryImpl.SetExceptions([]string{"fail"})
+	retryImpl.SetIntervalSecond(1)
+	retryImpl.SetMaxAttempt(3)
+	retryImpl.SetBackoffRate(0.9)
+	serviceTaskStateImpl.SetRetry([]state.Retry{retryImpl})
+	return serviceTaskStateImpl
+}
diff --git a/pkg/saga/statemachine/engine/invoker/http_invoker.go b/pkg/saga/statemachine/engine/invoker/http_invoker.go
new file mode 100644
index 00000000..c172aaa7
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/http_invoker.go
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"net/http"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+const errHttpCode = 400
+
+type HTTPInvoker struct {
+	clientsMapLock sync.Mutex
+	clients        map[string]HTTPClient
+}
+
+func NewHTTPInvoker() *HTTPInvoker {
+	return &HTTPInvoker{
+		clients: make(map[string]HTTPClient),
+	}
+}
+
+func (h *HTTPInvoker) RegisterClient(serviceName string, client HTTPClient) {
+	h.clientsMapLock.Lock()
+	defer h.clientsMapLock.Unlock()
+	h.clients[serviceName] = client
+}
+
+func (h *HTTPInvoker) GetClient(serviceName string) HTTPClient {
+	h.clientsMapLock.Lock()
+	defer h.clientsMapLock.Unlock()
+	return h.clients[serviceName]
+}
+
+func (h *HTTPInvoker) Invoke(ctx context.Context, input []any, service state.ServiceTaskState) (output []reflect.Value, err error) {
+	serviceTaskStateImpl := service.(*state.ServiceTaskStateImpl)
+	client := h.GetClient(serviceTaskStateImpl.ServiceName())
+	if client == nil {
+		return nil, fmt.Errorf("no http client %s for service task state", serviceTaskStateImpl.ServiceName())
+	}
+
+	if serviceTaskStateImpl.IsAsync() {
+		go func() {
+			_, err := client.Call(ctx, serviceTaskStateImpl, input)
+			if err != nil {
+				log.Errorf("invoke Service[%s].%s failed, err is %s", serviceTaskStateImpl.ServiceName(),
+					serviceTaskStateImpl.ServiceMethod(), err)
+			}
+		}()
+		return nil, nil
+	}
+
+	return client.Call(ctx, serviceTaskStateImpl, input)
+}
+
+func (h *HTTPInvoker) Close(ctx context.Context) error {
+	return nil
+}
+
+type HTTPClient interface {
+	Call(ctx context.Context, serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error)
+}
+
+type HTTPClientImpl struct {
+	serviceName string
+	baseURL     string
+	client      *http.Client
+}
+
+func NewHTTPClient(serviceName string, baseURL string, client *http.Client) *HTTPClientImpl {
+	if client == nil {
+		client = &http.Client{
+			Timeout: time.Second * 30,
+		}
+	}
+	return &HTTPClientImpl{
+		serviceName: serviceName,
+		baseURL:     baseURL,
+		client:      client,
+	}
+}
+
+func (h *HTTPClientImpl) Call(ctx context.Context, serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error) {
+	retryCountMap := make(map[state.Retry]int)
+	for {
+		res, err, shouldRetry := func() (res []reflect.Value, resErr error, shouldRetry bool) {
+			defer func() {
+				if r := recover(); r != nil {
+					errStr := fmt.Sprintf("%v", r)
+					retry := h.matchRetry(serviceTaskStateImpl, errStr)
+					resErr = errors.New(errStr)
+					if retry != nil {
+						shouldRetry = h.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
+					}
+				}
+			}()
+
+			reqBody, err := json.Marshal(input)
+			if err != nil {
+				return nil, err, false
+			}
+
+			req, err := http.NewRequestWithContext(ctx,
+				serviceTaskStateImpl.ServiceMethod(),
+				h.baseURL+serviceTaskStateImpl.Name(),
+				bytes.NewBuffer(reqBody))
+			if err != nil {
+				return nil, err, false
+			}
+
+			req.Header.Set("Content-Type", "application/json")
+
+			resp, err := h.client.Do(req)
+			if err != nil {
+				retry := h.matchRetry(serviceTaskStateImpl, err.Error())
+				if retry != nil {
+					return nil, err, h.needRetry(serviceTaskStateImpl, retryCountMap, retry, err)
+				}
+				return nil, err, false
+			}
+			defer resp.Body.Close()
+
+			body, err := io.ReadAll(resp.Body)
+			if err != nil {
+				return nil, err, false
+			}
+
+			if resp.StatusCode >= errHttpCode {
+				errStr := fmt.Sprintf("HTTP error: %d - %s", resp.StatusCode, string(body))
+				retry := h.matchRetry(serviceTaskStateImpl, errStr)
+				if retry != nil {
+					return nil, errors.New(errStr), h.needRetry(serviceTaskStateImpl, retryCountMap, retry, err)
+				}
+				return nil, errors.New(errStr), false
+			}
+
+			return []reflect.Value{
+				reflect.ValueOf(string(body)),
+				reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()),
+			}, nil, false
+		}()
+
+		if !shouldRetry {
+			if err != nil {
+				return nil, fmt.Errorf("invoke Service[%s] failed, not satisfy retry config, the last err is %s",
+					serviceTaskStateImpl.ServiceName(), err)
+			}
+			return res, nil
+		}
+	}
+}
+
+func (h *HTTPClientImpl) matchRetry(impl *state.ServiceTaskStateImpl, str string) state.Retry {
+	if impl.Retry() != nil {
+		for _, retry := range impl.Retry() {
+			if retry.Exceptions() != nil {
+				for _, exception := range retry.Exceptions() {
+					if strings.Contains(str, exception) {
+						return retry
+					}
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func (h *HTTPClientImpl) needRetry(impl *state.ServiceTaskStateImpl, countMap map[state.Retry]int, retry state.Retry, err error) bool {
+	attempt, exist := countMap[retry]
+	if !exist {
+		countMap[retry] = 0
+	}
+
+	if attempt >= retry.MaxAttempt() {
+		return false
+	}
+
+	intervalSecond := retry.IntervalSecond()
+	backoffRate := retry.BackoffRate()
+	var currentInterval int64
+	if attempt == 0 {
+		currentInterval = int64(intervalSecond * 1000)
+	} else {
+		currentInterval = int64(intervalSecond * backoffRate * float64(attempt) * 1000)
+	}
+
+	log.Warnf("invoke service[%s.%s] failed, will retry after %s millis, current retry count: %s, current err: %s",
+		impl.ServiceName(), impl.ServiceMethod(), currentInterval, attempt, err)
+
+	time.Sleep(time.Duration(currentInterval) * time.Millisecond)
+	countMap[retry] = attempt + 1
+	return true
+}
diff --git a/pkg/saga/statemachine/engine/invoker/http_invoker_test.go b/pkg/saga/statemachine/engine/invoker/http_invoker_test.go
new file mode 100644
index 00000000..a5288cb5
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/http_invoker_test.go
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"sync/atomic"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+func TestHTTPInvokerInvokeSucceedWithOutRetry(t *testing.T) {
+	// create test server
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		var input []interface{}
+		err := json.NewDecoder(r.Body).Decode(&input)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusBadRequest)
+			return
+		}
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(input[0].(string)))
+	}))
+	defer server.Close()
+
+	// create HTTP Invoker
+	invoker := NewHTTPInvoker()
+	client := NewHTTPClient("test", server.URL+"/", &http.Client{})
+	invoker.RegisterClient("test", client)
+
+	// invoke
+	ctx := context.Background()
+	values, err := invoker.Invoke(ctx, []any{"hello"}, newHTTPServiceTaskState())
+
+	// verify
+	assert.NoError(t, err)
+	assert.NotNil(t, values)
+	assert.Equal(t, "hello", values[0].Interface())
+}
+
+func TestHTTPInvokerInvokeWithRetry(t *testing.T) {
+	attemptCount := 0
+	// create test server
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		attemptCount++
+		if attemptCount < 2 {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("fail"))
+			return
+		}
+		var input []interface{}
+		json.NewDecoder(r.Body).Decode(&input)
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(input[0].(string)))
+	}))
+	defer server.Close()
+
+	// create HTTP Invoker
+	invoker := NewHTTPInvoker()
+	client := NewHTTPClient("test", server.URL+"/", &http.Client{})
+	invoker.RegisterClient("test", client)
+
+	// invoker
+	ctx := context.Background()
+	values, err := invoker.Invoke(ctx, []any{"hello"}, newHTTPServiceTaskStateWithRetry())
+
+	// verify
+	assert.NoError(t, err)
+	assert.NotNil(t, values)
+	assert.Equal(t, "hello", values[0].Interface())
+	assert.Equal(t, 2, attemptCount)
+}
+
+func TestHTTPInvokerInvokeFailedInRetry(t *testing.T) {
+	// create test server
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("fail"))
+	}))
+	defer server.Close()
+
+	// create HTTP Invoker
+	invoker := NewHTTPInvoker()
+	client := NewHTTPClient("test", server.URL+"/", &http.Client{})
+	invoker.RegisterClient("test", client)
+
+	// invoker
+	ctx := context.Background()
+	_, err := invoker.Invoke(ctx, []any{"hello"}, newHTTPServiceTaskStateWithRetry())
+
+	// verify
+	assert.Error(t, err)
+}
+
+func TestHTTPInvokerAsyncInvoke(t *testing.T) {
+	var called atomic.Bool
+	// create test server
+	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		called.Store(true)
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte("success"))
+	}))
+	defer server.Close()
+
+	// create HTTP Invoker
+	invoker := NewHTTPInvoker()
+	client := NewHTTPClient("test", server.URL+"/", &http.Client{})
+	invoker.RegisterClient("test", client)
+
+	// async invoke
+	ctx := context.Background()
+	taskState := newHTTPServiceTaskStateWithAsync()
+	_, err := invoker.Invoke(ctx, []any{"hello"}, taskState)
+
+	// verify
+	assert.NoError(t, err)
+	assert.Eventually(t, func() bool {
+		return called.Load()
+	}, 500*time.Millisecond, 10*time.Millisecond)
+}
+
+func newHTTPServiceTaskState() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("test")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("test")
+	serviceTaskStateImpl.SetServiceType("HTTP")
+	serviceTaskStateImpl.SetServiceMethod("POST")
+	return serviceTaskStateImpl
+}
+
+func newHTTPServiceTaskStateWithAsync() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("test")
+	serviceTaskStateImpl.SetIsAsync(true)
+	serviceTaskStateImpl.SetServiceName("test")
+	serviceTaskStateImpl.SetServiceType("HTTP")
+	serviceTaskStateImpl.SetServiceMethod("POST")
+	return serviceTaskStateImpl
+}
+
+func newHTTPServiceTaskStateWithRetry() state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName("test")
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName("test")
+	serviceTaskStateImpl.SetServiceType("HTTP")
+	serviceTaskStateImpl.SetServiceMethod("POST")
+
+	retryImpl := &state.RetryImpl{}
+	retryImpl.SetExceptions([]string{"fail"})
+	retryImpl.SetIntervalSecond(1)
+	retryImpl.SetMaxAttempt(3)
+	retryImpl.SetBackoffRate(0.9)
+	serviceTaskStateImpl.SetRetry([]state.Retry{retryImpl})
+	return serviceTaskStateImpl
+}
diff --git a/pkg/saga/statemachine/engine/invoker/invoker.go b/pkg/saga/statemachine/engine/invoker/invoker.go
new file mode 100644
index 00000000..1f5403c0
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/invoker.go
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+type ServiceInvokerManager interface {
+	ServiceInvoker(serviceType string) ServiceInvoker
+	PutServiceInvoker(serviceType string, invoker ServiceInvoker)
+}
+
+type ServiceInvoker interface {
+	Invoke(ctx context.Context, input []any, service state.ServiceTaskState) (output []reflect.Value, err error)
+	Close(ctx context.Context) error
+}
+
+// ScriptInvoker 脚本调用器接口
+type ScriptInvoker interface {
+	Type() string
+	Invoke(ctx context.Context, script string, params map[string]interface{}) (interface{}, error)
+	Close(ctx context.Context) error
+}
+
+// ScriptInvokerManager 脚本调用器管理器
+type ScriptInvokerManager interface {
+	GetInvoker(scriptType string) (ScriptInvoker, error)
+	RegisterInvoker(invoker ScriptInvoker) error
+}
+
+type ScriptInvokerManagerImpl struct {
+	invokers map[string]ScriptInvoker
+	mutex    sync.RWMutex
+}
+
+func NewScriptInvokerManager() ScriptInvokerManager {
+	return &ScriptInvokerManagerImpl{invokers: make(map[string]ScriptInvoker)}
+}
+
+func (manager *ScriptInvokerManagerImpl) GetInvoker(scriptType string) (ScriptInvoker, error) {
+	manager.mutex.RLock()
+	defer manager.mutex.RUnlock()
+
+	invoker := manager.invokers[scriptType]
+	if invoker == nil {
+		return nil, fmt.Errorf("script invoker %s not found", scriptType)
+	}
+	return invoker, nil
+}
+
+func (manager *ScriptInvokerManagerImpl) RegisterInvoker(invoker ScriptInvoker) error {
+	if invoker == nil {
+		return fmt.Errorf("script invoker is nil")
+	}
+	manager.mutex.Lock()
+	defer manager.mutex.Unlock()
+	manager.invokers[invoker.Type()] = invoker
+	return nil
+}
+
+type ServiceInvokerManagerImpl struct {
+	invokers map[string]ServiceInvoker
+	mutex    sync.Mutex
+}
+
+func NewServiceInvokerManagerImpl() *ServiceInvokerManagerImpl {
+	return &ServiceInvokerManagerImpl{
+		invokers: make(map[string]ServiceInvoker),
+	}
+}
+
+func (manager *ServiceInvokerManagerImpl) ServiceInvoker(serviceType string) ServiceInvoker {
+	return manager.invokers[serviceType]
+}
+
+func (manager *ServiceInvokerManagerImpl) PutServiceInvoker(serviceType string, invoker ServiceInvoker) {
+	manager.mutex.Lock()
+	defer manager.mutex.Unlock()
+	manager.invokers[serviceType] = invoker
+}
diff --git a/pkg/saga/statemachine/engine/invoker/javascript_script_invoker.go b/pkg/saga/statemachine/engine/invoker/javascript_script_invoker.go
new file mode 100644
index 00000000..7817494d
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/javascript_script_invoker.go
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"fmt"
+	"sync"
+
+	"github.com/robertkrimen/otto"
+)
+
+const defaultPoolSize = 10
+
+type JavaScriptScriptInvoker struct {
+	mutex      sync.Mutex
+	jsonParser JsonParser
+	closed     bool
+	vmPool     chan *otto.Otto
+	poolSize   int
+}
+
+func NewJavaScriptScriptInvoker() *JavaScriptScriptInvoker {
+	return &JavaScriptScriptInvoker{
+		jsonParser: &DefaultJsonParser{},
+		closed:     false,
+		poolSize:   defaultPoolSize,
+		vmPool:     make(chan *otto.Otto, defaultPoolSize),
+	}
+}
+
+func NewJavaScriptScriptInvokerWithPoolSize(poolSize int) *JavaScriptScriptInvoker {
+	if poolSize <= 0 {
+		poolSize = defaultPoolSize
+	}
+	return &JavaScriptScriptInvoker{
+		jsonParser: &DefaultJsonParser{},
+		closed:     false,
+		poolSize:   poolSize,
+		vmPool:     make(chan *otto.Otto, poolSize),
+	}
+}
+
+func (j *JavaScriptScriptInvoker) Type() string {
+	return "javascript"
+}
+
+func (j *JavaScriptScriptInvoker) Invoke(ctx context.Context, script string, params map[string]interface{}) (interface{}, error) {
+	j.mutex.Lock()
+	closed := j.closed
+	j.mutex.Unlock()
+
+	if closed {
+		return nil, fmt.Errorf("javascript invoker has been closed")
+	}
+
+	var vm *otto.Otto
+	select {
+	case vm = <-j.vmPool:
+		if err := cleanVMState(vm); err != nil {
+			vm = otto.New()
+		}
+	default:
+		vm = otto.New()
+	}
+
+	defer func() {
+		j.mutex.Lock()
+		defer j.mutex.Unlock()
+		if !j.closed {
+			select {
+			case j.vmPool <- vm:
+			default:
+				// Pool full, discard current instance
+			}
+		}
+	}()
+
+	for key, value := range params {
+		if err := vm.Set(key, value); err != nil {
+			return nil, fmt.Errorf("javascript set param %s error: %w", key, err)
+		}
+	}
+
+	resultChan := make(chan struct {
+		val otto.Value
+		err error
+	}, 1)
+
+	go func() {
+		defer func() {
+			if r := recover(); r != nil {
+				resultChan <- struct {
+					val otto.Value
+					err error
+				}{otto.UndefinedValue(), fmt.Errorf("javascript engine panic: %v", r)}
+			}
+		}()
+
+		val, err := vm.Run(script)
+		resultChan <- struct {
+			val otto.Value
+			err error
+		}{val, err}
+	}()
+
+	select {
+	case <-ctx.Done():
+		return nil, fmt.Errorf("javascript execution timeout: %w", ctx.Err())
+	case res := <-resultChan:
+		if res.err != nil {
+			return nil, fmt.Errorf("javascript execute error: %w", res.err)
+		}
+		val, err := res.val.Export()
+		if err != nil {
+			return nil, fmt.Errorf("failed to export javascript result: %w", err)
+		}
+		return val, nil
+	}
+}
+
+func (j *JavaScriptScriptInvoker) Close(ctx context.Context) error {
+	j.mutex.Lock()
+	defer j.mutex.Unlock()
+
+	if j.closed {
+		return nil
+	}
+
+	j.closed = true
+	close(j.vmPool)
+	for range j.vmPool {
+		// Let GC recycle VM resources
+	}
+	return nil
+}
+
+func cleanVMState(vm *otto.Otto) error {
+	_, err := vm.Run(`
+		for (const prop in global) {
+			if (!['Object', 'Array', 'Function', 'String', 'Number', 'Boolean', 'JSON', 'Date', 'RegExp'].includes(prop)) {
+				delete global[prop];
+			}
+		}
+	`)
+	return err
+}
diff --git a/pkg/saga/statemachine/engine/invoker/javascript_script_invoker_test.go b/pkg/saga/statemachine/engine/invoker/javascript_script_invoker_test.go
new file mode 100644
index 00000000..e41d1e5c
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/javascript_script_invoker_test.go
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"sync"
+	"testing"
+	"time"
+
+	"github.com/robertkrimen/otto"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJavaScriptScriptInvoker_Type(t *testing.T) {
+	invoker := NewJavaScriptScriptInvoker()
+	assert.Equal(t, "javascript", invoker.Type())
+}
+
+func TestJavaScriptScriptInvoker_Invoke_Basic(t *testing.T) {
+	tests := []struct {
+		name     string
+		script   string
+		params   map[string]interface{}
+		expected interface{}
+	}{
+		{
+			name:     "simple expression",
+			script:   "1 + 2",
+			params:   nil,
+			expected: float64(3),
+		},
+		{
+			name:     "param calculation",
+			script:   "a * b + c",
+			params:   map[string]interface{}{"a": 2, "b": 3, "c": 4},
+			expected: float64(10),
+		},
+		{
+			name:     "return string",
+			script:   "['hello', name].join(' ')",
+			params:   map[string]interface{}{"name": "world"},
+			expected: "hello world",
+		},
+		{
+			name:     "return object",
+			script:   `var obj = {id: 1, name: name}; obj;`,
+			params:   map[string]interface{}{"name": "test"},
+			expected: map[string]interface{}{"id": float64(1), "name": "test"},
+		},
+	}
+
+	invoker := NewJavaScriptScriptInvoker()
+	ctx := context.Background()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result, err := invoker.Invoke(ctx, tt.script, tt.params)
+			assert.NoError(t, err)
+
+			if resultMap, ok := result.(map[string]interface{}); ok {
+				for k, v := range resultMap {
+					if intVal, isInt := v.(int64); isInt {
+						resultMap[k] = float64(intVal)
+					}
+				}
+			}
+
+			assert.Equal(t, tt.expected, result)
+		})
+	}
+}
+
+func TestJavaScriptScriptInvoker_Invoke_Error(t *testing.T) {
+	tests := []struct {
+		name   string
+		script string
+		params map[string]interface{}
+		errMsg string
+	}{
+		{
+			name:   "syntax error",
+			script: "1 + ",
+			params: nil,
+			errMsg: "javascript execute error",
+		},
+		{
+			name:   "reference undefined variable",
+			script: "undefinedVar",
+			params: nil,
+			errMsg: "javascript execute error",
+		},
+	}
+
+	invoker := NewJavaScriptScriptInvoker()
+	ctx := context.Background()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			_, err := invoker.Invoke(ctx, tt.script, tt.params)
+
+			if err == nil {
+				t.Fatalf("Test case [%s] expected error but got none", tt.name)
+			}
+			assert.Contains(t, err.Error(), tt.errMsg, "Test case [%s] error message mismatch", tt.name)
+		})
+	}
+}
+
+func TestJavaScriptScriptInvoker_Invoke_Timeout(t *testing.T) {
+
+	script := `var target = 300; var start = new Date().getTime(); var elapsed = 0; while (elapsed < target) { elapsed = new Date().getTime() - start; } "done";`
+	invoker := NewJavaScriptScriptInvoker()
+
+	ctx1, cancel1 := context.WithTimeout(context.Background(), 200*time.Millisecond)
+	defer cancel1()
+	_, err := invoker.Invoke(ctx1, script, nil)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "javascript execution timeout")
+
+	ctx2, cancel2 := context.WithTimeout(context.Background(), 400*time.Millisecond)
+	defer cancel2()
+	result, err := invoker.Invoke(ctx2, script, nil)
+	assert.NoError(t, err, "Scenario 2: script execution should not return error")
+	assert.Equal(t, "done", result, "Scenario 2: should return 'done'")
+}
+
+func TestJavaScriptScriptInvoker_Invoke_Concurrent(t *testing.T) {
+	invoker := NewJavaScriptScriptInvoker()
+	ctx := context.Background()
+	var wg sync.WaitGroup
+	concurrency := 100
+	errChan := make(chan error, concurrency)
+
+	script := `a + b`
+	params := map[string]interface{}{"a": 10, "b": 20}
+
+	for i := 0; i < concurrency; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			result, err := invoker.Invoke(ctx, script, params)
+			if err != nil {
+				errChan <- err
+				return
+			}
+			if result != float64(30) {
+				errChan <- assert.AnError
+			}
+		}()
+	}
+
+	wg.Wait()
+	close(errChan)
+
+	assert.Empty(t, errChan, "Concurrent execution has errors")
+}
+
+func TestJavaScriptScriptInvoker_Close(t *testing.T) {
+	invoker := NewJavaScriptScriptInvoker()
+	ctx := context.Background()
+
+	result, err := invoker.Invoke(ctx, "1 + 1", nil)
+	assert.NoError(t, err)
+	assert.Equal(t, float64(2), result)
+
+	err = invoker.Close(ctx)
+	assert.NoError(t, err)
+
+	_, err = invoker.Invoke(ctx, "1 + 1", nil)
+	assert.Error(t, err)
+	assert.Contains(t, err.Error(), "javascript invoker has been closed")
+}
+
+func TestOttoScript(t *testing.T) {
+	vm := otto.New()
+	script := `var target = 300; var start = new Date().getTime(); var elapsed = 0; while (elapsed < target) { elapsed = new Date().getTime() - start; } "done";`
+	val, err := vm.Run(script)
+	if err != nil {
+		t.Fatalf("otto failed to parse script: %v", err)
+	}
+
+	result, exportErr := val.Export()
+	if exportErr != nil {
+		t.Fatalf("failed to export otto value: %v", exportErr)
+	}
+	t.Logf("Script execution result: %v", result)
+}
+
+func TestJavaScriptScriptInvoker_VMPoolReuse(t *testing.T) {
+	poolSize := 2
+	invoker := NewJavaScriptScriptInvokerWithPoolSize(poolSize)
+	ctx := context.Background()
+
+	vmIDs := make([]string, 0, 5)
+
+	script := `
+		if (!this.vmId) {
+			this.vmId = Math.random().toString(36).substr(2, 8); 
+		}
+		this.vmId;
+	`
+
+	for i := 0; i < 5; i++ {
+		result, err := invoker.Invoke(ctx, script, nil)
+		assert.NoError(t, err, "Error occurred while executing script")
+
+		id, ok := result.(string)
+		assert.True(t, ok, "VM ID should be a string type")
+		vmIDs = append(vmIDs, id)
+	}
+
+	uniqueIDs := make(map[string]bool)
+	for _, id := range vmIDs {
+		uniqueIDs[id] = true
+	}
+
+	assert.True(t, len(uniqueIDs) <= 5, "Abnormal number of VM instances created")
+	assert.True(t, len(uniqueIDs) >= 1, "No VM instances reused from the pool")
+}
+
+func TestJavaScriptScriptInvoker_VMStateClean(t *testing.T) {
+	invoker := NewJavaScriptScriptInvokerWithPoolSize(1)
+	ctx := context.Background()
+
+	_, err := invoker.Invoke(ctx, `this.foo = "polluted data"`, nil)
+	assert.NoError(t, err)
+
+	result, err := invoker.Invoke(ctx, `typeof this.foo`, nil)
+	assert.NoError(t, err)
+	assert.Equal(t, "undefined", result, "VM state not cleaned, residual global variable exists")
+
+	_, err = invoker.Invoke(ctx, `this.bar = function() { return "residual function"; }`, nil)
+	assert.NoError(t, err)
+
+	result, err = invoker.Invoke(ctx, `typeof this.bar`, nil)
+	assert.NoError(t, err)
+	assert.Equal(t, "undefined", result, "VM state not cleaned, residual function exists")
+}
+
+func TestJavaScriptScriptInvoker_PoolSizeDefault(t *testing.T) {
+	invoker := NewJavaScriptScriptInvokerWithPoolSize(0)
+	assert.Equal(t, defaultPoolSize, invoker.poolSize, "Default pool size not used when pool size is 0")
+
+	invoker = NewJavaScriptScriptInvokerWithPoolSize(-5)
+	assert.Equal(t, defaultPoolSize, invoker.poolSize, "Default pool size not used when pool size is negative")
+}
diff --git a/pkg/rm/init.go b/pkg/saga/statemachine/engine/invoker/json_parser.go
similarity index 61%
copy from pkg/rm/init.go
copy to pkg/saga/statemachine/engine/invoker/json_parser.go
index 469cdfaa..d51bdcf2 100644
--- a/pkg/rm/init.go
+++ b/pkg/saga/statemachine/engine/invoker/json_parser.go
@@ -15,18 +15,23 @@
  * limitations under the License.
  */
 
-package rm
+package invoker
 
-var rmConfig RmConfig
+import "encoding/json"
 
-type RmConfig struct {
-	Config
+// JsonParser 抽象 JSON 序列化接口,便于后续替换实现
+type JsonParser interface {
+	Marshal(v interface{}) ([]byte, error)
+	Unmarshal(data []byte, v interface{}) error
+}
+
+// DefaultJsonParser 默认使用标准库 json
+type DefaultJsonParser struct{}
 
-	ApplicationID  string
-	TxServiceGroup string
+func (p *DefaultJsonParser) Marshal(v interface{}) ([]byte, error) {
+	return json.Marshal(v)
 }
 
-// InitRmClient init seata rm client
-func InitRm(cfg RmConfig) {
-	rmConfig = cfg
+func (p *DefaultJsonParser) Unmarshal(data []byte, v interface{}) error {
+	return json.Unmarshal(data, v)
 }
diff --git a/pkg/saga/statemachine/engine/invoker/local_invoker.go b/pkg/saga/statemachine/engine/invoker/local_invoker.go
new file mode 100644
index 00000000..656b2f91
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/local_invoker.go
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"fmt"
+	"reflect"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+type LocalServiceInvoker struct {
+	serviceRegistry map[string]interface{}
+	methodCache     map[string]*reflect.Method
+	jsonParser      JsonParser
+	mutex           sync.RWMutex
+}
+
+func NewLocalServiceInvoker() *LocalServiceInvoker {
+	return &LocalServiceInvoker{
+		serviceRegistry: make(map[string]interface{}),
+		methodCache:     make(map[string]*reflect.Method),
+		jsonParser:      &DefaultJsonParser{},
+	}
+}
+
+func (l *LocalServiceInvoker) RegisterService(serviceName string, instance interface{}) {
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+	l.serviceRegistry[serviceName] = instance
+}
+
+func (l *LocalServiceInvoker) Invoke(ctx context.Context, input []any, service state.ServiceTaskState) ([]reflect.Value, error) {
+	serviceName := service.ServiceName()
+	instance, exists := l.serviceRegistry[serviceName]
+	if !exists {
+		return nil, fmt.Errorf("service %s not registered", serviceName)
+	}
+
+	methodName := service.ServiceMethod()
+	method, err := l.getMethod(serviceName, methodName, service.ParameterTypes())
+	if err != nil {
+		return nil, err
+	}
+
+	params, err := l.resolveParameters(input, method.Type)
+	if err != nil {
+		return nil, err
+	}
+
+	return l.invokeMethod(instance, method, params), nil
+}
+
+func (l *LocalServiceInvoker) resolveMethod(key, serviceName, methodName string) (*reflect.Method, error) {
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+
+	if cachedMethod, ok := l.methodCache[key]; ok {
+		return cachedMethod, nil
+	}
+
+	instance, exists := l.serviceRegistry[serviceName]
+	if !exists {
+		return nil, fmt.Errorf("service %s not found", serviceName)
+	}
+
+	objType := reflect.TypeOf(instance)
+	method, ok := objType.MethodByName(methodName)
+	if !ok {
+		return nil, fmt.Errorf("method %s not found in service %s", methodName, serviceName)
+	}
+
+	l.methodCache[key] = &method
+	return &method, nil
+}
+
+func (l *LocalServiceInvoker) getMethod(serviceName, methodName string, paramTypes []string) (*reflect.Method, error) {
+	key := fmt.Sprintf("%s.%s", serviceName, methodName)
+
+	l.mutex.RLock()
+	if method, ok := l.methodCache[key]; ok {
+		l.mutex.RUnlock()
+		return method, nil
+	}
+	l.mutex.RUnlock()
+
+	return l.resolveMethod(key, serviceName, methodName)
+}
+
+func (l *LocalServiceInvoker) resolveParameters(input []any, methodType reflect.Type) ([]reflect.Value, error) {
+	argTotal := methodType.NumIn()
+	if argTotal == 0 {
+		return nil, nil
+	}
+
+	argCount := argTotal - 1 // skip receiver
+	if argCount <= 0 {
+		return nil, nil
+	}
+
+	params := make([]reflect.Value, argCount)
+	for i := 0; i < argCount; i++ {
+		paramType := methodType.In(i + 1)
+		if i >= len(input) {
+			params[i] = reflect.Zero(paramType)
+			continue
+		}
+
+		converted, err := l.convertParam(input[i], paramType)
+		if err != nil {
+			return nil, fmt.Errorf("parameter %d conversion error: %w", i, err)
+		}
+
+		val := reflect.ValueOf(converted)
+		if !val.IsValid() {
+			params[i] = reflect.Zero(paramType)
+			continue
+		}
+		if val.Type().AssignableTo(paramType) {
+			params[i] = val
+			continue
+		}
+		if val.Type().ConvertibleTo(paramType) {
+			params[i] = val.Convert(paramType)
+			continue
+		}
+		params[i] = reflect.Zero(paramType)
+	}
+
+	return params, nil
+}
+
+func (l *LocalServiceInvoker) convertParam(value any, targetType reflect.Type) (any, error) {
+	if targetType.Kind() == reflect.Ptr {
+		elemType := targetType.Elem()
+		instance := reflect.New(elemType).Interface()
+		jsonData, err := l.jsonParser.Marshal(value)
+		if err != nil {
+			return nil, err
+		}
+		if err := l.jsonParser.Unmarshal(jsonData, instance); err != nil {
+			return nil, err
+		}
+		return instance, nil
+	}
+
+	if targetType.Kind() == reflect.Struct {
+		instance := reflect.New(targetType).Interface()
+		jsonData, err := l.jsonParser.Marshal(value)
+		if err != nil {
+			return nil, err
+		}
+		if err := l.jsonParser.Unmarshal(jsonData, instance); err != nil {
+			return nil, err
+		}
+		return reflect.ValueOf(instance).Elem().Interface(), nil
+	}
+
+	if targetType.Kind() == reflect.Int && reflect.TypeOf(value).Kind() == reflect.Float64 {
+		return int(value.(float64)), nil
+	} else if targetType == reflect.TypeOf("") && reflect.TypeOf(value).Kind() == reflect.Int {
+		return fmt.Sprintf("%d", value), nil
+	}
+
+	return value, nil
+}
+
+func (l *LocalServiceInvoker) invokeMethod(instance interface{}, method *reflect.Method, params []reflect.Value) []reflect.Value {
+	instanceValue := reflect.ValueOf(instance)
+	if method.Func.IsValid() {
+		allParams := append([]reflect.Value{instanceValue}, params...)
+		return method.Func.Call(allParams)
+	}
+	return nil
+}
+
+func (l *LocalServiceInvoker) Close(ctx context.Context) error {
+	l.mutex.Lock()
+	defer l.mutex.Unlock()
+	l.serviceRegistry = nil
+	l.methodCache = nil
+	return nil
+}
diff --git a/pkg/saga/statemachine/engine/invoker/local_invoker_test.go b/pkg/saga/statemachine/engine/invoker/local_invoker_test.go
new file mode 100644
index 00000000..9cc1afd3
--- /dev/null
+++ b/pkg/saga/statemachine/engine/invoker/local_invoker_test.go
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package invoker
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"reflect"
+	"testing"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+type MockLocalService struct {
+	invokeCount int
+}
+
+func (m *MockLocalService) GetServiceName() string {
+	return "MockLocalService"
+}
+
+func (m *MockLocalService) Add(a, b int) int {
+	m.invokeCount++
+	return a + b
+}
+
+func (m *MockLocalService) Multiply(f float64, i int) float64 {
+	m.invokeCount++
+	return f * float64(i)
+}
+
+type User struct {
+	Name string `json:"name"`
+	Age  int    `json:"age"`
+}
+
+func (m *MockLocalService) GetUserName(user User) string {
+	m.invokeCount++
+	return user.Name
+}
+
+func (m *MockLocalService) ErrorMethod() error {
+	return errors.New("expected error")
+}
+
+func TestLocalInvoker_ServiceNotRegistered(t *testing.T) {
+	invoker := NewLocalServiceInvoker()
+	ctx := context.Background()
+	taskState := newLocalServiceTaskState("unregisteredService", "AnyMethod")
+
+	_, err := invoker.Invoke(ctx, []any{}, taskState)
+	if err == nil {
+		t.Error("expected error when service not registered, but got nil")
+	}
+	if err.Error() != "service unregisteredService not registered" {
+		t.Errorf("unexpected error message: %v", err)
+	}
+}
+
+func TestLocalInvoker_MethodNotFound(t *testing.T) {
+	invoker := NewLocalServiceInvoker()
+	service := &MockLocalService{}
+	invoker.RegisterService("mockService", service)
+
+	ctx := context.Background()
+	taskState := newLocalServiceTaskState("mockService", "NonExistentMethod")
+
+	_, err := invoker.Invoke(ctx, []any{}, taskState)
+	if err == nil {
+		t.Error("expected error when method not found, but got nil")
+	}
+	if err.Error() != "method NonExistentMethod not found in service mockService" {
+		t.Errorf("unexpected error message: %v", err)
+	}
+}
+
+func TestLocalInvoker_InvokeSuccess(t *testing.T) {
+	tests := []struct {
+		name        string
+		service     interface{}
+		serviceName string
+		methodName  string
+		input       []any
+		expected    interface{}
+	}{
+		{
+			name:        "test basic method call",
+			service:     &MockLocalService{},
+			serviceName: "mockService",
+			methodName:  "GetServiceName",
+			input:       []any{},
+			expected:    "MockLocalService",
+		},
+		{
+			name:        "test method with parameters",
+			service:     &MockLocalService{},
+			serviceName: "mockService",
+			methodName:  "Add",
+			input:       []any{2, 3},
+			expected:    5,
+		},
+		{
+			name:        "test parameter type conversion",
+			service:     &MockLocalService{},
+			serviceName: "mockService",
+			methodName:  "Multiply",
+			input:       []any{2.5, 4},
+			expected:    10.0,
+		},
+	}
+
+	invoker := NewLocalServiceInvoker()
+	ctx := context.Background()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			invoker.RegisterService(tt.serviceName, tt.service)
+			taskState := newLocalServiceTaskState(tt.serviceName, tt.methodName)
+
+			results, err := invoker.Invoke(ctx, tt.input, taskState)
+			if err != nil {
+				t.Fatalf("unexpected error: %v", err)
+			}
+
+			if len(results) == 0 {
+				t.Fatal("no results returned")
+			}
+
+			result := results[0].Interface()
+			if !reflect.DeepEqual(result, tt.expected) {
+				t.Errorf("expected %v, got %v", tt.expected, result)
+			}
+		})
+	}
+}
+
+func TestLocalInvoker_StructParameterConversion(t *testing.T) {
+	invoker := NewLocalServiceInvoker()
+	service := &MockLocalService{}
+	invoker.RegisterService("userService", service)
+
+	ctx := context.Background()
+	taskState := newLocalServiceTaskState("userService", "GetUserName")
+
+	input := []any{map[string]interface{}{"name": "Alice", "age": 30}}
+	results, err := invoker.Invoke(ctx, input, taskState)
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if len(results) == 0 {
+		t.Fatal("no results returned")
+	}
+
+	result := results[0].Interface()
+	if result != "Alice" {
+		t.Errorf("expected 'Alice', got %v", result)
+	}
+}
+
+func TestLocalInvoker_MethodCaching(t *testing.T) {
+	invoker := NewLocalServiceInvoker()
+	service := &MockLocalService{}
+	invoker.RegisterService("cacheTestService", service)
+
+	ctx := context.Background()
+	taskState := newLocalServiceTaskState("cacheTestService", "Add")
+
+	_, err := invoker.Invoke(ctx, []any{1, 1}, taskState)
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	results, err := invoker.Invoke(ctx, []any{2, 3}, taskState)
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+
+	if results[0].Interface() != 5 {
+		t.Errorf("expected 5, got %v", results[0].Interface())
+	}
+
+	if service.invokeCount != 2 {
+		t.Errorf("expected 2 invocations, got %d", service.invokeCount)
+	}
+}
+
+func newLocalServiceTaskState(serviceName, methodName string) state.ServiceTaskState {
+	serviceTaskStateImpl := state.NewServiceTaskStateImpl()
+	serviceTaskStateImpl.SetName(fmt.Sprintf("%s_%s", serviceName, methodName))
+	serviceTaskStateImpl.SetIsAsync(false)
+	serviceTaskStateImpl.SetServiceName(serviceName)
+	serviceTaskStateImpl.SetServiceType("local")
+	serviceTaskStateImpl.SetServiceMethod(methodName)
+	return serviceTaskStateImpl
+}
diff --git a/pkg/saga/statemachine/engine/pcext/compensation_holder.go b/pkg/saga/statemachine/engine/pcext/compensation_holder.go
new file mode 100644
index 00000000..e7ecfb81
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/compensation_holder.go
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/util/collection"
+)
+
+type CompensationHolder struct {
+	statesNeedCompensation     *sync.Map
+	statesForCompensation      *sync.Map
+	stateStackNeedCompensation *collection.Stack
+}
+
+func (c *CompensationHolder) StatesNeedCompensation() *sync.Map {
+	return c.statesNeedCompensation
+}
+
+func (c *CompensationHolder) SetStatesNeedCompensation(statesNeedCompensation *sync.Map) {
+	c.statesNeedCompensation = statesNeedCompensation
+}
+
+func (c *CompensationHolder) StatesForCompensation() *sync.Map {
+	return c.statesForCompensation
+}
+
+func (c *CompensationHolder) SetStatesForCompensation(statesForCompensation *sync.Map) {
+	c.statesForCompensation = statesForCompensation
+}
+
+func (c *CompensationHolder) StateStackNeedCompensation() *collection.Stack {
+	return c.stateStackNeedCompensation
+}
+
+func (c *CompensationHolder) SetStateStackNeedCompensation(stateStackNeedCompensation *collection.Stack) {
+	c.stateStackNeedCompensation = stateStackNeedCompensation
+}
+
+func (c *CompensationHolder) AddToBeCompensatedState(stateName string, toBeCompensatedState statelang.StateInstance) {
+	c.statesNeedCompensation.Store(stateName, toBeCompensatedState)
+}
+
+func NewCompensationHolder() *CompensationHolder {
+	return &CompensationHolder{
+		statesNeedCompensation:     &sync.Map{},
+		statesForCompensation:      &sync.Map{},
+		stateStackNeedCompensation: collection.NewStack(),
+	}
+}
+
+func GetCurrentCompensationHolder(ctx context.Context, processContext process_ctrl.ProcessContext, forceCreate bool) *CompensationHolder {
+	var holder *CompensationHolder
+	if v := processContext.GetVariable(constant.VarNameCurrentCompensationHolder); v != nil {
+		if h, ok := v.(*CompensationHolder); ok {
+			holder = h
+		}
+	}
+	// ensure context mutex exists
+	lock, _ := processContext.GetVariable(constant.VarNameProcessContextMutexLock).(*sync.Mutex)
+	if lock == nil {
+		lock = &sync.Mutex{}
+		processContext.SetVariable(constant.VarNameProcessContextMutexLock, lock)
+	}
+	lock.Lock()
+	defer lock.Unlock()
+	if holder == nil && forceCreate {
+		holder = NewCompensationHolder()
+		processContext.SetVariable(constant.VarNameCurrentCompensationHolder, holder)
+	}
+	return holder
+}
diff --git a/pkg/saga/statemachine/engine/pcext/engine_utils.go b/pkg/saga/statemachine/engine/pcext/engine_utils.go
new file mode 100644
index 00000000..c3d0177e
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/engine_utils.go
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+	"errors"
+	"reflect"
+	"strings"
+	"sync"
+	"time"
+
+	"golang.org/x/sync/semaphore"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+func EndStateMachine(ctx context.Context, processContext process_ctrl.ProcessContext) error {
+	if processContext.HasVariable(constant.VarNameIsLoopState) {
+		if processContext.HasVariable(constant.LoopSemaphore) {
+			weighted, ok := processContext.GetVariable(constant.LoopSemaphore).(*semaphore.Weighted)
+			if !ok || weighted == nil {
+				return errors.New("semaphore type is not *semaphore.Weighted")
+			}
+			weighted.Release(1)
+		}
+	}
+
+	stateMachineInstance, ok := processContext.GetVariable(constant.VarNameStateMachineInst).(statelang.StateMachineInstance)
+	if !ok {
+		return errors.New("state machine instance type is not statelang.StateMachineInstance")
+	}
+
+	stateMachineInstance.SetEndTime(time.Now())
+
+	var exp error
+	if v := processContext.GetVariable(constant.VarNameCurrentException); v != nil {
+		ev, ok := v.(error)
+		if !ok {
+			return errors.New("exception type is not error")
+		}
+		exp = ev
+	}
+
+	if exp != nil {
+		stateMachineInstance.SetException(exp)
+		log.Debugf("Exception Occurred: %s", exp)
+	}
+
+	stateMachineConfig, ok := processContext.GetVariable(constant.VarNameStateMachineConfig).(engine.StateMachineConfig)
+	if !ok {
+		return errors.New("state machine config type is not engine.StateMachineConfig")
+	}
+
+	if err := stateMachineConfig.StatusDecisionStrategy().DecideOnEndState(ctx, processContext, stateMachineInstance, exp); err != nil {
+		return err
+	}
+
+	// Reconcile compensation status using executed compensation states to align with Java semantics
+	// If there are compensation states and all succeeded, override to SU. If any failed/unknown, mark UN.
+	// This guards against edge cases where holder/stack visibility causes FA.
+	compSeen := false
+	compAllSU := true
+	for _, si := range stateMachineInstance.StateList() {
+		if si.StateIDCompensatedFor() != "" {
+			compSeen = true
+			if si.Status() != statelang.SU {
+				compAllSU = false
+				break
+			}
+		}
+	}
+	if compSeen {
+		if compAllSU {
+			log.Debugf("All compensation states SU, overriding machine compensation_status to SU for [%s]", stateMachineInstance.ID())
+			stateMachineInstance.SetCompensationStatus(statelang.SU)
+			// In Java semantics, compensation success with Fail end yields final machine status FA
+			stateMachineInstance.SetStatus(statelang.FA)
+		} else if stateMachineInstance.CompensationStatus() == "" || stateMachineInstance.CompensationStatus() == statelang.RU {
+			log.Debugf("Compensation states contain non-SU, marking compensation_status UN for [%s]", stateMachineInstance.ID())
+			stateMachineInstance.SetCompensationStatus(statelang.UN)
+		}
+	} else {
+		log.Debugf("No compensation states observed for machine [%s]", stateMachineInstance.ID())
+		if v, ok := processContext.GetVariable(constant.VarNameFailEndStateFlag).(bool); ok && v {
+			// Fail end without compensation: normalize to status=FA, empty compensation_status
+			stateMachineInstance.SetCompensationStatus("")
+			stateMachineInstance.SetStatus(statelang.FA)
+		}
+	}
+
+	contextParams, ok := processContext.GetVariable(constant.VarNameStateMachineContext).(map[string]interface{})
+	if !ok {
+		return errors.New("state machine context type is not map[string]interface{}")
+	}
+	endParams := stateMachineInstance.EndParams()
+	for k, v := range contextParams {
+		endParams[k] = v
+	}
+	stateMachineInstance.SetEndParams(endParams)
+
+	switch v := processContext.GetInstruction().(type) {
+	case *StateInstruction:
+		v.SetEnd(true)
+	case StateInstruction:
+		tmp := v
+		tmp.SetEnd(true)
+		processContext.SetInstruction(&tmp)
+	default:
+		return errors.New("state instruction type is not process_ctrl.StateInstruction")
+	}
+
+	stateMachineInstance.SetRunning(false)
+	stateMachineInstance.SetEndTime(time.Now())
+
+	if stateMachineInstance.StateMachine().IsPersist() && stateMachineConfig.StateLangStore() != nil {
+		err := stateMachineConfig.StateLogStore().RecordStateMachineFinished(ctx, stateMachineInstance, processContext)
+		if err != nil {
+			return err
+		}
+	}
+
+	callBack, ok := processContext.GetVariable(constant.VarNameAsyncCallback).(engine.CallBack)
+	if ok {
+		if exp != nil {
+			callBack.OnError(ctx, processContext, stateMachineInstance, exp)
+		} else {
+			callBack.OnFinished(ctx, processContext, stateMachineInstance)
+		}
+	}
+
+	return nil
+}
+
+func HandleException(processContext process_ctrl.ProcessContext, abstractTaskState *state.AbstractTaskState, err error) {
+	catches := abstractTaskState.Catches()
+	for _, exceptionMatch := range catches {
+		exceptions := exceptionMatch.Exceptions()
+		exceptionTypes := exceptionMatch.ExceptionTypes()
+		if len(exceptions) != 0 {
+			if exceptionTypes == nil {
+				lock, _ := processContext.GetVariable(constant.VarNameProcessContextMutexLock).(*sync.Mutex)
+				if lock != nil {
+					lock.Lock()
+					defer lock.Unlock()
+				}
+				if exceptionMatch.ExceptionTypes() == nil {
+					errorType := reflect.TypeOf(errors.New(""))
+					for range exceptions {
+						exceptionTypes = append(exceptionTypes, errorType)
+					}
+					exceptionMatch.SetExceptionTypes(exceptionTypes)
+				} else {
+					exceptionTypes = exceptionMatch.ExceptionTypes()
+				}
+			}
+		}
+
+		for i := range exceptionTypes {
+			if reflect.TypeOf(err) == exceptionTypes[i] {
+				// HACK: we can not get error type in config file during runtime, so we use exception str
+				if strings.Contains(err.Error(), exceptions[i]) {
+					hierarchicalProcessContext := processContext.(process_ctrl.HierarchicalProcessContext)
+					hierarchicalProcessContext.SetVariable(constant.VarNameCurrentExceptionRoute, exceptionMatch.Next())
+					return
+				}
+			}
+		}
+	}
+
+	log.Error("Task execution failed and no catches configured")
+	hierarchicalProcessContext := processContext.(process_ctrl.HierarchicalProcessContext)
+	hierarchicalProcessContext.SetVariable(constant.VarNameIsExceptionNotCatch, true)
+}
+
+// GetOriginStateName get origin state name without suffix like fork
+func GetOriginStateName(stateInstance statelang.StateInstance) string {
+	stateName := stateInstance.Name()
+	if stateName != "" {
+		end := strings.LastIndex(stateName, constant.LoopStateNamePattern)
+		if end > -1 {
+			return stateName[:end+1]
+		}
+	}
+	return stateName
+}
+
+// IsTimeout test if is timeout
+func IsTimeout(gmtUpdated time.Time, timeoutMillis int) bool {
+	if timeoutMillis < 0 {
+		return false
+	}
+	return time.Now().Unix()-gmtUpdated.Unix() > int64(timeoutMillis)
+}
+
+func GenerateParentId(stateInstance statelang.StateInstance) string {
+	return stateInstance.MachineInstanceID() + constant.SeperatorParentId + stateInstance.ID()
+}
+
+// GetNetExceptionType Speculate what kind of network anomaly is caused by the error
+func GetNetExceptionType(err error) constant.NetExceptionType {
+	if err == nil {
+		return constant.NotNetException
+	}
+
+	// If it contains a specific error message, simply guess
+	errMsg := err.Error()
+	if strings.Contains(errMsg, "connection refused") {
+		return constant.ConnectException
+	} else if strings.Contains(errMsg, "timeout") {
+		return constant.ConnectTimeoutException
+	} else if strings.Contains(errMsg, "i/o timeout") {
+		return constant.ReadTimeoutException
+	}
+	return constant.NotNetException
+}
diff --git a/pkg/saga/statemachine/engine/pcext/instruction.go b/pkg/saga/statemachine/engine/pcext/instruction.go
new file mode 100644
index 00000000..9ff0d1c0
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/instruction.go
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"errors"
+	"fmt"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+)
+
+type StateInstruction struct {
+	stateName        string
+	stateMachineName string
+	tenantId         string
+	end              bool
+	temporaryState   statelang.State
+}
+
+func NewStateInstruction(stateMachineName string, tenantId string) *StateInstruction {
+	return &StateInstruction{stateMachineName: stateMachineName, tenantId: tenantId}
+}
+
+func (s *StateInstruction) StateName() string {
+	return s.stateName
+}
+
+func (s *StateInstruction) SetStateName(stateName string) {
+	s.stateName = stateName
+}
+
+func (s *StateInstruction) StateMachineName() string {
+	return s.stateMachineName
+}
+
+func (s *StateInstruction) SetStateMachineName(stateMachineName string) {
+	s.stateMachineName = stateMachineName
+}
+
+func (s *StateInstruction) TenantId() string {
+	return s.tenantId
+}
+
+func (s *StateInstruction) SetTenantId(tenantId string) {
+	s.tenantId = tenantId
+}
+
+func (s *StateInstruction) End() bool {
+	return s.end
+}
+
+func (s *StateInstruction) SetEnd(end bool) {
+	s.end = end
+}
+
+func (s *StateInstruction) TemporaryState() statelang.State {
+	return s.temporaryState
+}
+
+func (s *StateInstruction) SetTemporaryState(temporaryState statelang.State) {
+	s.temporaryState = temporaryState
+}
+
+func (s *StateInstruction) GetState(context process_ctrl.ProcessContext) (statelang.State, error) {
+	if s.temporaryState != nil {
+		return s.temporaryState, nil
+	}
+
+	if s.stateMachineName == "" {
+		return nil, errors.New("stateMachineName is required")
+	}
+
+	stateMachineConfig, ok := context.GetVariable(constant.VarNameStateMachineConfig).(engine.StateMachineConfig)
+	if !ok {
+		return nil, errors.New("stateMachineConfig is required in context")
+	}
+	stateMachine, err := stateMachineConfig.StateMachineRepository().GetLastVersionStateMachine(s.stateMachineName, s.tenantId)
+	if err != nil {
+		return nil, errors.New("get stateMachine in state machine repository error")
+	}
+	if stateMachine == nil {
+		return nil, errors.New(fmt.Sprintf("stateMachine [%s] is not exist", s.stateMachineName))
+	}
+
+	if s.stateName == "" {
+		s.stateName = stateMachine.StartState()
+	}
+
+	state := stateMachine.States()[s.stateName]
+	if state == nil {
+		return nil, errors.New(fmt.Sprintf("state [%s] is not exist", s.stateName))
+	}
+
+	return state, nil
+}
diff --git a/pkg/saga/statemachine/engine/pcext/loop_context_holder.go b/pkg/saga/statemachine/engine/pcext/loop_context_holder.go
new file mode 100644
index 00000000..60928c10
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/loop_context_holder.go
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+)
+
+type LoopContextHolder struct {
+	nrOfInstances                int32
+	nrOfActiveInstances          int32
+	nrOfCompletedInstances       int32
+	failEnd                      bool
+	completionConditionSatisfied bool
+	loopCounterStack             []int
+	forwardCounterStack          []int
+	collection                   interface{}
+}
+
+func NewLoopContextHolder() *LoopContextHolder {
+	return &LoopContextHolder{
+		nrOfInstances:                0,
+		nrOfActiveInstances:          0,
+		nrOfCompletedInstances:       0,
+		failEnd:                      false,
+		completionConditionSatisfied: false,
+		loopCounterStack:             make([]int, 0),
+		forwardCounterStack:          make([]int, 0),
+		collection:                   nil,
+	}
+}
+
+func GetCurrentLoopContextHolder(ctx context.Context, processContext process_ctrl.ProcessContext, forceCreate bool) *LoopContextHolder {
+	mutex := processContext.GetVariable(constant.VarNameProcessContextMutexLock).(*sync.Mutex)
+	mutex.Lock()
+	defer mutex.Unlock()
+
+	loopContextHolder := processContext.GetVariable(constant.VarNameCurrentLoopContextHolder).(*LoopContextHolder)
+	if loopContextHolder == nil && forceCreate {
+		loopContextHolder = &LoopContextHolder{}
+		processContext.SetVariable(constant.VarNameCurrentLoopContextHolder, loopContextHolder)
+	}
+	return loopContextHolder
+}
+
+func ClearCurrent(ctx context.Context, processContext process_ctrl.ProcessContext) {
+	processContext.RemoveVariable(constant.VarNameCurrentLoopContextHolder)
+}
+
+func (l *LoopContextHolder) NrOfInstances() int32 {
+	return l.nrOfInstances
+}
+
+func (l *LoopContextHolder) NrOfActiveInstances() int32 {
+	return l.nrOfActiveInstances
+}
+
+func (l *LoopContextHolder) NrOfCompletedInstances() int32 {
+	return l.nrOfCompletedInstances
+}
+
+func (l *LoopContextHolder) FailEnd() bool {
+	return l.failEnd
+}
+
+func (l *LoopContextHolder) SetFailEnd(failEnd bool) {
+	l.failEnd = failEnd
+}
+
+func (l *LoopContextHolder) CompletionConditionSatisfied() bool {
+	return l.completionConditionSatisfied
+}
+
+func (l *LoopContextHolder) SetCompletionConditionSatisfied(completionConditionSatisfied bool) {
+	l.completionConditionSatisfied = completionConditionSatisfied
+}
+
+func (l *LoopContextHolder) LoopCounterStack() []int {
+	return l.loopCounterStack
+}
+
+func (l *LoopContextHolder) ForwardCounterStack() []int {
+	return l.forwardCounterStack
+}
+
+func (l *LoopContextHolder) Collection() interface{} {
+	return l.collection
+}
+
+func (l *LoopContextHolder) SetCollection(collection interface{}) {
+	l.collection = collection
+}
diff --git a/pkg/saga/statemachine/engine/pcext/loop_task_utils.go b/pkg/saga/statemachine/engine/pcext/loop_task_utils.go
new file mode 100644
index 00000000..8b0de8ae
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/loop_task_utils.go
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+	"seata.apache.org/seata-go/pkg/util/log"
+)
+
+func GetLoopConfig(ctx context.Context, processContext process_ctrl.ProcessContext, currentState statelang.State) state.Loop {
+	if !matchLoop(currentState) {
+		return nil
+	}
+	// Extract underlying AbstractTaskState pointer safely
+	var task *state.AbstractTaskState
+	switch s := currentState.(type) {
+	case *state.ServiceTaskStateImpl:
+		task = s.AbstractTaskState
+	case *state.ScriptTaskStateImpl:
+		task = s.AbstractTaskState
+	case *state.SubStateMachineImpl:
+		if s.ServiceTaskStateImpl != nil {
+			task = s.ServiceTaskStateImpl.AbstractTaskState
+		}
+	default:
+		return nil
+	}
+	if task == nil || task.Loop() == nil {
+		return nil
+	}
+
+	loop := task.Loop()
+	collectionName := loop.Collection()
+	if collectionName == "" {
+		return nil
+	}
+
+	stateMachineInstance := processContext.GetVariable(constant.VarNameStateMachineInst).(statelang.StateMachineInstance)
+	stateMachineConfig := processContext.GetVariable(constant.VarNameStateMachineConfig).(engine.StateMachineConfig)
+	expression := CreateValueExpression(stateMachineConfig.ExpressionResolver(), collectionName)
+	collection := GetValue(expression, stateMachineInstance.Context(), nil)
+	if collection == nil {
+		log.Warn("State [{}] loop collection param [{}] invalid", currentState.Name(), collectionName)
+		return nil
+	}
+	if collectionList, ok := collection.([]any); ok && len(collectionList) > 0 {
+		current := GetCurrentLoopContextHolder(ctx, processContext, true)
+		current.SetCollection(collection)
+		return loop
+	}
+	return nil
+}
+
+func matchLoop(currentState statelang.State) bool {
+	return currentState != nil && (constant.StateTypeServiceTask == currentState.Type() ||
+		constant.StateTypeScriptTask == currentState.Type() || constant.StateTypeSubStateMachine == currentState.Type())
+}
diff --git a/pkg/saga/statemachine/engine/pcext/parameter_utils.go b/pkg/saga/statemachine/engine/pcext/parameter_utils.go
new file mode 100644
index 00000000..95dfea14
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/parameter_utils.go
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"fmt"
+	"strings"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/expr"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+func CreateInputParams(processContext process_ctrl.ProcessContext, expressionResolver expr.ExpressionResolver,
+	stateInstance *statelang.StateInstanceImpl, serviceTaskState *state.AbstractTaskState, variablesFrom any) []any {
+	inputAssignments := serviceTaskState.Input()
+	if len(inputAssignments) == 0 {
+		return inputAssignments
+	}
+
+	inputExpressions := serviceTaskState.InputExpressions()
+	if len(inputExpressions) == 0 {
+		lock := processContext.GetVariable(constant.VarNameProcessContextMutexLock).(*sync.Mutex)
+		lock.Lock()
+		defer lock.Unlock()
+		inputExpressions = serviceTaskState.InputExpressions()
+		if len(inputExpressions) == 0 {
+			inputExpressions = make([]any, 0, len(inputAssignments))
+
+			for _, assignment := range inputAssignments {
+				inputExpressions = append(inputExpressions, CreateValueExpression(expressionResolver, assignment))
+			}
+		}
+		serviceTaskState.SetInputExpressions(inputExpressions)
+	}
+	inputValues := make([]any, 0, len(inputExpressions))
+	for _, valueExpression := range inputExpressions {
+		value := GetValue(valueExpression, variablesFrom, stateInstance)
+		inputValues = append(inputValues, value)
+	}
+
+	return inputValues
+}
+
+func CreateOutputParams(config engine.StateMachineConfig, expressionResolver expr.ExpressionResolver,
+	serviceTaskState *state.AbstractTaskState, variablesFrom any) (map[string]any, error) {
+	outputAssignments := serviceTaskState.Output()
+	if len(outputAssignments) == 0 {
+		return make(map[string]any, 0), nil
+	}
+
+	outputExpressions := serviceTaskState.OutputExpressions()
+	if outputExpressions == nil {
+		config.ComponentLock().Lock()
+		defer config.ComponentLock().Unlock()
+		outputExpressions = serviceTaskState.OutputExpressions()
+		if outputExpressions == nil {
+			outputExpressions = make(map[string]any, len(outputAssignments))
+			for key, value := range outputAssignments {
+				outputExpressions[key] = CreateValueExpression(expressionResolver, value)
+			}
+		}
+		serviceTaskState.SetOutputExpressions(outputExpressions)
+	}
+	outputValues := make(map[string]any, len(outputExpressions))
+	for paramName := range outputExpressions {
+		outputValues[paramName] = GetValue(outputExpressions[paramName], variablesFrom, nil)
+	}
+	return outputValues, nil
+}
+
+func CreateValueExpression(expressionResolver expr.ExpressionResolver, paramAssignment any) any {
+	switch v := paramAssignment.(type) {
+	case expr.Expression:
+		return v
+	case map[string]any:
+		paramMap := make(map[string]any, len(v))
+		for key, value := range v {
+			paramMap[key] = CreateValueExpression(expressionResolver, value)
+		}
+		return paramMap
+	case []any:
+		paramList := make([]any, 0, len(v))
+		for _, value := range v {
+			paramList = append(paramList, CreateValueExpression(expressionResolver, value))
+		}
+		return paramList
+	case string:
+		if !strings.HasPrefix(v, "$") {
+			return v
+		}
+		return expressionResolver.Expression(v)
+	default:
+		return paramAssignment
+	}
+}
+
+func GetValue(valueExpression any, variablesFrom any, stateInstance statelang.StateInstance) any {
+	switch v := valueExpression.(type) {
+	case expr.Expression:
+		value := v.Value(variablesFrom)
+		if _, ok := v.(expr.SequenceExpression); value != nil && stateInstance != nil && stateInstance.BusinessKey() == "" && ok {
+			stateInstance.SetBusinessKey(fmt.Sprintf("%v", value))
+		}
+		return value
+	case map[string]any:
+		mapValue := make(map[string]any, len(v))
+		for key, value := range v {
+			resolved := GetValue(value, variablesFrom, stateInstance)
+			if resolved != nil {
+				mapValue[key] = resolved
+			}
+		}
+		return mapValue
+	case []any:
+		listValue := make([]any, 0, len(v))
+		for i := range v {
+			listValue = append(listValue, GetValue(v[i], variablesFrom, stateInstance))
+		}
+		return listValue
+	default:
+		return valueExpression
+	}
+}
diff --git a/pkg/saga/statemachine/engine/pcext/process_handler.go b/pkg/saga/statemachine/engine/pcext/process_handler.go
new file mode 100644
index 00000000..aef3aae1
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/process_handler.go
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+	"errors"
+	"sync"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine/expr"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+	stateimpl "seata.apache.org/seata-go/pkg/saga/statemachine/statelang/state"
+)
+
+type StateHandler interface {
+	State() string
+	process_ctrl.ProcessHandler
+}
+
+type InterceptAbleStateHandler interface {
+	StateHandler
+	StateHandlerInterceptorList() []StateHandlerInterceptor
+	RegistryStateHandlerInterceptor(stateHandlerInterceptor StateHandlerInterceptor)
+}
+
+type StateHandlerInterceptor interface {
+	PreProcess(ctx context.Context, processContext process_ctrl.ProcessContext) error
+	PostProcess(ctx context.Context, processContext process_ctrl.ProcessContext) error
+	Match(stateType string) bool
+}
+
+type StateMachineProcessHandler struct {
+	mp map[string]StateHandler
+	mu sync.RWMutex
+}
+
+func NewStateMachineProcessHandler() *StateMachineProcessHandler {
+	return &StateMachineProcessHandler{
+		mp: make(map[string]StateHandler),
+	}
+}
+
+func (s *StateMachineProcessHandler) Process(ctx context.Context, processContext process_ctrl.ProcessContext) error {
+	var stateInstruction *StateInstruction
+	switch v := processContext.GetInstruction().(type) {
+	case *StateInstruction:
+		stateInstruction = v
+	case StateInstruction:
+		tmp := v
+		stateInstruction = &tmp
+	default:
+		return errors.New("invalid state instruction from processContext")
+	}
+
+	state, err := stateInstruction.GetState(processContext)
+	if err != nil {
+		return err
+	}
+
+	// mark Fail end-state to influence final machine status decision
+	if state.Type() == constant.StateTypeFail {
+		processContext.SetVariable(constant.VarNameFailEndStateFlag, true)
+	}
+
+	stateType := state.Type()
+	stateHandler := s.GetStateHandler(stateType)
+
+	interceptAbleStateHandler, ok := stateHandler.(InterceptAbleStateHandler)
+
+	var stateHandlerInterceptorList []StateHandlerInterceptor
+	if ok {
+		stateHandlerInterceptorList = interceptAbleStateHandler.StateHandlerInterceptorList()
+	}
+
+	if stateHandlerInterceptorList != nil && len(stateHandlerInterceptorList) > 0 {
+		for _, stateHandlerInterceptor := range stateHandlerInterceptorList {
+			err = stateHandlerInterceptor.PreProcess(ctx, processContext)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	// Prepare current state instance in context before processing
+	smInst, ok := processContext.GetVariable(constant.VarNameStateMachineInst).(statelang.StateMachineInstance)
+	if !ok || smInst == nil {
+		return errors.New("state machine instance not found in context")
+	}
+
+	stInst := statelang.NewStateInstanceImpl()
+	stInst.SetName(state.Name())
+	stInst.SetType(state.Type())
+	// If service task, enrich service attributes
+	if svc, ok := state.(*stateimpl.ServiceTaskStateImpl); ok {
+		stInst.SetServiceName(svc.ServiceName())
+		stInst.SetServiceMethod(svc.ServiceMethod())
+		stInst.SetServiceType(svc.ServiceType())
+		stInst.SetForUpdate(svc.ForUpdate())
+
+		// ensure mutex lock for parameter evaluation exists
+		if !processContext.HasVariable(constant.VarNameProcessContextMutexLock) {
+			processContext.SetVariable(constant.VarNameProcessContextMutexLock, &sync.Mutex{})
+		}
+		// if this is a compensation execution, mark the link to original state
+		if v := processContext.GetVariable("_compensate_for_state_id_"); v != nil {
+			if sid, ok := v.(string); ok && sid != "" {
+				stInst.SetStateIDCompensatedFor(sid)
+				// also add to holder's 'StatesForCompensation' for final status decision
+				holder := GetCurrentCompensationHolder(ctx, processContext, true)
+				holder.StatesForCompensation().Store(stInst.Name(), stInst)
+				// clear after consuming
+				processContext.RemoveVariable("_compensate_for_state_id_")
+			}
+		}
+
+		// evaluate input params from CEL expressions if any
+		if cfg, ok := processContext.GetVariable(constant.VarNameStateMachineConfig).(engine.StateMachineConfig); ok {
+			var exprResolver expr.ExpressionResolver = cfg.ExpressionResolver()
+			// use all variables in process context for expression scope
+			variables := processContext.GetVariables()
+			inputParams := CreateInputParams(processContext, exprResolver, stInst, svc.AbstractTaskState, variables)
+			processContext.SetVariable(constant.VarNameInputParams, inputParams)
+		}
+	}
+	// Assign a temporary ID key for list/map tracking
+	tmpId := state.Name()
+	if tmpId == "" {
+		tmpId = "state"
+	}
+	smInst.PutState(tmpId, stInst)
+	processContext.SetVariable(constant.VarNameStateInst, stInst)
+
+	// Execute handler when present; end states don't require a handler
+	if stateHandler != nil {
+		err = stateHandler.Process(ctx, processContext)
+		if err != nil {
+			return err
+		}
+	}
+
+	if stateHandlerInterceptorList != nil && len(stateHandlerInterceptorList) > 0 {
+		for _, stateHandlerInterceptor := range stateHandlerInterceptorList {
+			err = stateHandlerInterceptor.PostProcess(ctx, processContext)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	// Set execution result on state instance
+	if ex, _ := processContext.GetVariable(constant.VarNameCurrentException).(error); ex != nil {
+		stInst.SetStatus(statelang.FA)
+		stInst.SetError(ex)
+	} else {
+		// For Fail end state, mark FA; otherwise mark SU
+		if stateType == constant.StateTypeFail {
+			stInst.SetStatus(statelang.FA)
+		} else {
+			stInst.SetStatus(statelang.SU)
+		}
+	}
+
+	return nil
+}
+
+func (s *StateMachineProcessHandler) GetStateHandler(stateType string) StateHandler {
+	s.mu.RLock()
+	defer s.mu.RUnlock()
+	return s.mp[stateType]
+}
+
+func (s *StateMachineProcessHandler) RegistryStateHandler(stateType string, stateHandler StateHandler) {
+	s.mu.Lock()
+	defer s.mu.Unlock()
+	if s.mp == nil {
+		s.mp = make(map[string]StateHandler)
+	}
+	s.mp[stateType] = stateHandler
+}
diff --git a/pkg/saga/statemachine/engine/pcext/process_router.go b/pkg/saga/statemachine/engine/pcext/process_router.go
new file mode 100644
index 00000000..c650645c
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/process_router.go
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pcext
+
+import (
+	"context"
+
+	"github.com/pkg/errors"
+
+	"seata.apache.org/seata-go/pkg/saga/statemachine/constant"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/engine"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/process_ctrl"
+	"seata.apache.org/seata-go/pkg/saga/statemachine/statelang"
+)
+
+type StateMachineProcessRouter struct {
+	stateRouters map[string]process_ctrl.StateRouter
+}
+
+func (s *StateMachineProcessRouter) Route(ctx context.Context, processContext process_ctrl.ProcessContext) (process_ctrl.Instruction, error) {
+	var stateInstruction *StateInstruction
+	switch v := processContext.GetInstruction().(type) {
+	case *StateInstruction:
+		stateInstruction = v
+	case StateInstruction:
+		tmp := v
+		stateInstruction = &tmp
+	default:
+		return nil, errors.New("instruction is not a state instruction")
+	}
+
+	var state statelang.State
+	if stateInstruction.TemporaryState() != nil {
+		state = stateInstruction.TemporaryState()
+		stateInstruction.SetTemporaryState(nil)
+	} else {
+		stateMachineConfig, ok := processContext.GetVariable(constant.VarNameStateMachineConfig).(engine.StateMachineConfig)
+		if !ok {
+			return nil, errors.New("state machine config not found")
+		}
+
+		stateMachine, err := stateMachineConfig.StateMachineRepository().GetStateMachineByNameAndTenantId(stateInstruction.StateMachineName(),
+			stateInstruction.TenantId())
+		if err != nil {
+			return nil, err
+		}
+
+		state = stateMachine.States()[stateInstruction.StateName()]
+	}
+
+	stateType := state.Type()
+	router := s.stateRouters[stateType]
+
+	var interceptors []process_ctrl.StateRouterInterceptor
+	if interceptAbleStateRouter, ok := router.(process_ctrl.InterceptAbleStateRouter); ok {
+		interceptors = interceptAbleStateRouter.StateRouterInterceptor()
+	}
+
+	var executedInterceptors []process_ctrl.StateRouterInterceptor
+	var exception error
+	instruction, exception := func() (process_ctrl.Instruction, error) {
+		if interceptors == nil || len(executedInterceptors) == 0 {
+			executedInterceptors = make([]process_ctrl.StateRouterInterceptor, 0, len(interceptors))
+			for _, interceptor := range interceptors {
+				executedInterceptors = append(executedInterceptors, interceptor)
+				err := interceptor.PreRoute(ctx, processContext, state)
+				if err != nil {
+					return nil, err
+				}
+			}
+		}
+
+		instruction, err := router.Route(ctx, processContext, state)
+		if err != nil {
+			return nil, err
+		}
+		return instruction, nil
+	}()
+
+	if interceptors == nil || len(executedInterceptors) == 0 {
+		for i := len(executedInterceptors) - 1; i >= 0; i-- {
+			err := executedInterceptors[i].PostRoute(ctx, processContext, instruction, exception)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		// if 'Succeed' or 'Fail' State did not configured, we must end the state machine
+		if instruction == nil && !stateInstruction.End() {
+			err := EndStateMachine(ctx, processContext)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	return instruction, nil
+}
+
+func (s *StateMachineProcessRouter) InitDefaultStateRouters() {
+	if s.stateRouters == nil || len(s.stateRouters) == 0 {
+		s.stateRouters = make(map[string]process_ctrl.StateRouter)
+		taskStateRouter := &TaskStateRouter{}
+		s.stateRouters[constant.StateTypeServiceTask] = taskStateRouter
+		s.stateRouters[constant.StateTypeScriptTask] = taskStateRouter
+		s.stateRouters[constant.StateTypeChoice] = taskStateRouter
+		s.stateRouters[constant.StateTypeCompensationTrigger] = taskStateRouter
+		s.stateRouters[constant.StateTypeSubStateMachine] = taskStateRouter
+		s.stateRouters[constant.StateTypeCompensateSubMachine] = taskStateRouter
+		s.stateRouters[constant.StateTypeLoopStart] = taskStateRouter
+
+		endStateRouter := &EndStateRouter{}
+		s.stateRouters[constant.StateTypeSucceed] = endStateRouter
+		s.stateRouters[constant.StateTypeFail] = endStateRouter
+	}
+}
+
+func (s *StateMachineProcessRouter) StateRouters() map[string]process_ctrl.StateRouter {
+	return s.stateRouters
+}
+
+func (s *StateMachineProcessRouter) SetStateRouters(stateRouters map[string]process_ctrl.StateRouter) {
+	s.stateRouters = stateRouters
+}
diff --git a/pkg/saga/statemachine/engine/pcext/state_router_impl.go b/pkg/saga/statemachine/engine/pcext/state_router_impl.go
new file mode 100644
index 00000000..2fc1a1f9
--- /dev/null
+++ b/pkg/saga/statemachine/engine/pcext/state_router_impl.go
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
... 12675 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org