You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ni...@apache.org on 2019/08/10 07:50:31 UTC

[servicecomb-pack] 26/36: SCB-1411 Transaction object adds suspended type attribute

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 70e968301883c1fe9096555fcc45f689cb7fa962
Author: Lei Zhang <co...@gmail.com>
AuthorDate: Fri Aug 9 14:05:34 2019 +0800

    SCB-1411 Transaction object adds suspended type attribute
---
 .../pack/alpha/core/fsm/SuspendedType.java         |  5 +++++
 .../pack/alpha/core/fsm/event/TxAbortedEvent.java  |  6 ++++++
 .../alpha/core/fsm/event/TxCompensatedEvent.java   |  6 ++++++
 .../pack/alpha/core/fsm/event/TxStartedEvent.java  |  6 ++++++
 .../fsm/repository/model/GlobalTransaction.java    | 13 +++++++++++
 .../servicecomb/pack/alpha/fsm/SagaActor.java      | 24 +++++++++++++--------
 .../pack/alpha/fsm/domain/SagaEndedDomain.java     | 17 ++++++++++++++-
 .../servicecomb/pack/alpha/fsm/model/SagaData.java | 25 ++++++++++++++++++++++
 .../spring/integration/akka/SagaDataExtension.java |  1 +
 .../alpha/server/fsm/GrpcSagaEventService.java     |  8 ++++++-
 .../alpha/ui/controller/TransactionController.java |  4 ++++
 .../resources/templates/transaction_details.html   | 10 ++++++++-
 12 files changed, 113 insertions(+), 12 deletions(-)

diff --git a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/SuspendedType.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/SuspendedType.java
new file mode 100644
index 0000000..82ceffa
--- /dev/null
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/SuspendedType.java
@@ -0,0 +1,5 @@
+package org.apache.servicecomb.pack.alpha.core.fsm;
+
+public enum SuspendedType {
+  NULL, TIMEOUT, UNPREDICTABLE
+}
diff --git a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxAbortedEvent.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxAbortedEvent.java
index b3f8406..3b50a3b 100644
--- a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxAbortedEvent.java
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxAbortedEvent.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.pack.alpha.core.fsm.event;
 
