diff --git a/pom.xml b/pom.xml
index f143fd31..819389e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,7 +18,7 @@
   jar
 
   
-    1.2-rc1
+    1.2.1-SNAPSHOT
     ${sebserver-version}
     ${sebserver-version}
     UTF-8
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/ClientEventLastPingMapper.java b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/ClientEventLastPingMapper.java
index cf233e83..6fdaadb8 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/ClientEventLastPingMapper.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/batis/ClientEventLastPingMapper.java
@@ -8,6 +8,9 @@
 
 package ch.ethz.seb.sebserver.webservice.datalayer.batis;
 
+import static ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport.*;
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+
 import java.util.Collection;
 
 import org.apache.ibatis.annotations.Arg;
@@ -15,39 +18,85 @@ import org.apache.ibatis.annotations.ConstructorArgs;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.ResultType;
 import org.apache.ibatis.annotations.SelectProvider;
+import org.apache.ibatis.annotations.UpdateProvider;
 import org.apache.ibatis.type.JdbcType;
 import org.mybatis.dynamic.sql.select.MyBatis3SelectModelAdapter;
 import org.mybatis.dynamic.sql.select.QueryExpressionDSL;
 import org.mybatis.dynamic.sql.select.SelectDSL;
 import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
+import org.mybatis.dynamic.sql.update.UpdateDSL;
+import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
 import org.mybatis.dynamic.sql.util.SqlProviderAdapter;
 
+import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
 import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
 
 @Mapper
 public interface ClientEventLastPingMapper {
 
     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
-    Long num(SelectStatementProvider selectStatement);
+    @ConstructorArgs({ @Arg(column = "server_time", javaType = Long.class, jdbcType = JdbcType.BIGINT) })
+    Collection selectPingTimes(SelectStatementProvider selectStatement);
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    @ConstructorArgs({ @Arg(column = "server_time", javaType = Long.class, jdbcType = JdbcType.BIGINT) })
+    Long selectPingTime(SelectStatementProvider selectStatement);
+
+    @SelectProvider(type = SqlProviderAdapter.class, method = "select")
+    @ConstructorArgs({ @Arg(column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT, id = true) })
+    Long selectPK(SelectStatementProvider selectStatement);
+
+    @UpdateProvider(type = SqlProviderAdapter.class, method = "update")
+    int update(UpdateStatementProvider updateStatement);
 
     @SelectProvider(type = SqlProviderAdapter.class, method = "select")
     @ResultType(ClientEventLastPingRecord.class)
     @ConstructorArgs({
             @Arg(column = "id", javaType = Long.class, jdbcType = JdbcType.BIGINT),
-            @Arg(column = "server_time", javaType = Long.class, jdbcType = JdbcType.BIGINT),
+            @Arg(column = "server_time", javaType = Long.class, jdbcType = JdbcType.BIGINT)
     })
     Collection selectMany(SelectStatementProvider select);
 
+    default Long selectPingTimeByPrimaryKey(final Long id_) {
+        return SelectDSL.selectWithMapper(
+                this::selectPingTime,
+                ClientEventRecordDynamicSqlSupport.serverTime.as("server_time"))
+                .from(ClientEventRecordDynamicSqlSupport.clientEventRecord)
+                .where(ClientEventRecordDynamicSqlSupport.id, isEqualTo(id_))
+                .build()
+                .execute();
+    }
+
+    default Long pingRecordIdByConnectionId(final Long connectionId) {
+        return SelectDSL.selectDistinctWithMapper(
+                this::selectPK,
+                ClientEventRecordDynamicSqlSupport.id.as("id"))
+                .from(ClientEventRecordDynamicSqlSupport.clientEventRecord)
+                .where(ClientEventRecordDynamicSqlSupport.clientConnectionId, isEqualTo(connectionId))
+                .and(ClientEventRecordDynamicSqlSupport.type, isEqualTo(EventType.LAST_PING.id))
+                .build()
+                .execute();
+    }
+
     default QueryExpressionDSL>> selectByExample() {
+
         return SelectDSL.selectWithMapper(
                 this::selectMany,
 
-                ClientEventRecordDynamicSqlSupport.clientConnectionId.as("id"),
+                ClientEventRecordDynamicSqlSupport.id.as("id"),
                 ClientEventRecordDynamicSqlSupport.serverTime.as("server_time"))
 
                 .from(ClientEventRecordDynamicSqlSupport.clientEventRecord);
     }
 
+    default int updatePingTime(final Long _id, final Long pingTime) {
+        return UpdateDSL.updateWithMapper(this::update, clientEventRecord)
+                .set(serverTime).equalTo(pingTime)
+                .where(id, isEqualTo(_id))
+                .build()
+                .execute();
+    }
+
     final class ClientEventLastPingRecord {
 
         public final Long id;
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java
index 1d07897b..7c4b583a 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientEventDAOImpl.java
@@ -18,6 +18,7 @@ import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import org.joda.time.DateTimeUtils;
 import org.mybatis.dynamic.sql.SqlBuilder;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
@@ -312,21 +313,6 @@ public class ClientEventDAOImpl implements ClientEventDAO {
                     .stream()
                     .map(pk -> new EntityKey(String.valueOf(pk), EntityType.CLIENT_EVENT))
                     .collect(Collectors.toList());
-
-//            return all
-//                    .stream()
-//                    .map(EntityKey::getModelId)
-//                    .map(Long::parseLong)
-//                    .map(pk -> {
-//                        final int deleted = this.clientEventRecordMapper.deleteByPrimaryKey(pk);
-//                        if (deleted == 1) {
-//                            return new EntityKey(String.valueOf(pk), EntityType.CLIENT_EVENT);
-//                        } else {
-//                            return null;
-//                        }
-//                    })
-//                    .filter(Objects::nonNull)
-//                    .collect(Collectors.toList());
         });
     }
 
