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

ningjiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-pack.git

commit 9bba11c5a01ea1350ef2da8ad30309068c8ed6ec
Author: Daniel Qian <[email protected]>
AuthorDate: Tue Jul 23 11:11:05 2019 +0800

    SCB-1389 write docs for explicit passing transaction context
---
 docs/design.md        |   2 +-
 docs/design_zh.md     |   2 +-
 docs/user_guide.md    | 106 ++++++++++++++++++++++++++++++++++++++++++++++++-
 docs/user_guide_zh.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 211 insertions(+), 6 deletions(-)

diff --git a/docs/design.md b/docs/design.md
index 4f07f11..7224bc2 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -10,7 +10,7 @@ Omega plays as an embedded agent inside services. When a 
service request arrives
 
 ![Omega Internal](static_files/omega_internal.png)
 
-## Inter-Service Communication
+## <a name="comm"></a>Inter-Service Communication
 The process of Inter-Service Communication is similar to 
[Zipkin](https://github.com/openzipkin/zipkin)'s. In the producer side, omega 
intercepts the transaction ids from request to retrieve the transaction 
context. In the consumer side, omega inject the global transaction ids into 
request to pass the transaction context. Sub-transactions can chain as a single 
global transaction by co-operating producers and consumers.
 
 ![Inter-Service Communication](static_files/inter-service_communication.png)
diff --git a/docs/design_zh.md b/docs/design_zh.md
index 71a0d63..ace9858 100644
--- a/docs/design_zh.md
+++ b/docs/design_zh.md
@@ -12,7 +12,7 @@ omega是微服务中内嵌的一个agent。当服务收到请求时,omega会
 
 ![Omega Internal](static_files/omega_internal.png)
 
-## 服务间通信流程
+## <a name="comm"></a>服务间通信流程
 
服务间通信的流程与[Zipkin](https://github.com/openzipkin/zipkin)的类似。在服务生产方,omega会拦截请求中事务相关的id来提取事务的上下文。在服务消费方,omega会在请求中注入事务相关的id来传递事务的上下文。通过服务提供方和服务消费方的这种协作处理,子事务能连接起来形成一个完整的全局事务。
 
 ![Inter-Service Communication](static_files/inter-service_communication.png)
diff --git a/docs/user_guide.md b/docs/user_guide.md
index bef201b..21d4767 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -111,7 +111,109 @@ Take a transfer money application as an example:
 
 5. Since pack-0.3.0,  you can access the 
[OmegaContext](https://github.com/apache/servicecomb-pack/blob/master/omega/omega-context/src/main/java/org/apache/servicecomb/pack/omega/context/OmegaContext.java)
 for the gloableTxId and localTxId in the @Compensable annotated method or the 
cancel method.
 
+#### Passing transaction context explicitly
+
+In most cases, Omega passing the transaction context for you transparently 
(see [Inter-Service Communication](design.md#comm) for details). Transaction 
context passing is implemented in a way of injecting transaction context 
information on the sender side and extracting it on the receiver side. Below is 
an example to illustrate this process:
+
+Service A:
+
+```java
+@SagaStart
+public void foo() {
+  restTemplate.postForEntity("http://service-b/bar";, ...);
+}
+```
+
+Service B:
+
+```java
+@GetMapping("/bar")
+@Compensable
+public void bar() {
+  ...
+}
+```
+
+Here is how Omega does:
+
+1. Service A's `foo` method opens a new global transaction.
+2. `TransactionClientHttpRequestInterceptor` injects transaction context into 
request headers when `RestTemplate` request Service B.
+3. When Service B receive the request, `TransactionHandlerInterceptor` extract 
context info from request headers.
+
+Omega supports following implicity transaction context passing:
+
+1. omega-transport-{dubbo,feign,resttemplate,servicecomb}.
+2. Method call in the same thread (based on `OmegaContext` thread local 
fields).
+3. `java.util.concurrent.Executor{Service}` annotated by `@OmegaContextAware`.
+
+So here comes a problem: what if implicit transaction context passing can't 
work? For example, Service A invokes Service B via some RPC library and no 
extension can be made to injecting or extracting transaction context 
information. In this situation you need explicit transaction context passing. 
Omega provides two classes to achieve that.
+
+##### TransactionContext
+
+Service A:
+
+```java
+@SagaStart
+public void foo(BarCommand cmd) {
+  TransactionContext txContext = OmegaContext.getTransactionContext();
+  someRpc.send(cmd, txContext);
+}
+```
+
+Service B:
+
+```java
+public void listen(BarCommand cmd, TransactionContext parentTxContext) {
+  bar(cmd, txContext);
+}
+@Compensable
+public void bar(BarCommand cmd, TransactionContext parentTxContext) {
+  ...
+  // TransactionContext childTxContext = OmegaContext.getTransactionContext();
+}
+```
+
+Notice that `bar` method got parent transaction context in parameter list, and 
got child transaction context from `OmegaContext` in method body. So if you 
want to passing transaction context to another service, you should pass child 
transaction context.
+
+##### TransactionContextProperties
+
+Service A:
+
+```java
+public class BarCommand {}
+public class BarCommandWithTxContext 
+  extends BarCommand implements TransactionContextProperties {
+  // setter getter for globalTxId
+  // setter getter for localTxId
+}
+@SagaStart
+public void foo(BarCommand cmd) {
+  TransactionContext txContext = OmegaContext.getTransactionContext();
+  BarCommandWithTxContext cmdWithTxContext = new BarCommandWithTxContext(cmd);
+  cmdWithTxContext.setGlobalTxId(txContext.globalTxId());
+  cmdWithTxContext.setLocalTxId(txContext.localTxId());
+  someRpc.send(cmdWithTxContext);
+}
+```
+
+Service B:
+
+```java
+public void listen(BarCommandWithTxContext cmdWithTxContext) {
+  bar(cmdWithTxContext);
+}
+
+@Compensable
+public void bar(BarCommandWithTxContext cmdWithTxContext) {
+  ...
+  // TransactionContext childTxContext = OmegaContext.getTransactionContext();
+}
+```
+
+Similar to the previous approach, `cmdWithTxContext.get{Global,Local}TxId()` 
also returns parent transaction context information.
+
 ### TCC support
+
 Add TCC annotations and corresponding confirm and cancel methods
  Take a transfer money application as an example:
  1. add `@TccStart` at the starting point of the global transaction
@@ -498,7 +600,7 @@ Uses Spring Cloud Zookeeper 2.x by default, if you want to 
use Spring Cloud Zook
             ]
         }
     }
-    ```
+   ```
 
    **Note:**  `metadata` property is alpha gRPC address
 
@@ -621,7 +723,7 @@ Uses Spring Cloud Nacos Discovery 0.2.x by default, if you 
want to use Spring Cl
         "clusters": ""
         }
 
-    ```
+   ```
 
    **Note:**  `metadata` property is alpha gRPC address
 
diff --git a/docs/user_guide_zh.md b/docs/user_guide_zh.md
index 925be65..85a2031 100644
--- a/docs/user_guide_zh.md
+++ b/docs/user_guide_zh.md
@@ -111,9 +111,111 @@ Saga可通过以下任一方式进行构建:
 
 5. 从pack-0.3.0开始, 你可以在服务函数或者取消函数中通过访问 
[OmegaContext](https://github.com/apache/servicecomb-pack/blob/master/omega/omega-context/src/main/java/org/apache/servicecomb/pack/omega/context/OmegaContext.java)
 来获取 gloableTxId 以及 localTxId 信息。
 
+#### 显式传递事务上下文
+
+在一般情况下,Omega能够替你处理事务上下文的传递工作(详情见[服务间通信流程](design_zh.md#comm)),因此你的代码并不需要知道事务上下文的存在。而事务上下文的传递实际上是通过在请求方注入、在接受方提取来完成的,下面举一个请例子来说明这个过程:
+
+Service A:
+
+```java
+@SagaStart
+public void foo() {
+  restTemplate.postForEntity("http://service-b/bar";, ...);
+}
+```
+
+Service B:
+
+```java
+@GetMapping("/bar")
+@Compensable
+public void bar() {
+  ...
+}
+```
+
+我们可以先来看看Omega是怎么传递事务上下文的:
+
+1. Service A的foo方法会开启一个新的全局事务。
+2. TransactionClientHttpRequestInterceptor会在RestTemplate请求Service 
B时在Http请求头中注入事务上下文信息。
+3. 当Servce B接收到请求时,TransactionHandlerInterceptor会从请求头中提取事务上下文信息。
+
+目前Omega支持以下形式的隐式事务上下文传递:
+
+1. omega-transport-{dubbo,feign,resttemplate,servicecomb}。
+2. 同线程内调用。
+3. 标注了@OmegaContextAware的java.util.concurrent.Executor{Service}。
+
+那么问题来了,如果隐式传递事务上下文不行怎么办?比如Service A使用某种RPC机制件来调用Service 
B,而你又没有办法注入或提取事务上下文信息。这个时候你只能采用显式的方式把事务上下文传递出去。Omega提供了两个类来实现这一点。
+
+##### 利用TransactionContext传递
+
+Service A:
+
+```java
+@SagaStart
+public void foo(BarCommand cmd) {
+  TransactionContext txContext = OmegaContext.getTransactionContext();
+  someRpc.send(cmd, txContext);
+}
+```
+
+Service B:
+
+```java
+public void listen(BarCommand cmd, TransactionContext parentTxContext) {
+  bar(cmd, txContext);
+}
+@Compensable
+public void bar(BarCommand cmd, TransactionContext parentTxContext) {
+  ...
+  // TransactionContext childTxContext = omegaContext.getTransactionContext();
+}
+```
+
+需要注意的是`bar`方法接收到的是父事务上下文,在进入`bar`之后从OmegaContext得到的是子事务上下文(Omega替你开启了新的事务)。如果你需要将事务上下文传递给另一个服务,那么你应该传递子事务上下文。
+
+##### 利用TransactionContextProperties传递
+
+Service A:
+
+```java
+public class BarCommand {}
+public class BarCommandWithTxContext 
+  extends BarCommand implements TransactionContextProperties {
+  // setter getter for globalTxId
+  // setter getter for localTxId
+}
+@SagaStart
+public void foo(BarCommand cmd) {
+  TransactionContext txContext = OmegaContext.getTransactionContext();
+  BarCommandWithTxContext cmdWithTxContext = new BarCommandWithTxContext(cmd);
+  cmdWithTxContext.setGlobalTxId(txContext.globalTxId());
+  cmdWithTxContext.setLocalTxId(txContext.localTxId());
+  someRpc.send(cmdWithTxContext);
+}
+```
+
+Service B:
+
+```java
+public void listen(BarCommandWithTxContext cmdWithTxContext) {
+  bar(cmdWithTxContext);
+}
+
+@Compensable
+public void bar(BarCommandWithTxContext cmdWithTxContext) {
+  ...
+  // TransactionContext childTxContext = OmegaContext.getTransactionContext();
+}
+```
+
+和前面一种方式类似,TransactionContextProperties.get{Global,Local}TxId()返回的也是父事务上下文信息。
+
 ### TCC 支持
 在对应的方法中添加TccStart 和 Participate标注 
  以一个转账应用为例:
+
 1. 在全局事务的起点添加 `@TccStart` 的注解。
    ```java
    import org.apache.servicecomb.pack.omega.context.annotations.TccStart;
@@ -165,6 +267,8 @@ Saga可通过以下任一方式进行构建:
 5. 从pack-0.3.0开始, 你可以在服务函数或者取消函数中通过访问 
[OmegaContext](https://github.com/apache/servicecomb-pack/blob/master/omega/omega-context/src/main/java/org/apache/servicecomb/pack/omega/context/OmegaContext.java)
 来获取 gloableTxId 以及 localTxId 信息。
 
 
+
+
 ## 如何运行
 1. 运行postgreSQL,
    ```bash
@@ -577,7 +681,6 @@ Saga可通过以下任一方式进行构建:
 
    **注意:** 更多 Nacos 参数请参考 [Spring Cloud Nacos Discovery 
](https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html)
    
-
 2. 验证是否注册成功
 
    访问Nacos的实例, 通过nacos 提供的openapi`curl -X GET 
'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=servicecomb-alpha-server‘`
 可以看到如下服务注册信息,在metadata 中可以发现gRPC的地址已经被注册
@@ -614,7 +717,7 @@ Saga可通过以下任一方式进行构建:
     "env": "",
     "clusters": ""
     }
-    ```
+   ```
    **注意:** 
默认情况下注册的服务名是`servicecomb-alpha-server`,如果你需要自定义服务名可以在运行Alpha的时候通过命令行参数`spring.application.name`配置
 
 3. 配置omega

Reply via email to