+import java.util.Date;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.TxEvent;
 
 public class TxAbortedEvent extends TxEvent {
@@ -73,6 +74,11 @@ public class TxAbortedEvent extends TxEvent {
       return this;
     }
 
+    public Builder createTime(Date createTime){
+      txAbortedEvent.setCreateTime(createTime);
+      return this;
+    }
+
     public TxAbortedEvent build() {
       return txAbortedEvent;
     }
diff --git a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxCompensatedEvent.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxCompensatedEvent.java
index 127c70d..4b7297a 100644
--- a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxCompensatedEvent.java
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxCompensatedEvent.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.pack.alpha.core.fsm.event;
 
+import java.util.Date;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.TxEvent;
 
 public class TxCompensatedEvent extends TxEvent {
@@ -58,6 +59,11 @@ public class TxCompensatedEvent extends TxEvent {
       return this;
     }
 
+    public Builder createTime(Date createTime){
+      txCompensatedEvent.setCreateTime(createTime);
+      return this;
+    }
+
     public TxCompensatedEvent build() {
       return txCompensatedEvent;
     }
diff --git a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxStartedEvent.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxStartedEvent.java
index 9b1e540..4b6a64b 100644
--- a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxStartedEvent.java
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/event/TxStartedEvent.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.pack.alpha.core.fsm.event;
 
+import java.util.Date;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.TxEvent;
 
 public class TxStartedEvent extends TxEvent {
@@ -114,6 +115,11 @@ public class TxStartedEvent extends TxEvent {
       return this;
     }
 
+    public Builder createTime(Date createTime){
+      txStartedEvent.setCreateTime(createTime);
+      return this;
+    }
+
     public TxStartedEvent build() {
       return txStartedEvent;
     }
diff --git a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/repository/model/GlobalTransaction.java b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/repository/model/GlobalTransaction.java
index f4548bd..01d8956 100644
--- a/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/repository/model/GlobalTransaction.java
+++ b/alpha/alpha-core/src/main/java/org/apache/servicecomb/pack/alpha/core/fsm/repository/model/GlobalTransaction.java
@@ -23,6 +23,7 @@ import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import org.apache.servicecomb.pack.alpha.core.fsm.SuspendedType;
 import org.apache.servicecomb.pack.alpha.core.fsm.TransactionType;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.BaseEvent;
 
@@ -40,6 +41,7 @@ public class GlobalTransaction {
   private Long durationTime;
   private List<SagaSubTransaction> subTransactions = new ArrayList<>();
   private List<Map<String,Object>> events = new LinkedList<>();
+  private SuspendedType suspendedType;
 
   public String getGlobalTxId() {
     return globalTxId;
@@ -85,6 +87,10 @@ public class GlobalTransaction {
     return events;
   }
 
+  public SuspendedType getSuspendedType() {
+    return suspendedType;
+  }
+
   public static Builder builder() {
     return new Builder();
   }
@@ -101,6 +107,7 @@ public class GlobalTransaction {
     private Integer subTxSize;
     private List<SagaSubTransaction> subTransactions;
     private List<BaseEvent> events;
+    private SuspendedType suspendedType;
 
     private Builder() {
     }
@@ -155,6 +162,11 @@ public class GlobalTransaction {
       return this;
     }
 
+    public Builder suspendedType(SuspendedType suspendedType) {
+      this.suspendedType = suspendedType;
+      return this;
+    }
+
     public GlobalTransaction build() {
       GlobalTransaction globalTransaction = new GlobalTransaction();
       globalTransaction.instanceId = this.instanceId;
@@ -167,6 +179,7 @@ public class GlobalTransaction {
       globalTransaction.subTxSize = this.subTxSize;
       globalTransaction.durationTime = this.endTime.getTime() - this.beginTime.getTime();
       globalTransaction.subTransactions = this.subTransactions;
+      globalTransaction.suspendedType = this.suspendedType;
       for(BaseEvent event : events){
         try {
           globalTransaction.events.add(event.toMap());
diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/SagaActor.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/SagaActor.java
index 2734deb..fc06255 100644
--- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/SagaActor.java
+++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/SagaActor.java
@@ -25,6 +25,7 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
 import org.apache.servicecomb.pack.alpha.core.AlphaException;
+import org.apache.servicecomb.pack.alpha.core.fsm.SuspendedType;
 import org.apache.servicecomb.pack.alpha.core.fsm.TxState;
 import org.apache.servicecomb.pack.alpha.fsm.domain.AddTxEventDomain;
 import org.apache.servicecomb.pack.alpha.fsm.domain.DomainEvent;
@@ -75,6 +76,7 @@ public class SagaActor extends
               SagaDataExtension.SAGA_DATA_EXTENSION_PROVIDER.get(context().system()).doSagaBeginCounter();
               SagaStartedDomain domainEvent = new SagaStartedDomain(event);
               if (event.getTimeout() > 0) {
+                data.setTimeout(event.getTimeout());
                 return goTo(SagaActorState.READY)
                     .applying(domainEvent)
                     .forMax(Duration.create(event.getTimeout(), TimeUnit.SECONDS));
@@ -102,19 +104,19 @@ public class SagaActor extends
             }
         ).event(SagaEndedEvent.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED, SuspendedType.UNPREDICTABLE);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             }
         ).event(SagaAbortedEvent.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED, SuspendedType.UNPREDICTABLE);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             }
         ).event(Collections.singletonList(StateTimeout()), SagaData.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(null, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(null, SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             })
@@ -146,7 +148,8 @@ public class SagaActor extends
             }
         ).event(SagaTimeoutEvent.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED,
+                  SuspendedType.TIMEOUT);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             }
@@ -158,7 +161,8 @@ public class SagaActor extends
             }
         ).event(Collections.singletonList(StateTimeout()), SagaData.class,
             (event, data) -> {
-              return goTo(SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(null, SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
+              return goTo(SagaActorState.SUSPENDED).applying(domainEvent);
             })
     );
 
@@ -188,7 +192,7 @@ public class SagaActor extends
             }
         ).event(SagaTimeoutEvent.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             }
