diff --git a/running_exercise/lib/loop_thread.py b/running_exercise/lib/loop_thread.py
index edbcc33afb7bdadcc2678374338f15346104d160..405db4d0b07b7d424119c6bd96f60bbb241f4b14 100644
--- a/running_exercise/lib/loop_thread.py
+++ b/running_exercise/lib/loop_thread.py
@@ -32,48 +32,71 @@ class LoopThread(Thread):
         self.__finished.set()
 
     def run(self):
-        SubscriptionHandler.broadcast_exercise_loop(self.updater.exercise, True)
-        self.updater.update(self.elapsed_s)
-        SubscriptionHandler.broadcast_exercises(
-            self.updater.exercise, ExerciseEventTypeEnum.modify()
-        )
-        wait_time: float = self.__interval_s
-        while (
-            self.elapsed_s <= self.__total_time_s
-            and not self.__finished.wait(wait_time)
-        ):
-            update_time = self.updater.update(self.elapsed_s)
-            wait_time = (
-                self.__interval_s - update_time
-                if update_time < self.__interval_s
-                else 0
+        try:
+            SubscriptionHandler.broadcast_exercise_loop(
+                self.updater.exercise, True
             )
-            # this is necessary to prevent infinite length loops with 0 interval
-            # I wouldn't expect this during any real deployment, however it might
-            # be useful during testing for max speed update times
-            if self.__interval_s == 0:
-                self.elapsed_s += 1
-            else:
-                self.elapsed_s += self.__interval_s
-            logger.info(
-                f"update loop for exercise id: {self.updater.exercise.id} elapsed time: {self.elapsed_s}s"
+            self.updater.update(self.elapsed_s)
+            SubscriptionHandler.broadcast_exercises(
+                self.updater.exercise, ExerciseEventTypeEnum.modify()
             )
+            wait_time: float = self.__interval_s
+            while (
+                self.elapsed_s <= self.__total_time_s
+                and not self.__finished.wait(wait_time)
+            ):
+                update_time = self.updater.update(self.elapsed_s)
+                wait_time = (
+                    self.__interval_s - update_time
+                    if update_time < self.__interval_s
+                    else 0
+                )
+                # this is necessary to prevent infinite length loops with 0 interval
+                # I wouldn't expect this during any real deployment, however it might
+                # be useful during testing for max speed update times
+                if self.__interval_s == 0:
+                    self.elapsed_s += 1
+                else:
+                    self.elapsed_s += self.__interval_s
+                logger.info(
+                    f"update loop for exercise id: {self.updater.exercise.id} elapsed time: {self.elapsed_s}s"
+                )
 
-        SubscriptionHandler.broadcast_exercise_loop(
-            self.updater.exercise, False
-        )
-        self.__finished.set()
+            SubscriptionHandler.broadcast_exercise_loop(
+                self.updater.exercise, False
+            )
+            self.__finished.set()
 
-        if self.elapsed_s >= self.__total_time_s:
-            self.updater.finish()
-            logger.info(
-                f"finishing exercise loop for exercise id: {self.updater.exercise.id}"
+            if self.elapsed_s >= self.__total_time_s:
+                self.updater.finish()
+                logger.info(
+                    f"finishing exercise loop for exercise id: {self.updater.exercise.id}"
+                )
+            else:
+                self.updater.stop(self.elapsed_s)
+            SubscriptionHandler.broadcast_exercises(
+                self.updater.exercise, ExerciseEventTypeEnum.modify()
+            )
+        except Exception as ex:
+            logger.error(
+                f"loop thread exception {type(ex).__name__}: {str(ex)}"
             )
-        else:
-            self.updater.stop(self.elapsed_s)
-        SubscriptionHandler.broadcast_exercises(
-            self.updater.exercise, ExerciseEventTypeEnum.modify()
-        )
+            for i in range(10):
+                try:
+                    self.updater.stop(self.elapsed_s - self.__interval_s)
+                except:
+                    logger.error(
+                        f"failed to stop exercise: {self.updater.exercise.id}"
+                    )
+                else:
+                    logger.info(
+                        f"stopped exercise: {self.updater.exercise.id} on the {i}th try"
+                    )
+                    break
+            else:
+                logger.error(
+                    f"failed to stop exercise: {self.updater.exercise.id} 10 times, still running"
+                )
 
     def remaining_time_s(self) -> int:
         return self.__total_time_s - self.elapsed_s
diff --git a/ttxbackend/settings.py b/ttxbackend/settings.py
index fab2fc47d29e98215cc257e754548cf3723f1c90..e672a44ba9c625fe6a5f5a9e696f46cf60b84823 100644
--- a/ttxbackend/settings.py
+++ b/ttxbackend/settings.py
@@ -100,6 +100,9 @@ DATABASES = {
     "default": {
         "ENGINE": "django.db.backends.sqlite3",
         "NAME": os.path.join(BASE_DIR, DATA_STORAGE, "db.sqlite3"),
+        "OPTIONS": {
+            "timeout": 20,
+        },
     }
 }