You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by se...@apache.org on 2018/01/24 07:44:21 UTC

[incubator-servicecomb-saga] branch master updated: SCB-151 Update to add the pack-demo

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

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


The following commit(s) were added to refs/heads/master by this push:
     new f5f0b31  SCB-151 Update to add the pack-demo
f5f0b31 is described below

commit f5f0b317f40b1baef1143f74dab1e8c83f0d8249
Author: Zheng Feng <zh...@gmail.com>
AuthorDate: Tue Jan 23 11:52:48 2018 +0800

    SCB-151 Update to add the pack-demo
---
 saga-demo/pack-demo/README.md                      | 48 ++++++++++++
 saga-demo/{ => pack-demo/booking}/pom.xml          | 85 +++++++++++-----------
 .../saga/demo/pack/booking/Application.java        | 30 ++++++++
 .../saga/demo/pack/booking/BookingController.java  | 45 ++++++++++++
 .../booking/src/main/resources/application.yaml    | 22 ++++++
 saga-demo/{ => pack-demo/car}/pom.xml              | 85 +++++++++++-----------
 .../saga/demo/pack/car/Application.java            | 30 ++++++++
 .../servicecomb/saga/demo/pack/car/CarBooking.java | 66 +++++++++++++++++
 .../saga/demo/pack/car/CarBookingController.java   | 50 +++++++++++++
 .../saga/demo/pack/car/CarBookingService.java      | 49 +++++++++++++
 .../car/src/main/resources/application.yaml        | 22 ++++++
 saga-demo/pack-demo/docker-compose.yaml            | 76 +++++++++++++++++++
 saga-demo/{ => pack-demo/hotel}/pom.xml            | 85 +++++++++++-----------
 .../saga/demo/pack/hotel/Application.java          | 30 ++++++++
 .../saga/demo/pack/hotel/HotelBooking.java         | 66 +++++++++++++++++
 .../demo/pack/hotel/HotelBookingController.java    | 51 +++++++++++++
 .../saga/demo/pack/hotel/HotelBookingService.java  | 52 +++++++++++++
 .../hotel/src/main/resources/application.yaml      | 22 ++++++
 saga-demo/pack-demo/pom.xml                        | 37 ++++++++++
 saga-demo/pom.xml                                  |  1 +
 20 files changed, 826 insertions(+), 126 deletions(-)

diff --git a/saga-demo/pack-demo/README.md b/saga-demo/pack-demo/README.md
new file mode 100644
index 0000000..1e8d700
--- /dev/null
+++ b/saga-demo/pack-demo/README.md
@@ -0,0 +1,48 @@
+# Pack Transaction Demo
+This demo simulates a booking application including three services:
+* pack-booking
+* pack-car
+* pack-hotel
+
+## Running Demo
+1. run the following command to create docker images in saga project root folder.
+```
+mvn package -DskipTests -Pdocker -Pdemo
+```
+
+2. start application up in saga/saga-demo/pack-demo with the following command
+```
+docker-compose up
+```
+
+## User Requests
+1. Booking 2 rooms and 2 cars, this booking will be OK.
+```
+curl -X POST http://{docker.host.ip}:8083/booking/test/2/2
+```
+Check the hotel booking status with
+```
+curl http://{docker.host.ip}:8081/bookings
+```
+Check the car booking status with
+```
+curl http://{docker.host.ip}:8082/bookings
+
+```
+
+2. Booking 3 rooms and 2 cars, this booking will case the hotel order failed and trigger the compansate operation with car booking.
+```
+curl -X POST http://{docker.host.ip}:8083/booking/test/3/2
+```
+Check the hotel booking status with
+```
+curl http://{docker.host.ip}:8081/bookings
+```
+Check the car booking status with
+```
+curl http://{docker.host.ip}:8082/bookings
+```
+The second car booking will be marked with **cancel:true**
+
+
+**Note** transactions and compensations implemented by services must be idempotent.
diff --git a/saga-demo/pom.xml b/saga-demo/pack-demo/booking/pom.xml
similarity index 50%
copy from saga-demo/pom.xml
copy to saga-demo/pack-demo/booking/pom.xml
index 4e6c28c..47a8f9e 100644
--- a/saga-demo/pom.xml
+++ b/saga-demo/pack-demo/booking/pom.xml
@@ -18,64 +18,65 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
-    <artifactId>saga</artifactId>
-    <groupId>org.apache.servicecomb.saga</groupId>
+    <artifactId>pack-demo</artifactId>
+    <groupId>org.apache.servicecomb.saga.demo</groupId>
     <version>0.0.3-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.servicecomb.saga.demo</groupId>