@@ -210,14 +214,15 @@ public class SagaActor extends
             }
         ).event(Collections.singletonList(StateTimeout()), SagaData.class,
             (event, data) -> {
-              return goTo(SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(null, SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
+              return goTo(SagaActorState.SUSPENDED).applying(domainEvent);
             })
     );
 
     when(SagaActorState.FAILED,
         matchEvent(SagaTimeoutEvent.class, SagaData.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(event, SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             }
@@ -273,7 +278,7 @@ public class SagaActor extends
             }
         ).event(Arrays.asList(StateTimeout()), SagaData.class,
             (event, data) -> {
-              SagaEndedDomain domainEvent = new SagaEndedDomain(SagaActorState.SUSPENDED);
+              SagaEndedDomain domainEvent = new SagaEndedDomain(SagaActorState.SUSPENDED, SuspendedType.TIMEOUT);
               return goTo(SagaActorState.SUSPENDED)
                   .applying(domainEvent);
             })
@@ -438,6 +443,7 @@ public class SagaActor extends
       } else if (domainEvent.getState() == SagaActorState.SUSPENDED) {
         data.setEndTime(new Date());
         data.setTerminated(true);
+        data.setSuspendedType(domainEvent.getSuspendedType());
       } else if (domainEvent.getState() == SagaActorState.COMPENSATED) {
         data.setEndTime(new Date());
         data.setTerminated(true);
diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/domain/SagaEndedDomain.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/domain/SagaEndedDomain.java
index 778feca..8da396b 100644
--- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/domain/SagaEndedDomain.java
+++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/domain/SagaEndedDomain.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.pack.alpha.fsm.domain;
 
+import org.apache.servicecomb.pack.alpha.core.fsm.SuspendedType;
 import org.apache.servicecomb.pack.alpha.fsm.SagaActorState;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.BaseEvent;
 
@@ -24,16 +25,26 @@ public class SagaEndedDomain implements DomainEvent {
 
   private SagaActorState state;
   private BaseEvent event;
+  private SuspendedType suspendedType;
+
+  public SagaEndedDomain(BaseEvent event, SagaActorState state, SuspendedType suspendedType) {
+    if(event != null){
+      this.event = event;
+    }
+    this.state = state;
+    this.suspendedType = suspendedType;
+  }
 
   public SagaEndedDomain(BaseEvent event, SagaActorState state) {
     if(event != null){
       this.event = event;
     }
     this.state = state;
+    this.suspendedType = SuspendedType.NULL;
   }
 
 
-  public SagaEndedDomain(SagaActorState state) {
+  public SagaEndedDomain(SagaActorState state, SuspendedType suspendedType) {
     this.state = state;
   }
 
@@ -45,4 +56,8 @@ public class SagaEndedDomain implements DomainEvent {
   public BaseEvent getEvent() {
     return event;
   }
+
+  public SuspendedType getSuspendedType() {
+    return suspendedType;
+  }
 }
diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/model/SagaData.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/model/SagaData.java
index 5b214f2..e3974b9 100644
--- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/model/SagaData.java
+++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/model/SagaData.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicLong;
+import org.apache.servicecomb.pack.alpha.core.fsm.SuspendedType;
 import org.apache.servicecomb.pack.alpha.fsm.SagaActorState;
 import org.apache.servicecomb.pack.alpha.core.fsm.event.base.BaseEvent;
 
@@ -34,6 +35,8 @@ public class SagaData implements Serializable {
   private Date endTime;
   private String globalTxId;
   private Date expirationTime;
+  private int timeout;
+  private SuspendedType suspendedType = SuspendedType.NULL;
   private boolean terminated;
   private SagaActorState lastState;
   private AtomicLong compensationRunningCounter = new AtomicLong();
@@ -88,6 +91,18 @@ public class SagaData implements Serializable {
     this.expirationTime = expirationTime;
   }
 
+  public void setTimeout(int timeout) {
+    this.timeout = timeout;
+  }
+
+  public SuspendedType getSuspendedType() {
+    return suspendedType;
+  }
+
+  public void setSuspendedType(SuspendedType suspendedType) {
+    this.suspendedType = suspendedType;
+  }
+
   public boolean isTerminated() {
     return terminated;
   }
@@ -166,6 +181,11 @@ public class SagaData implements Serializable {
       return this;
     }
 
+    public Builder timeout(int timeout) {
+      sagaData.setTimeout(timeout);
+      return this;
+    }
+
     public Builder terminated(boolean terminated) {
       sagaData.setTerminated(terminated);
       return this;
@@ -191,6 +211,11 @@ public class SagaData implements Serializable {
       return this;
     }
 
+    public Builder suspendedType(SuspendedType suspendedType) {
+      sagaData.setSuspendedType(suspendedType);
+      return this;
+    }
+
     public SagaData build() {
       return sagaData;
     }
diff --git a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/spring/integration/akka/SagaDataExtension.java b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/spring/integration/akka/SagaDataExtension.java
index 0451a83..f8b50c7 100644
--- a/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/spring/integration/akka/SagaDataExtension.java
+++ b/alpha/alpha-fsm/src/main/java/org/apache/servicecomb/pack/alpha/fsm/spring/integration/akka/SagaDataExtension.java
@@ -86,6 +86,7 @@ public class SagaDataExtension extends AbstractExtensionId<SagaDataExt> {
           .subTxSize(sagaData.getTxEntityMap().size())
           .subTransactions(subTransactions)
           .events(sagaData.getEvents())
+          .suspendedType(sagaData.getSuspendedType())
           .build();
       repositoryChannel.send(record);
       sagaDataMap.remove(globalTxId);
diff --git a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/fsm/GrpcSagaEventService.java b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/fsm/GrpcSagaEventService.java
index 9c4dac0..cedfc30 100644
--- a/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/fsm/GrpcSagaEventService.java
+++ b/alpha/alpha-server/src/main/java/org/apache/servicecomb/pack/alpha/server/fsm/GrpcSagaEventService.java
@@ -88,22 +88,26 @@ public class GrpcSagaEventService extends TxEventServiceImplBase {
           .serviceName(message.getServiceName())
           .instanceId(message.getInstanceId())
           .globalTxId(message.getGlobalTxId())
+          .createTime(new Date())
           .timeout(message.getTimeout()).build();
     } else if (message.getType().equals(EventType.SagaEndedEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.SagaEndedEvent.builder()
           .serviceName(message.getServiceName())
           .instanceId(message.getInstanceId())
+          .createTime(new Date())
           .globalTxId(message.getGlobalTxId()).build();
     } else if (message.getType().equals(EventType.SagaAbortedEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.SagaAbortedEvent.builder()
           .serviceName(message.getServiceName())
           .instanceId(message.getInstanceId())
           .globalTxId(message.getGlobalTxId())
+          .createTime(new Date())
           .payloads(message.getPayloads().toByteArray()).build();
     } else if (message.getType().equals(EventType.SagaTimeoutEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.SagaTimeoutEvent.builder()
           .serviceName(message.getServiceName())
           .instanceId(message.getInstanceId())
+          .createTime(new Date())
           .globalTxId(message.getGlobalTxId()).build();
     } else if (message.getType().equals(EventType.TxStartedEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.TxStartedEvent.builder()
@@ -115,6 +119,7 @@ public class GrpcSagaEventService extends TxEventServiceImplBase {
           .compensationMethod(message.getCompensationMethod())
           .retryMethod(message.getRetryMethod())
           .retries(message.getRetries())
+          .createTime(new Date())
           .payloads(message.getPayloads().toByteArray()).build();
     } else if (message.getType().equals(EventType.TxEndedEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.TxEndedEvent.builder()
@@ -130,6 +135,7 @@ public class GrpcSagaEventService extends TxEventServiceImplBase {
           .globalTxId(message.getGlobalTxId())
           .parentTxId(message.getParentTxId())
           .localTxId(message.getLocalTxId())
+          .createTime(new Date())
           .payloads(message.getPayloads().toByteArray()).build();
     } else if (message.getType().equals(EventType.TxCompensatedEvent.name())) {
       event = org.apache.servicecomb.pack.alpha.core.fsm.event.TxCompensatedEvent.builder()
@@ -137,12 +143,12 @@ public class GrpcSagaEventService extends TxEventServiceImplBase {
           .instanceId(message.getInstanceId())
           .globalTxId(message.getGlobalTxId())
           .parentTxId(message.getParentTxId())
+          .createTime(new Date())
           .localTxId(message.getLocalTxId()).build();
     } else {
       ok = false;
     }
     if (event != null) {
-      event.setCreateTime(new Date());
       actorEventChannel.send(event);
     }
     responseObserver.onNext(ok ? ALLOW : REJECT);
diff --git a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/controller/TransactionController.java b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/controller/TransactionController.java
index 5772103..9d21367 100644
--- a/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/controller/TransactionController.java
+++ b/alpha/alpha-ui/src/main/java/org/apache/servicecomb/pack/alpha/ui/controller/TransactionController.java
@@ -150,6 +150,7 @@ public class TransactionController {
           .type(event.get("type").toString())
           .serviceName(event.get("serviceName").toString())
           .instanceId(event.get("instanceId").toString())
+          .timeout(event.get("timeout") != null ? Integer.valueOf(event.get("timeout").toString()) : 0)
           .globalTxId(event.get("globalTxId").toString())
           .parentTxId(event.get("parentTxId") != null ? event.get("parentTxId").toString() : null)
           .localTxId(event.get("localTxId") != null ? event.get("localTxId").toString() : null)
@@ -193,6 +194,9 @@ public class TransactionController {
     });
     map.put("events", events);
     map.put("globalTxId", globalTransaction.getGlobalTxId());
+    map.put("state", globalTransaction.getState());
+    map.put("endTime", globalTransaction.getEndTime());
+    map.put("suspendedType", globalTransaction.getSuspendedType());
     map.put("subTransactions", subTransactions);
     return "transaction_details";
   }
diff --git a/alpha/alpha-ui/src/main/resources/templates/transaction_details.html b/alpha/alpha-ui/src/main/resources/templates/transaction_details.html
index 697febc..e279fc2 100644
--- a/alpha/alpha-ui/src/main/resources/templates/transaction_details.html
+++ b/alpha/alpha-ui/src/main/resources/templates/transaction_details.html
@@ -41,7 +41,7 @@
               </div>
               <div class="col-xl-6 col-lg-6">
                 <div><i class="fas fa-calendar"></i> <span class="small" th:text="${event.createTime}"></span></div>
-                <div><i class="fas fa-clock"></i> <span class="small" th:text="${event.timeout}+' ms'"></span></div>
+                <div th:if="${event.type}==SagaStartedEvent"><i class="fas fa-clock"></i> <span class="small" th:text="${event.timeout}+' ms'"></span></div>
                 <div th:if="${event.type}==TxStartedEvent"><i class="fas fa-undo"></i> <span class="small" th:text="${event.retries}"></span></div>
                 <div th:if="${event.type}==TxStartedEvent  or ${event.type}==TxAbortedEvent or ${event.type}=='SagaAbortedEvent'" class="position-absolute" style="bottom: 0px; right: 15px;">
                   <i name="event_more" class="fas fa-caret-square-down" style="cursor:pointer" th:target="'div-more-'+${stat.index}"></i>
@@ -70,6 +70,14 @@
             </div>
             <hr th:if="${!stat.last}"/>
           </div>
+          <div class="events">
+            <hr/>
+            <div th:if="${state}=='SUSPENDED'" class="row text-danger">
+              <div class="col-xl-12 col-lg-12">
+                <div><span class="small" th:text="'Suspended Type: ' + ${suspendedType} + ' - ' + ${endTime}"></span></div>
+              </div>
+            </div>
+          </div>
         </div>
       </div>
     </div>