@@ -345,7 +331,7 @@ public class ClientEventDAOImpl implements ClientEventDAO {
                 return lastPingRec.get(0);
             }
 
-            final long millisecondsNow = Utils.getMillisecondsNow();
+            final long millisecondsNow = DateTimeUtils.currentTimeMillis();
             final ClientEventRecord clientEventRecord = new ClientEventRecord();
             clientEventRecord.setClientConnectionId(connectionId);
             clientEventRecord.setType(EventType.LAST_PING.id);
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java
index c996e4a0..a056b7d9 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java
@@ -45,6 +45,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
 import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
 import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService;
 import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService;
+import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedPingCache;
 import ch.ethz.seb.sebserver.webservice.weblayer.api.APIConstraintViolationException;
 
 @Lazy
@@ -71,6 +72,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
     private final SEBClientNotificationService sebClientNotificationService;
     private final WebserviceInfo webserviceInfo;
     private final ExamAdminService examAdminService;
+    private final DistributedPingCache distributedPingCache;
 
     protected SEBClientConnectionServiceImpl(
             final ExamSessionService examSessionService,
@@ -79,7 +81,8 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
             final SEBClientConfigDAO sebClientConfigDAO,
             final SEBClientInstructionService sebInstructionService,
             final SEBClientNotificationService sebClientNotificationService,
-            final ExamAdminService examAdminService) {
+            final ExamAdminService examAdminService,
+            final DistributedPingCache distributedPingCache) {
 
         this.examSessionService = examSessionService;
         this.examSessionCacheService = examSessionService.getExamSessionCacheService();
@@ -91,6 +94,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
         this.sebClientNotificationService = sebClientNotificationService;
         this.webserviceInfo = sebInstructionService.getWebserviceInfo();
         this.examAdminService = examAdminService;
+        this.distributedPingCache = distributedPingCache;
     }
 
     @Override
@@ -453,6 +457,12 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
                 updatedClientConnection = clientConnection;
             }
 
+            // delete stored ping if this is a distributed setup
+            if (this.webserviceInfo.isDistributed()) {
+                this.distributedPingCache
+                        .deletePingForConnection(updatedClientConnection.id);
+            }
+
             reloadConnectionCache(connectionToken);
             return updatedClientConnection;
         });
@@ -501,6 +511,12 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
                 updatedClientConnection = clientConnection;
             }
 
+            // delete stored ping if this is a distributed setup
+            if (this.webserviceInfo.isDistributed()) {
+                this.distributedPingCache
+                        .deletePingForConnection(updatedClientConnection.id);
+            }
+
             reloadConnectionCache(connectionToken);
             return updatedClientConnection;
         });