-  <artifactId>saga-demo</artifactId>
-  <name>Saga::Demo</name>
-
-  <packaging>pom</packaging>
-  <modules>
-    <module>dependency-free-transaction-demo</module>
-    <module>conditional-transaction-demo</module>
-  </modules>
-
-  <dependencyManagement>
-    <dependencies>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-test</artifactId>
-        <version>${spring.boot.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-          </exclusion>
-        </exclusions>
-        <scope>test</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-dependencies</artifactId>
-        <version>${spring.boot.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
+  <artifactId>pack-booking</artifactId>
+  <name>Saga::Demo::Pack::Booking</name>
 
   <dependencies>
     <dependency>
       <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-test</artifactId>
-      <scope>test</scope>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.saga</groupId>
+      <artifactId>omega-spring-starter</artifactId>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicecomb.saga</groupId>
+       <artifactId>omega-transport-resttemplate</artifactId>
+     </dependency>
   </dependencies>
 
   <build>
     <plugins>
+      <!-- mixin plugin configurations declared in another pom,
+      just like importing dependencies managed in another pom -->
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-deploy-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
+        <groupId>com.github.odavid.maven.plugins</groupId>
+        <artifactId>mixin-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
     </plugins>
   </build>
 
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.commonjava.maven.plugins</groupId>
+            <artifactId>directory-maven-plugin</artifactId>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
 </project>
diff --git a/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java b/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java
new file mode 100644
index 0000000..2dda806
--- /dev/null
+++ b/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/Application.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.booking;
+
+import org.apache.servicecomb.saga.omega.spring.EnableOmega;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableOmega
+public class Application {
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+}
diff --git a/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java b/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java
new file mode 100644
index 0000000..a2d88a4
--- /dev/null
+++ b/saga-demo/pack-demo/booking/src/main/java/org/apache/servicecomb/saga/demo/pack/booking/BookingController.java
@@ -0,0 +1,45 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.booking;
+
+import org.apache.servicecomb.saga.omega.context.annotations.SagaStart;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+@RestController
+public class BookingController {
+  @Autowired
+  private RestTemplate template;
+
+  @SagaStart
+  @PostMapping("/booking/{name}/{rooms}/{cars}")
+  public String order(@PathVariable String name,  @PathVariable Integer rooms, @PathVariable Integer cars) {
+    template.postForEntity(
+        "http://pack-car.servicecomb.io:8080/order/{name}/{cars}",
+        null, String.class, name, cars);
+
+    template.postForEntity(
+        "http://pack-hotel.servicecomb.io:8080/order/{name}/{rooms}",
+        null, String.class, name, rooms);
+
+    return name + " booking " + rooms + " rooms and " + cars + " cars OK";
+  }
+}
diff --git a/saga-demo/pack-demo/booking/src/main/resources/application.yaml b/saga-demo/pack-demo/booking/src/main/resources/application.yaml
new file mode 100644
index 0000000..ef8f833
--- /dev/null
+++ b/saga-demo/pack-demo/booking/src/main/resources/application.yaml
@@ -0,0 +1,22 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+spring:
+  application:
+    name: pack-booking
+alpha:
+  cluster:
+    address: alpha-server.servicecomb.io:8080
diff --git a/saga-demo/pom.xml b/saga-demo/pack-demo/car/pom.xml
similarity index 50%
copy from saga-demo/pom.xml
copy to saga-demo/pack-demo/car/pom.xml
index 4e6c28c..78ebd5f 100644
--- a/saga-demo/pom.xml
+++ b/saga-demo/pack-demo/car/pom.xml
@@ -18,64 +18,65 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
-    <artifactId>saga</artifactId>
-    <groupId>org.apache.servicecomb.saga</groupId>
+    <artifactId>pack-demo</artifactId>
+    <groupId>org.apache.servicecomb.saga.demo</groupId>
     <version>0.0.3-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.servicecomb.saga.demo</groupId>
-  <artifactId>saga-demo</artifactId>
-  <name>Saga::Demo</name>
-
-  <packaging>pom</packaging>
-  <modules>
-    <module>dependency-free-transaction-demo</module>
-    <module>conditional-transaction-demo</module>
-  </modules>
-
-  <dependencyManagement>
-    <dependencies>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-test</artifactId>
-        <version>${spring.boot.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-          </exclusion>
-        </exclusions>
-        <scope>test</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-dependencies</artifactId>
-        <version>${spring.boot.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
+  <artifactId>pack-car</artifactId>
+  <name>Saga::Demo::Pack::Car</name>
 
   <dependencies>
     <dependency>
       <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-test</artifactId>
-      <scope>test</scope>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.saga</groupId>
+      <artifactId>omega-spring-starter</artifactId>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicecomb.saga</groupId>
+       <artifactId>omega-transport-resttemplate</artifactId>
     </dependency>
   </dependencies>
 
   <build>
     <plugins>
+      <!-- mixin plugin configurations declared in another pom,
+      just like importing dependencies managed in another pom -->
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-deploy-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
+        <groupId>com.github.odavid.maven.plugins</groupId>
+        <artifactId>mixin-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
     </plugins>
   </build>
 
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.commonjava.maven.plugins</groupId>
+            <artifactId>directory-maven-plugin</artifactId>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
 </project>
diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java
new file mode 100644
index 0000000..a4fe3d9
--- /dev/null
+++ b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/Application.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.car;
+
+import org.apache.servicecomb.saga.omega.spring.EnableOmega;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableOmega
+public class Application {
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+}
diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java
new file mode 100644
index 0000000..11b936d
--- /dev/null
+++ b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBooking.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.car;
+
+public class CarBooking {
+  private Integer id;
+  private String name;
+  private Integer cars;
+  private boolean confirm;
+  private boolean cancel;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public void setId(Integer id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Integer getCars() {
+    return cars;
+  }
+
+  public void setCars(Integer cars) {
+    this.cars = cars;
+  }
+
+  public boolean isConfirm() {
+    return confirm;
+  }
+
+  public void setConfirm(boolean confirm) {
+    this.confirm = confirm;
+  }
+
+  public boolean isCancel() {
+    return cancel;
+  }
+
+  public void setCancel(boolean cancel) {
+    this.cancel = cancel;
+  }
+}
diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java
new file mode 100644
index 0000000..60849aa
--- /dev/null
+++ b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingController.java
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.car;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@RestController
+public class CarBookingController {
+  @Autowired
+  private CarBookingService service;
+
+  private AtomicInteger id = new AtomicInteger(0);
+
+  @GetMapping("/bookings") List<CarBooking> getAll() {
+    return new ArrayList<>(service.getAllBookings());
+  }
+
+  @PostMapping("/order/{name}/{cars}")
+  CarBooking order(@PathVariable String name, @PathVariable Integer cars) {
+    CarBooking booking = new CarBooking();
+    booking.setId(id.incrementAndGet());
+    booking.setName(name);
+    booking.setCars(cars);
+    service.order(booking);
+    return booking;
+  }
+}
diff --git a/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java
new file mode 100644
index 0000000..8c3f8f4
--- /dev/null
+++ b/saga-demo/pack-demo/car/src/main/java/org/apache/servicecomb/saga/demo/pack/car/CarBookingService.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.car;
+
+import org.apache.servicecomb.saga.omega.transaction.annotations.Compensable;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class CarBookingService {
+  private ConcurrentHashMap<Integer, CarBooking> bookings = new ConcurrentHashMap<>();
+
+  @Compensable(compensationMethod = "cancel")
+  public void order(CarBooking booking) {
+    booking.setConfirm(true);
+    booking.setCancel(false);
+    bookings.put(booking.getId(), booking);
+  }
+
+  public void cancel(CarBooking booking) {
+    Integer id = booking.getId();
+    if (bookings.containsKey(id)) {
+      CarBooking origin = bookings.get(id);
+      origin.setConfirm(false);
+      origin.setCancel(true);
+    }
+  }
+
+  public Collection<CarBooking> getAllBookings() {
+    return bookings.values();
+  }
+}
diff --git a/saga-demo/pack-demo/car/src/main/resources/application.yaml b/saga-demo/pack-demo/car/src/main/resources/application.yaml
new file mode 100644
index 0000000..2a1c2b7
--- /dev/null
+++ b/saga-demo/pack-demo/car/src/main/resources/application.yaml
@@ -0,0 +1,22 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+spring:
+  application:
+    name: pack-car
+alpha:
+  cluster:
+    address: alpha-server.servicecomb.io:8080
diff --git a/saga-demo/pack-demo/docker-compose.yaml b/saga-demo/pack-demo/docker-compose.yaml
new file mode 100644
index 0000000..b452d24
--- /dev/null
+++ b/saga-demo/pack-demo/docker-compose.yaml
@@ -0,0 +1,76 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+version: '2.1'
+
+services:
+  postgres:
+    image: "postgres"
+    hostname: postgres
+    environment:
+      - POSTGRES_DB=saga
+      - POSTGRES_USER=saga
+      - POSTGRES_PASSWORD=password
+    healthcheck:
+        test: ["CMD-SHELL", "nc -z localhost 5432 &> /dev/null; echo $$?"]
+        interval: 30s
+        timeout: 10s
+        retries: 5
+
+  alpha:
+    image: "alpha-server:0.0.3-SNAPSHOT"
+    hostname: alpha-server
+    links:
+      - "postgres:postgresql.servicecomb.io"
+    environment:
+      - JAVA_OPTS=-Dspring.profiles.active=prd
+    depends_on:
+      postgres:
+        condition: service_healthy
+
+  pack-hotel:
+    image: "pack-hotel:0.0.3-SNAPSHOT"
+    hostname: pack-hotel
+    links:
+      - "alpha:alpha-server.servicecomb.io"
+    ports:
+      - "8081:8080"
+    depends_on:
+      - alpha
+
+  pack-car:
+    image: "pack-car:0.0.3-SNAPSHOT"
+    hostname: pack-car
+    links:
+      - "alpha:alpha-server.servicecomb.io"
+    ports:
+      - "8082:8080"
+    depends_on:
+      - alpha
+
+  pack-booking:
+    image: "pack-booking:0.0.3-SNAPSHOT"
+    hostname: pack-booking
+    links:
+      - "alpha:alpha-server.servicecomb.io"
+      - "pack-hotel:pack-hotel.servicecomb.io"
+      - "pack-car:pack-car.servicecomb.io"
+    ports:
+      - "8083:8080"
+    depends_on:
+      - pack-hotel
+      - pack-car
diff --git a/saga-demo/pom.xml b/saga-demo/pack-demo/hotel/pom.xml
similarity index 50%
copy from saga-demo/pom.xml
copy to saga-demo/pack-demo/hotel/pom.xml
index 4e6c28c..8b4dc09 100644
--- a/saga-demo/pom.xml
+++ b/saga-demo/pack-demo/hotel/pom.xml
@@ -18,64 +18,65 @@
 
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
-    <artifactId>saga</artifactId>
-    <groupId>org.apache.servicecomb.saga</groupId>
+    <artifactId>pack-demo</artifactId>
+    <groupId>org.apache.servicecomb.saga.demo</groupId>
     <version>0.0.3-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.servicecomb.saga.demo</groupId>
-  <artifactId>saga-demo</artifactId>
-  <name>Saga::Demo</name>
-
-  <packaging>pom</packaging>
-  <modules>
-    <module>dependency-free-transaction-demo</module>
-    <module>conditional-transaction-demo</module>
-  </modules>
-
-  <dependencyManagement>
-    <dependencies>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-test</artifactId>
-        <version>${spring.boot.version}</version>
-        <exclusions>
-          <exclusion>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-          </exclusion>
-        </exclusions>
-        <scope>test</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-dependencies</artifactId>
-        <version>${spring.boot.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
+  <artifactId>pack-hotel</artifactId>
+  <name>Saga::Demo::Pack::Hotel</name>
 
   <dependencies>
     <dependency>
       <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-test</artifactId>
-      <scope>test</scope>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-web</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb.saga</groupId>
+      <artifactId>omega-spring-starter</artifactId>
+    </dependency>
+    <dependency>
+       <groupId>org.apache.servicecomb.saga</groupId>
+       <artifactId>omega-transport-resttemplate</artifactId>
     </dependency>
   </dependencies>
 
   <build>
     <plugins>
+      <!-- mixin plugin configurations declared in another pom,
+      just like importing dependencies managed in another pom -->
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-deploy-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
+        <groupId>com.github.odavid.maven.plugins</groupId>
+        <artifactId>mixin-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
       </plugin>
     </plugins>
   </build>
 
+  <profiles>
+    <profile>
+      <id>docker</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.commonjava.maven.plugins</groupId>
+            <artifactId>directory-maven-plugin</artifactId>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
 </project>
diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java
new file mode 100644
index 0000000..26a55e3
--- /dev/null
+++ b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/Application.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.hotel;
+
+import org.apache.servicecomb.saga.omega.spring.EnableOmega;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableOmega
+public class Application {
+  public static void main(String[] args) {
+    SpringApplication.run(Application.class, args);
+  }
+}
diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java
new file mode 100644
index 0000000..e7c748c
--- /dev/null
+++ b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBooking.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.hotel;
+
+public class HotelBooking {
+  private Integer id;
+  private String name;
+  private Integer rooms;
+  private boolean confirm;
+  private boolean cancel;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public void setId(Integer id) {
+    this.id = id;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Integer getRooms() {
+    return rooms;
+  }
+
+  public void setRooms(Integer rooms) {
+    this.rooms = rooms;
+  }
+
+  public boolean isConfirm() {
+    return confirm;
+  }
+
+  public void setConfirm(boolean confirm) {
+    this.confirm = confirm;
+  }
+
+  public boolean isCancel() {
+    return cancel;
+  }
+
+  public void setCancel(boolean cancel) {
+    this.cancel = cancel;
+  }
+}
diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java
new file mode 100644
index 0000000..0474d71
--- /dev/null
+++ b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingController.java
@@ -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 org.apache.servicecomb.saga.demo.pack.hotel;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@RestController
+public class HotelBookingController {
+  @Autowired
+  private HotelBookingService service;
+
+  private AtomicInteger id = new AtomicInteger(0);
+
+  @GetMapping("/bookings")
+  List<HotelBooking> getAll() {
+    return new ArrayList<>(service.getAllBookings());
+  }
+
+  @PostMapping("/order/{name}/{rooms}")
+  HotelBooking order(@PathVariable String name, @PathVariable Integer rooms) {
+    HotelBooking booking = new HotelBooking();
+    booking.setId(id.incrementAndGet());
+    booking.setName(name);
+    booking.setRooms(rooms);
+    service.order(booking);
+    return booking;
+  }
+}
diff --git a/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java
new file mode 100644
index 0000000..d819843
--- /dev/null
+++ b/saga-demo/pack-demo/hotel/src/main/java/org/apache/servicecomb/saga/demo/pack/hotel/HotelBookingService.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.servicecomb.saga.demo.pack.hotel;
+
+import org.apache.servicecomb.saga.omega.transaction.annotations.Compensable;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class HotelBookingService {
+  private ConcurrentHashMap<Integer, HotelBooking> bookings = new ConcurrentHashMap<>();
+
+  @Compensable(compensationMethod = "cancel")
+  public void order(HotelBooking booking) {
+    if (booking.getRooms() > 2) {
+      throw new IllegalArgumentException("can not order the rooms large than two");
+    }
+    booking.setConfirm(true);
+    booking.setCancel(false);
+    bookings.put(booking.getId(), booking);
+  }
+
+  public void cancel(HotelBooking booking) {
+    Integer id = booking.getId();
+    if (bookings.containsKey(id)) {
+      HotelBooking origin = bookings.get(id);
+      origin.setConfirm(false);
+      origin.setCancel(true);
+    }
+  }
+
+  public Collection<HotelBooking> getAllBookings() {
+    return bookings.values();
+  }
+}
diff --git a/saga-demo/pack-demo/hotel/src/main/resources/application.yaml b/saga-demo/pack-demo/hotel/src/main/resources/application.yaml
new file mode 100644
index 0000000..cb03be0
--- /dev/null
+++ b/saga-demo/pack-demo/hotel/src/main/resources/application.yaml
@@ -0,0 +1,22 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+spring:
+  application:
+    name: pack-hotel
+alpha:
+  cluster:
+    address: alpha-server.servicecomb.io:8080
diff --git a/saga-demo/pack-demo/pom.xml b/saga-demo/pack-demo/pom.xml
new file mode 100644
index 0000000..3b3453e
--- /dev/null
+++ b/saga-demo/pack-demo/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>saga-demo</artifactId>
+    <groupId>org.apache.servicecomb.saga.demo</groupId>
+    <version>0.0.3-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>pack-demo</artifactId>
+  <name>Saga::Demo::Pack</name>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>booking</module>
+    <module>car</module>
+    <module>hotel</module>
+  </modules>
+
+</project>
diff --git a/saga-demo/pom.xml b/saga-demo/pom.xml
index 4e6c28c..dfdef26 100644
--- a/saga-demo/pom.xml
+++ b/saga-demo/pom.xml
@@ -32,6 +32,7 @@
   <modules>
     <module>dependency-free-transaction-demo</module>
     <module>conditional-transaction-demo</module>
+    <module>pack-demo</module>
   </modules>
 
   <dependencyManagement>

-- 
To stop receiving notification emails like this one, please contact
seanyinx@apache.org.