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-saga.git


The following commit(s) were added to refs/heads/master by this push:
     new 10cdd07  Implement Saga Console API's
10cdd07 is described below

commit 10cdd07742497d349c087c8f641e466455b137bb
Author: asifdxtreme <mohammad.asif.siddiq...@huawei.com>
AuthorDate: Tue Oct 30 16:28:22 2018 +0530

    Implement Saga Console API's
---
 .../alpha/server/TxEventEnvelopeRepository.java    | 137 ++++++++++-
 .../console/saga/SagaTransactionsController.java   | 255 +++++++++++++++++++++
 .../alpha/server/console/saga/model/Stats.java     | 103 +++++++++
 3 files changed, 494 insertions(+), 1 deletion(-)

diff --git 
a/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/TxEventEnvelopeRepository.java
 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/TxEventEnvelopeRepository.java
index 89808c9..ebb7610 100644
--- 
a/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/TxEventEnvelopeRepository.java
+++ 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/TxEventEnvelopeRepository.java
@@ -28,7 +28,7 @@ import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.CrudRepository;
 
-interface TxEventEnvelopeRepository extends CrudRepository<TxEvent, Long> {
+public interface TxEventEnvelopeRepository extends CrudRepository<TxEvent, 
Long> {
   List<TxEvent> findByGlobalTxId(String globalTxId);
 
   @Query("SELECT t FROM TxEvent t "
@@ -124,6 +124,141 @@ interface TxEventEnvelopeRepository extends 
CrudRepository<TxEvent, Long> {
       + "  AND t1.surrogateId > t.surrogateId )")
   List<TxEvent> findDuplicateEventsByType(String type);
 
+  List<TxEvent> findByServiceName(String serviceName);
+
+  @Query("SELECT count(t) FROM TxEvent t" +
+      " WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent'))")
+  int findCountOfCompensatingEvents();
+
+  @Query("SELECT t FROM TxEvent t" +
+      " WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findCompensatingEvents();
+
+  @Query("SELECT t FROM TxEvent t" +
+      " WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findCompensatingEvents(Pageable pageable);
+
+  @Query("SELECT count(t) FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent', 'TxCompensatedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent'))\n")
+  int findCountOfCommittedEvents();
+
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent', 'TxCompensatedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findCommittedEvents();
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent', 'TxCompensatedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findCommittedEvents(Pageable pageable);
+
+  @Query("SELECT count(t) FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent'))\n")
+  int findCountOfPendingEvents();
+
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findPendingEvents();
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND NOT EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findPendingEvents(Pageable pageable);
+
+  @Query("SELECT count(t) FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM " +
+      "TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxCompensatedEvent'))\n")
+  int findCountOfRollBackedEvents();
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM " +
+      "TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxCompensatedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findRollBackedEvents();
+
+  @Query("SELECT t FROM TxEvent t " +
+      "WHERE t.type = 'SagaStartedEvent' " +
+      "AND EXISTS(  SELECT t1.globalTxId " +
+      "FROM TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxAbortedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM " +
+      "TxEvent t1 WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('SagaEndedEvent')) " +
+      "AND EXISTS(  SELECT t1.globalTxId FROM TxEvent t1 " +
+      "WHERE t1.globalTxId = t.globalTxId  " +
+      "AND t1.type IN ('TxCompensatedEvent')) " +
+      "ORDER BY t.surrogateId DESC")
+  List<TxEvent> findRollBackedEvents(Pageable pageable);
+
+  @Query("SELECT count(DISTINCT t.globalTxId) FROM TxEvent t")
+  int findTotalCountOfTransactions();
+
   @Transactional
   @Modifying(clearAutomatically = true)
   @Query("DELETE FROM TxEvent WHERE surrogateId = ?1 ")
diff --git 
a/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/SagaTransactionsController.java
 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/SagaTransactionsController.java
new file mode 100644
index 0000000..bafb25d
--- /dev/null
+++ 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/SagaTransactionsController.java
@@ -0,0 +1,255 @@
+/*
+ * 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.alpha.server.console.saga;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+
+import kamon.annotation.EnableKamon;
+import kamon.annotation.Trace;
+
+import org.apache.servicecomb.saga.alpha.core.TxEvent;
+import org.apache.servicecomb.saga.alpha.server.TxEventEnvelopeRepository;
+import org.apache.servicecomb.saga.alpha.server.console.saga.model.Stats;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.lang.invoke.MethodHandles;
+import java.util.*;
+
+@EnableKamon
+@Controller
+@RequestMapping("/saga")
+
+public class SagaTransactionsController {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  private final TxEventEnvelopeRepository eventRepository;
+
+  SagaTransactionsController(TxEventEnvelopeRepository eventRepository) {
+    this.eventRepository = eventRepository;
+  }
+
+  @Trace("getStats")
+  @GetMapping(value = "/stats")
+  ResponseEntity<Stats> getStats() {
+        /*
+        This function gives returns the count of the transactions listed below
+        1. Total Transactions
+        2. PENDING
+        3. COMMITTED
+        4. COMPENSATING
+        5. ROLLBACKED
+        6. FAILURERATE
+
+        Sample Response
+        {
+            "totalTransaction": 10,
+            "PENDING": 3,
+            "COMMITTED": 1,
+            "COMPENSATING": 2,
+            "ROLLBACKED": 4,
+            "FAILURERATE": 60,
+            "updatedAt": 1540450937
+        }
+         */
+    Stats oStats = new Stats(eventRepository.findTotalCountOfTransactions(), 
eventRepository.findCountOfPendingEvents(),
+        eventRepository.findCountOfCommittedEvents(), 
eventRepository.findCountOfCompensatingEvents(),
+        eventRepository.findCountOfRollBackedEvents());
+    return ResponseEntity.ok(oStats);
+  }
+
+
+  @Trace("getRecentTransactions")
+  @GetMapping(value = "/recent")
+  ResponseEntity<Collection<SagaTransactionsController.TxEventVo>> 
recentTransactions(
+      @RequestParam(name = "status") String status, @RequestParam(name = 
"count") int count) {
+        /*
+        This will return the list of recent transactions
+        Parameters :
+        status - Status of transaction (PENDING, COMMITTED, COMPENSATING, 
ROLLBACKED)
+        count - Number of last transactions to be returned (max: 15, default: 
5)
+
+        Sample Response
+        [
+            {
+                "surrogateId": 6,
+                "serviceName": "booking",
+                "instanceId": "booking-172.23.0.7",
+                "creationTime": 1540823579335,
+                "globalTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "localTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "parentTxId": null,
+                "type": "SagaEndedEvent",
+                "compensationMethod": "",
+                "expiryTime": 253402214400000,
+                "retryMethod": "",
+                "retries": 0,
+                "payloads": "AQE="
+            }
+        ]
+         */
+    Iterable<TxEvent> events;
+
+    List<SagaTransactionsController.TxEventVo> eventVos = new LinkedList<>();
+    switch (status) {
+      case "PENDING":
+        events = eventRepository.findPendingEvents(new PageRequest(0, count));
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "COMMITTED":
+        events = eventRepository.findCommittedEvents(new PageRequest(0, 
count));
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "COMPENSATING":
+        events = eventRepository.findCompensatingEvents(new PageRequest(0, 
count));
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "ROLLBACKED":
+        events = eventRepository.findRollBackedEvents(new PageRequest(0, 
count));
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      default:
+        LOG.info("Unknown Status");
+    }
+    return ResponseEntity.ok(eventVos);
+  }
+
+  @Trace("getTransactions")
+  @GetMapping(value = "/transactions")
+  ResponseEntity<Collection<SagaTransactionsController.TxEventVo>> 
getTransactions(
+      @RequestParam(name = "status") String status) {
+        /*
+        This will return the list of transactions with pagination enabled.
+        Parameters :
+            status - Status of transaction (ALL, PENDING, COMMITTED, 
COMPENSATING, ROLLBACKED)
+            pagination - is pagination enabled
+            countPerPage - List of elements per page
+            pageNumber - Current Page to be sent
+
+        Sample Response
+        [
+            {
+                "surrogateId": 6,
+                "serviceName": "booking",
+                "instanceId": "booking-172.23.0.7",
+                "creationTime": 1540823579335,
+                "globalTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "localTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "parentTxId": null,
+                "type": "SagaEndedEvent",
+                "compensationMethod": "",
+                "expiryTime": 253402214400000,
+                "retryMethod": "",
+                "retries": 0,
+                "payloads": "AQE="
+            }
+        ]
+         */
+    //TODO Pagination
+
+    Iterable<TxEvent> events;
+
+    List<SagaTransactionsController.TxEventVo> eventVos = new LinkedList<>();
+
+    switch (status) {
+      case "PENDING":
+        events = eventRepository.findPendingEvents();
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "COMMITTED":
+        events = eventRepository.findCommittedEvents();
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "COMPENSATING":
+        events = eventRepository.findCompensatingEvents();
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "ROLLBACKED":
+        events = eventRepository.findRollBackedEvents();
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      case "ALL":
+        events = eventRepository.findAll();
+        events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+        break;
+      default:
+        LOG.info("Unknown Status");
+    }
+
+    return ResponseEntity.ok(eventVos);
+  }
+
+  @Trace("findTransactions")
+  @GetMapping(value = "/findTransactions")
+  ResponseEntity<Collection<SagaTransactionsController.TxEventVo>> 
findTransactions(
+      @RequestParam(required = false, name = "globalTxID") Object globalTxID,
+      @RequestParam(required = false, name = "microServiceName") String 
microServiceName) {
+        /*
+        This will return all the list of sub-transactions  for a particular 
Global ID or MicroService.
+        Parameter :
+            globalID : GlobalID of the transactions
+            microserviceName : Name of the Microservice
+        Sample Response
+        [
+            {
+                "surrogateId": 6,
+                "serviceName": "booking",
+                "instanceId": "booking-172.23.0.7",
+                "creationTime": 1540823579335,
+                "globalTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "localTxId": "daa74121-9e00-4567-96b7-dc9fd163060b",
+                "parentTxId": null,
+                "type": "SagaEndedEvent",
+                "compensationMethod": "",
+                "expiryTime": 253402214400000,
+                "retryMethod": "",
+                "retries": 0,
+                "payloads": "AQE="
+            }
+        ]
+         */
+
+    Iterable<TxEvent> events;
+    if (globalTxID != null) {
+      events = eventRepository.findByGlobalTxId(globalTxID.toString());
+    } else if (microServiceName != "") {
+      events = eventRepository.findByServiceName(microServiceName);
+    } else {
+      events = null;
+    }
+
+    Collection<TxEventVo> eventVos = new LinkedList<>();
+    events.forEach(event -> eventVos.add(new 
SagaTransactionsController.TxEventVo(event)));
+
+    return ResponseEntity.ok(eventVos);
+  }
+
+  @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
+  private static class TxEventVo extends TxEvent {
+    private TxEventVo(TxEvent event) {
+      super(event);
+    }
+  }
+}
diff --git 
a/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/model/Stats.java
 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/model/Stats.java
new file mode 100644
index 0000000..befaa03
--- /dev/null
+++ 
b/alpha/alpha-server/src/main/java/org/apache/servicecomb/saga/alpha/server/console/saga/model/Stats.java
@@ -0,0 +1,103 @@
+/*
+ * 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.alpha.server.console.saga.model;
+
+import java.util.Date;
+
+public class Stats {
+
+  public int getTotalTransactions() {
+    return totalTransactions;
+  }
+
+  public void setTotalTransactions(int totalTransactions) {
+    this.totalTransactions = totalTransactions;
+  }
+
+  private int totalTransactions;
+
+  public int getPendingTransactions() {
+    return pendingTransactions;
+  }
+
+  public void setPendingTransactions(int pendingTransactions) {
+    this.pendingTransactions = pendingTransactions;
+  }
+
+  public int getCommittedTransactions() {
+    return committedTransactions;
+  }
+
+  public void setCommittedTransactions(int committedTransactions) {
+    this.committedTransactions = committedTransactions;
+  }
+
+  public int getCompensatingTransactions() {
+    return compensatingTransactions;
+  }
+
+  public void setCompensatingTransactions(int compensatingTransactions) {
+    this.compensatingTransactions = compensatingTransactions;
+  }
+
+  public int getRollbackTransactions() {
+    return rollbackTransactions;
+  }
+
+  public void setRollbackTransactions(int rollbackTransactions) {
+    this.rollbackTransactions = rollbackTransactions;
+  }
+
+  private int pendingTransactions;
+
+  private int committedTransactions;
+
+  private int compensatingTransactions;
+
+  private int rollbackTransactions;
+
+  public Date getUpdatedAt() {
+    return updatedAt;
+  }
+
+  public void setUpdatedAt(Date updatedAt) {
+    this.updatedAt = updatedAt;
+  }
+
+  private Date updatedAt;
+
+  public int getFailureRate() {
+    return failureRate;
+  }
+
+  public void setFailureRate(int failureRate) {
+    this.failureRate = failureRate;
+  }
+
+  private int failureRate;
+
+  public Stats(int totalTransactions, int pendingTransactions, int 
committedTransactions, int compensatingTransactions,
+      int rollbackTransactions) {
+    setTotalTransactions(totalTransactions);
+    setPendingTransactions(pendingTransactions);
+    setCommittedTransactions(committedTransactions);
+    setCompensatingTransactions(compensatingTransactions);
+    setRollbackTransactions(rollbackTransactions);
+    setFailureRate(rollbackTransactions + compensatingTransactions / 
totalTransactions);
+    setUpdatedAt(new Date());
+  }
+}

Reply via email to