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 <[email protected]>
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());
+ }
+}