@@ -510,6 +526,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
     public void updatePingEvents() {
         try {
 
+            final boolean distributed = this.webserviceInfo.isDistributed();
             final Cache cache = this.cacheManager.getCache(ExamSessionCacheService.CACHE_NAME_ACTIVE_CLIENT_CONNECTION);
             final long now = Utils.getMillisecondsNow();
             final Consumer missingPingUpdate = missingPingUpdate(now);
@@ -518,7 +535,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
                     .allRunningExamIds()
                     .getOrThrow()
                     .stream()
-                    .flatMap(examId -> (this.webserviceInfo.isDistributed())
+                    .flatMap(examId -> distributed
                             ? this.clientConnectionDAO
                                     .getConnectionTokensNoCache(examId)
                                     .getOrThrow()
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/AbstractPingIndicator.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/AbstractPingIndicator.java
index 18a5bff0..754232ff 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/AbstractPingIndicator.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/AbstractPingIndicator.java
@@ -20,7 +20,6 @@ import ch.ethz.seb.sebserver.gbl.Constants;
 import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
 import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
 import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
-import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
 
 public abstract class AbstractPingIndicator extends AbstractClientIndicator {
 
@@ -28,14 +27,15 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
 
     private final Set EMPTY_SET = Collections.unmodifiableSet(EnumSet.noneOf(EventType.class));
 
-    protected final ClientEventDAO clientEventDAO;
+    protected final DistributedPingCache distributedPingCache;
 
-    private long lastUpdate = 0;
-    protected ClientEventRecord pingRecord = null;
+    private final long lastUpdate = 0;
+    protected Long pingRecord = null;
+
+    protected AbstractPingIndicator(final DistributedPingCache distributedPingCache) {
 
-    protected AbstractPingIndicator(final ClientEventDAO clientEventDAO) {
         super();
-        this.clientEventDAO = clientEventDAO;
+        this.distributedPingCache = distributedPingCache;
     }
 
     @Override
@@ -47,10 +47,12 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
 
         super.init(indicatorDefinition, connectionId, active, cachingEnabled);
 
-        if (!this.cachingEnabled) {
-            this.pingRecord = this.clientEventDAO
-                    .initPingEvent(this.connectionId)
-                    .getOr(null);
+        if (!this.cachingEnabled && this.active) {
+            this.pingRecord = this.distributedPingCache.initPingForConnection(this.connectionId);
+            if (this.pingRecord == null) {
+                // try once again
+                this.pingRecord = this.distributedPingCache.initPingForConnection(this.connectionId);
+            }
         }
     }
 
@@ -64,10 +66,7 @@ public abstract class AbstractPingIndicator extends AbstractClientIndicator {
             // Update last ping time on persistent storage
             final long millisecondsNow = DateTimeUtils.currentTimeMillis();
             if (millisecondsNow - this.lastUpdate > INTERVAL_FOR_PERSISTENT_UPDATE) {
-                this.pingRecord.setClientTime(timestamp);
-                this.pingRecord.setServerTime(millisecondsNow);
-                this.clientEventDAO.updatePingEvent(this.pingRecord);
-                this.lastUpdate = millisecondsNow;
+                this.distributedPingCache.updatePing(this.pingRecord, millisecondsNow);
             }
         }
     }
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/DistributedPingCache.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/DistributedPingCache.java
new file mode 100644
index 00000000..c60d99bc
--- /dev/null
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/DistributedPingCache.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator;
+
+import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
+import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.stream.Collectors;
+
+import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
+import org.joda.time.DateTimeUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
+import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
+import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
+import ch.ethz.seb.sebserver.webservice.datalayer.batis.ClientEventLastPingMapper;
+import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordDynamicSqlSupport;
+import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ClientEventRecordMapper;
+import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
+
+@Lazy
+@Component
+@WebServiceProfile
+public class DistributedPingCache implements DisposableBean {
+
+    private static final Logger log = LoggerFactory.getLogger(DistributedPingCache.class);
+
+    private final ClientEventLastPingMapper clientEventLastPingMapper;
+    private final ClientEventRecordMapper clientEventRecordMapper;
+    private ScheduledFuture> taskRef;
+
+    private final Map pingCache = new ConcurrentHashMap<>();
+
+    public DistributedPingCache(
+            final ClientEventLastPingMapper clientEventLastPingMapper,
+            final ClientEventRecordMapper clientEventRecordMapper,
+            final WebserviceInfo webserviceInfo,
+            final TaskScheduler taskScheduler) {
+
+        this.clientEventLastPingMapper = clientEventLastPingMapper;
+        this.clientEventRecordMapper = clientEventRecordMapper;
+        if (webserviceInfo.isDistributed()) {
+            try {
+                this.taskRef = taskScheduler.scheduleAtFixedRate(this::updateCache, 1000);
+            } catch (final Exception e) {
+                log.error("Failed to initialize distributed ping cache update task");
+                this.taskRef = null;
+            }
+        } else {
+            this.taskRef = null;
+        }
+    }
+
+    @Transactional
+    public Long initPingForConnection(final Long connectionId) {
+        try {
+            Long recordId = this.clientEventLastPingMapper
+                    .pingRecordIdByConnectionId(connectionId);
+
+            if (recordId == null) {
+                final long millisecondsNow = DateTimeUtils.currentTimeMillis();
+                final ClientEventRecord clientEventRecord = new ClientEventRecord();
+                clientEventRecord.setClientConnectionId(connectionId);
+                clientEventRecord.setType(EventType.LAST_PING.id);
+                clientEventRecord.setClientTime(millisecondsNow);
+                clientEventRecord.setServerTime(millisecondsNow);
+                this.clientEventRecordMapper.insert(clientEventRecord);
+
+                recordId = this.clientEventLastPingMapper.pingRecordIdByConnectionId(connectionId);
+            }
+
+            return recordId;
+        } catch (final Exception e) {
+            log.error("Failed to initialize ping for connection -> {}", connectionId, e);
+            return null;
+        }
+    }
+
+    @Transactional
+    public void updatePing(final Long pingRecordId, final Long pingTime) {
+        try {
+
+            this.clientEventLastPingMapper
+                    .updatePingTime(pingRecordId, pingTime);
+
+        } catch (final Exception e) {
+            log.error("Failed to update ping for ping record id -> {}", pingRecordId);
+        }
+    }
+
+    @Transactional
+    public void deletePingForConnection(final Long connectionId) {
+        try {
+
+            this.clientEventRecordMapper
+                    .deleteByExample()
+                    .where(ClientEventRecordDynamicSqlSupport.clientConnectionId, isEqualTo(connectionId))
+                    .and(ClientEventRecordDynamicSqlSupport.type, isEqualTo(EventType.LAST_PING.id))
+                    .build()
+                    .execute();
+
+        } catch (final Exception e) {
+            log.error("Failed to delete ping for connection -> {}", connectionId, e);
+        }
+    }
+
+    public Long getLastPing(final Long pingRecordId) {
+        try {
+            Long ping = this.pingCache.get(pingRecordId);
+            if (ping == null) {
+                log.debug("******* Get and cache ping time: {}", pingRecordId);
+                ping = this.clientEventLastPingMapper.selectPingTimeByPrimaryKey(pingRecordId);
+                if (ping != null) {
+                    this.pingCache.put(pingRecordId, ping);
+                }
+            }
+
+            return ping;
+        } catch (final Exception e) {
+            log.error("Error while trying to get last ping from storage: {}", e.getMessage());
+            return 0L;
+        }
+    }
+
+    @Transactional
+    public void updateCache() {
+
+        if (this.pingCache.isEmpty()) {
+            return;
+        }
+
+        log.debug("****** Update distributed ping cache: {}", this.pingCache);
+
+        try {
+            final ArrayList pks = new ArrayList<>(this.pingCache.keySet());
+            final Map mapping = this.clientEventLastPingMapper
+                    .selectByExample()
+                    .where(
+                            ClientEventRecordDynamicSqlSupport.id,
+                            isIn(pks))
+                    .build()
+                    .execute()
+                    .stream()
+                    .collect(Collectors.toMap(entry -> entry.id, entry -> entry.lastPingTime));
+
+            if (mapping != null) {
+                this.pingCache.clear();
+                this.pingCache.putAll(mapping);
+            }
+
+        } catch (final Exception e) {
+            log.error("Error while trying to update distributed ping cache: {}", this.pingCache, e);
+        }
+    }
+
+    @Override
+    public void destroy() throws Exception {
+        if (this.taskRef != null) {
+            try {
+                final boolean cancel = this.taskRef.cancel(true);
+                if (!cancel) {
+                    log.warn("Failed to cancel distributed ping cache update task");
+                }
+            } catch (final Exception e) {
+                log.error("Failed to cancel distributed ping cache update task: ", e);
+            }
+        }
+
+    }
+
+}
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicator.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicator.java
index c4954a74..85bb95a6 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicator.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicator.java
@@ -26,9 +26,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
 import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
 import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
 import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent.EventType;
-import ch.ethz.seb.sebserver.gbl.util.Result;
 import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ClientEventRecord;
-import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientEventDAO;
 
 @Lazy
 @Component(IndicatorType.Names.LAST_PING)
@@ -46,8 +44,8 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
     private boolean missingPing = false;
     private boolean hidden = false;
 
-    public PingIntervalClientIndicator(final ClientEventDAO clientEventDAO) {
-        super(clientEventDAO);
+    public PingIntervalClientIndicator(final DistributedPingCache distributedPingCache) {
+        super(distributedPingCache);
         this.cachingEnabled = true;
     }
 
@@ -129,17 +127,10 @@ public final class PingIntervalClientIndicator extends AbstractPingIndicator {
 
             // if this indicator is not missing ping
             if (!this.isMissingPing()) {
-
-                final Result lastPing = this.clientEventDAO
-                        .getLastPing(super.pingRecord.getId());
-
-                if (!lastPing.hasError()) {
-                    if (Double.isNaN(this.currentValue)) {
-                        return lastPing.get().doubleValue();
-                    }
-                    return Math.max(this.currentValue, lastPing.get().doubleValue());
-                } else {
-                    log.error("Failed to get last ping from persistent: {}", lastPing.getError().getMessage());
+                final Long lastPing = this.distributedPingCache.getLastPing(super.pingRecord);
+                if (lastPing != null) {
+                    final double doubleValue = lastPing.doubleValue();
+                    return Math.max(Double.isNaN(this.currentValue) ? doubleValue : this.currentValue, doubleValue);
                 }
             }
 
diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPI_V1_Controller.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPI_V1_Controller.java
index bd54c09a..4120f6b1 100644
--- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPI_V1_Controller.java
+++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPI_V1_Controller.java
@@ -270,7 +270,7 @@ public class ExamAPI_V1_Controller {
         final String instructionConfirm = request.getParameter(API.EXAM_API_PING_INSTRUCTION_CONFIRM);
 
         if (log.isTraceEnabled()) {
-            log.trace("****************** SEB client connection: {} ip: ",
+            log.trace("****************** SEB client connection: {} ip: {}",
                     connectionToken,
                     getClientAddress(request));
         }
diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties
index 81ac2bc0..277c15de 100644
--- a/src/main/resources/config/application-dev-ws.properties
+++ b/src/main/resources/config/application-dev-ws.properties
@@ -22,7 +22,7 @@ sebserver.webservice.clean-db-on-startup=false
 
 # webservice configuration
 sebserver.init.adminaccount.gen-on-init=false
-sebserver.webservice.distributed=false
+sebserver.webservice.distributed=true
 sebserver.webservice.master.delay.threshold=10000
 sebserver.webservice.http.external.scheme=http
 sebserver.webservice.http.external.servername=localhost
diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicatorTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicatorTest.java
index 1d1b6143..6fbb52b4 100644
--- a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicatorTest.java
+++ b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/indicator/PingIntervalClientIndicatorTest.java
@@ -33,9 +33,10 @@ public class PingIntervalClientIndicatorTest {
         DateTimeUtils.setCurrentMillisProvider(() -> 1L);
 
         final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
+        final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
 
         final PingIntervalClientIndicator pingIntervalClientIndicator =
-                new PingIntervalClientIndicator(clientEventDAO);
+                new PingIntervalClientIndicator(distributedPingCache);
         assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
     }
 
@@ -45,9 +46,10 @@ public class PingIntervalClientIndicatorTest {
         DateTimeUtils.setCurrentMillisProvider(() -> 1L);
 
         final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
+        final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
 
         final PingIntervalClientIndicator pingIntervalClientIndicator =
-                new PingIntervalClientIndicator(clientEventDAO);
+                new PingIntervalClientIndicator(distributedPingCache);
         assertEquals("0.0", String.valueOf(pingIntervalClientIndicator.getValue()));
 
         DateTimeUtils.setCurrentMillisProvider(() -> 10L);
@@ -60,9 +62,10 @@ public class PingIntervalClientIndicatorTest {
         DateTimeUtils.setCurrentMillisProvider(() -> 1L);
 
         final ClientEventDAO clientEventDAO = Mockito.mock(ClientEventDAO.class);
+        final DistributedPingCache distributedPingCache = Mockito.mock(DistributedPingCache.class);
 
         final PingIntervalClientIndicator pingIntervalClientIndicator =
-                new PingIntervalClientIndicator(clientEventDAO);
+                new PingIntervalClientIndicator(distributedPingCache);
         final JSONMapper jsonMapper = new JSONMapper();
         final String json = jsonMapper.writeValueAsString(pingIntervalClientIndicator);
         assertEquals("{\"indicatorValue\":0.0,\"indicatorType\":\"LAST_PING\"}", json);