diff --git a/build.sbt b/build.sbt
index df14eb8..e66d09d 100644
--- a/build.sbt
+++ b/build.sbt
@@ -54,11 +54,9 @@
   "ch.qos.logback"                  % "logback-classic"              % "1.2.3",
   "com.zaxxer"                      % "HikariCP"                     % "3.4.5",
   "com.typesafe"                    % "config"                       % "1.4.0",
-  "com.typesafe.akka"               %% "akka-actor"                  % "2.5.27",
   "fr.brouillard.oss.security.xhub" % "xhub4j-core"                  % "1.1.0",
   "com.github.bkromhout"            % "java-diff-utils"              % "2.1.1",
   "org.cache2k"                     % "cache2k-all"                  % "1.2.4.Final",
-  "com.enragedginger"               %% "akka-quartz-scheduler"       % "1.8.1-akka-2.5.x" exclude ("com.mchange", "c3p0") exclude ("com.zaxxer", "HikariCP-java6"),
   "net.coobird"                     % "thumbnailator"                % "0.4.11",
   "com.github.zafarkhaja"           % "java-semver"                  % "0.9.0",
   "com.nimbusds"                    % "oauth2-oidc-sdk"              % "5.64.4",
diff --git a/src/main/resources/update/gitbucket-core_4.34.xml b/src/main/resources/update/gitbucket-core_4.34.xml
new file mode 100644
index 0000000..4094e6a
--- /dev/null
+++ b/src/main/resources/update/gitbucket-core_4.34.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<changeSet>
+  <dropTable tableName="ACTIVITY" />
+</changeSet>
diff --git a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
index 5255e17..dd00503 100644
--- a/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
+++ b/src/main/scala/gitbucket/core/GitBucketCoreModule.scala
@@ -1,7 +1,22 @@
 package gitbucket.core
 
-import io.github.gitbucket.solidbase.migration.{SqlMigration, LiquibaseMigration}
-import io.github.gitbucket.solidbase.model.{Version, Module}
+import java.io.FileOutputStream
+import java.nio.charset.StandardCharsets
+import java.sql.Connection
+import java.util
+import java.util.UUID
+
+import gitbucket.core.model.Activity
+import gitbucket.core.util.Directory.ActivityLog
+import gitbucket.core.util.JDBCUtil
+import io.github.gitbucket.solidbase.Solidbase
+import io.github.gitbucket.solidbase.migration.{LiquibaseMigration, Migration, SqlMigration}
+import io.github.gitbucket.solidbase.model.{Module, Version}
+import org.json4s.NoTypeHints
+import org.json4s.jackson.Serialization
+import org.json4s.jackson.Serialization.write
+
+import scala.util.Using
 
 object GitBucketCoreModule
     extends Module(
@@ -65,5 +80,38 @@
       new Version("4.31.1"),
       new Version("4.31.2"),
       new Version("4.32.0", new LiquibaseMigration("update/gitbucket-core_4.32.xml")),
-      new Version("4.33.0")
+      new Version("4.33.0"),
+      new Version(
+        "4.34.0",
+        new Migration() {
+          override def migrate(moduleId: String, version: String, context: util.Map[String, AnyRef]): Unit = {
+            implicit val formats = Serialization.formats(NoTypeHints)
+            import JDBCUtil._
+
+            val conn = context.get(Solidbase.CONNECTION).asInstanceOf[Connection]
+            val list = conn.select("SELECT * FROM ACTIVITY ORDER BY ACTIVITY_ID") {
+              rs =>
+                Activity(
+                  activityId = UUID.randomUUID().toString,
+                  userName = rs.getString("USER_NAME"),
+                  repositoryName = rs.getString("REPOSITORY_NAME"),
+                  activityUserName = rs.getString("ACTIVITY_USER_NAME"),
+                  activityType = rs.getString("ACTIVITY_TYPE"),
+                  message = rs.getString("MESSAGE"),
+                  additionalInfo = {
+                    val additionalInfo = rs.getString("ADDITIONAL_INFO")
+                    if (rs.wasNull()) None else Some(additionalInfo)
+                  },
+                  activityDate = rs.getTimestamp("ACTIVITY_DATE")
+                )
+            }
+            Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
+              list.foreach { activity =>
+                out.write((write(activity) + "\n").getBytes(StandardCharsets.UTF_8))
+              }
+            }
+          }
+        },
+        new LiquibaseMigration("update/gitbucket-core_4.34.xml")
+      )
     )
diff --git a/src/main/scala/gitbucket/core/controller/AccountController.scala b/src/main/scala/gitbucket/core/controller/AccountController.scala
index f187e29..f4978d4 100644
--- a/src/main/scala/gitbucket/core/controller/AccountController.scala
+++ b/src/main/scala/gitbucket/core/controller/AccountController.scala
@@ -35,6 +35,7 @@
     with WebHookService
     with PrioritiesService
     with RepositoryCreationService
+    with RequestCache
 
 trait AccountControllerBase extends AccountManagementControllerBase {
   self: AccountService
diff --git a/src/main/scala/gitbucket/core/controller/ApiController.scala b/src/main/scala/gitbucket/core/controller/ApiController.scala
index f84111a..07898e1 100644
--- a/src/main/scala/gitbucket/core/controller/ApiController.scala
+++ b/src/main/scala/gitbucket/core/controller/ApiController.scala
@@ -52,6 +52,7 @@
     with ReferrerAuthenticator
     with ReadableUsersAuthenticator
     with WritableUsersAuthenticator
+    with RequestCache
 
 trait ApiControllerBase extends ControllerBase {
 
diff --git a/src/main/scala/gitbucket/core/controller/DashboardController.scala b/src/main/scala/gitbucket/core/controller/DashboardController.scala
index 5355bc1..bae642d 100644
--- a/src/main/scala/gitbucket/core/controller/DashboardController.scala
+++ b/src/main/scala/gitbucket/core/controller/DashboardController.scala
@@ -22,6 +22,7 @@
     with WebHookPullRequestReviewCommentService
     with MilestonesService
     with UsersAuthenticator
+    with RequestCache
 
 trait DashboardControllerBase extends ControllerBase {
   self: IssuesService with PullRequestService with RepositoryService with AccountService with UsersAuthenticator =>
diff --git a/src/main/scala/gitbucket/core/controller/IndexController.scala b/src/main/scala/gitbucket/core/controller/IndexController.scala
index 15feaa8..cddd77a 100644
--- a/src/main/scala/gitbucket/core/controller/IndexController.scala
+++ b/src/main/scala/gitbucket/core/controller/IndexController.scala
@@ -29,6 +29,7 @@
     with AccessTokenService
     with AccountFederationService
     with OpenIDConnectService
+    with RequestCache
 
 trait IndexControllerBase extends ControllerBase {
   self: RepositoryService
@@ -78,7 +79,7 @@
       }
       .getOrElse {
         gitbucket.core.html.index(
-          getRecentActivities(),
+          getRecentPublicActivities(),
           getVisibleRepositories(None, withoutPhysicalInfo = true),
           showBannerToCreatePersonalAccessToken = false
         )
@@ -161,7 +162,7 @@
 
   get("/activities.atom") {
     contentType = "application/atom+xml; type=feed"
-    xml.feed(getRecentActivities())
+    xml.feed(getRecentPublicActivities())
   }
 
   post("/sidebar-collapse") {
diff --git a/src/main/scala/gitbucket/core/controller/IssuesController.scala b/src/main/scala/gitbucket/core/controller/IssuesController.scala
index f19e7a9..20470e4 100644
--- a/src/main/scala/gitbucket/core/controller/IssuesController.scala
+++ b/src/main/scala/gitbucket/core/controller/IssuesController.scala
@@ -30,6 +30,7 @@
     with WebHookPullRequestReviewCommentService
     with CommitsService
     with PrioritiesService
+    with RequestCache
 
 trait IssuesControllerBase extends ControllerBase {
   self: IssuesService
diff --git a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
index 15d18ef..43b7f12 100644
--- a/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
+++ b/src/main/scala/gitbucket/core/controller/PullRequestsController.scala
@@ -36,6 +36,7 @@
     with MergeService
     with ProtectedBranchService
     with PrioritiesService
+    with RequestCache
 
 trait PullRequestsControllerBase extends ControllerBase {
   self: RepositoryService
diff --git a/src/main/scala/gitbucket/core/controller/ReleasesController.scala b/src/main/scala/gitbucket/core/controller/ReleasesController.scala
index b0ab907..d2cee57 100644
--- a/src/main/scala/gitbucket/core/controller/ReleasesController.scala
+++ b/src/main/scala/gitbucket/core/controller/ReleasesController.scala
@@ -2,7 +2,14 @@
 
 import java.io.File
 
-import gitbucket.core.service.{AccountService, ActivityService, PaginationHelper, ReleaseService, RepositoryService}
+import gitbucket.core.service.{
+  AccountService,
+  ActivityService,
+  PaginationHelper,
+  ReleaseService,
+  RepositoryService,
+  RequestCache
+}
 import gitbucket.core.util._
 import gitbucket.core.util.Directory._
 import gitbucket.core.util.Implicits._
@@ -22,6 +29,7 @@
     with ReadableUsersAuthenticator
     with ReferrerAuthenticator
     with WritableUsersAuthenticator
+    with RequestCache
 
 trait ReleaseControllerBase extends ControllerBase {
   self: RepositoryService
diff --git a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
index 0e34d94..e35741e 100644
--- a/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
+++ b/src/main/scala/gitbucket/core/controller/RepositorySettingsController.scala
@@ -30,8 +30,10 @@
     with ProtectedBranchService
     with CommitStatusService
     with DeployKeyService
+    with ActivityService
     with OwnerAuthenticator
     with UsersAuthenticator
+    with RequestCache
 
 trait RepositorySettingsControllerBase extends ControllerBase {
   self: RepositoryService
@@ -40,6 +42,7 @@
     with ProtectedBranchService
     with CommitStatusService
     with DeployKeyService
+    with ActivityService
     with OwnerAuthenticator
     with UsersAuthenticator =>
 
@@ -97,9 +100,7 @@
       "events" -> webhookEvents,
       "ctype" -> label("ctype", text()),
       "token" -> optional(trim(label("token", text(maxlength(100)))))
-    )(
-      (url, events, ctype, token) => WebHookForm(url, events, WebHookContentType.valueOf(ctype), token)
-    )
+    )((url, events, ctype, token) => WebHookForm(url, events, WebHookContentType.valueOf(ctype), token))
 
   // for rename repository
   case class RenameRepositoryForm(repositoryName: String)
@@ -251,9 +252,10 @@
    * Send the test request to registered web hook URLs.
    */
   ajaxPost("/:owner/:repository/settings/hooks/test")(ownerOnly { repository =>
-    def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] = h.map { h =>
-      Array(h.getName, h.getValue)
-    }
+    def _headers(h: Array[org.apache.http.Header]): Array[Array[String]] =
+      h.map { h =>
+        Array(h.getName, h.getValue)
+      }
 
     Using.resource(Git.open(getRepositoryDir(repository.owner, repository.name))) {
       git =>
@@ -371,7 +373,15 @@
   post("/:owner/:repository/settings/rename", renameForm)(ownerOnly { (form, repository) =>
     if (context.settings.repositoryOperation.rename || context.loginAccount.get.isAdmin) {
       if (repository.name != form.repositoryName) {
+        // Update database and move git repository
         renameRepository(repository.owner, repository.name, repository.owner, form.repositoryName)
+        // Record activity log
+        recordRenameRepositoryActivity(
+          repository.owner,
+          form.repositoryName,
+          repository.name,
+          context.loginAccount.get.userName
+        )
       }
       redirect(s"/${repository.owner}/${form.repositoryName}")
     } else Forbidden()
@@ -384,7 +394,15 @@
     if (context.settings.repositoryOperation.transfer || context.loginAccount.get.isAdmin) {
       // Change repository owner
       if (repository.owner != form.newOwner) {
+        // Update database and move git repository
         renameRepository(repository.owner, repository.name, form.newOwner, repository.name)
+        // Record activity log
+        recordRenameRepositoryActivity(
+          form.newOwner,
+          repository.name,
+          repository.owner,
+          context.loginAccount.get.userName
+        )
       }
       redirect(s"/${form.newOwner}/${repository.name}")
     } else Forbidden()
@@ -435,32 +453,34 @@
   /**
    * Provides duplication check for web hook url.
    */
-  private def webHook(needExists: Boolean): Constraint = new Constraint() {
-    override def validate(name: String, value: String, messages: Messages): Option[String] =
-      if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
-        Some(if (needExists) {
-          "URL had not been registered yet."
+  private def webHook(needExists: Boolean): Constraint =
+    new Constraint() {
+      override def validate(name: String, value: String, messages: Messages): Option[String] =
+        if (getWebHook(params("owner"), params("repository"), value).isDefined != needExists) {
+          Some(if (needExists) {
+            "URL had not been registered yet."
+          } else {
+            "URL had been registered already."
+          })
         } else {
-          "URL had been registered already."
-        })
-      } else {
-        None
-      }
-  }
-
-  private def webhookEvents = new ValueType[Set[WebHook.Event]] {
-    def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
-      WebHook.Event.values.flatMap { t =>
-        params.get(name + "." + t.name).map(_ => t)
-      }.toSet
+          None
+        }
     }
-    def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] =
-      if (convert(name, params, messages).isEmpty) {
-        Seq(name -> messages("error.required").format(name))
-      } else {
-        Nil
+
+  private def webhookEvents =
+    new ValueType[Set[WebHook.Event]] {
+      def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Set[WebHook.Event] = {
+        WebHook.Event.values.flatMap { t =>
+          params.get(name + "." + t.name).map(_ => t)
+        }.toSet
       }
-  }
+      def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] =
+        if (convert(name, params, messages).isEmpty) {
+          Seq(name -> messages("error.required").format(name))
+        } else {
+          Nil
+        }
+    }
 
 //  /**
 //   * Provides Constraint to validate the collaborator name.
@@ -480,70 +500,77 @@
   /**
    * Duplicate check for the rename repository name.
    */
-  private def renameRepositoryName: Constraint = new Constraint() {
-    override def validate(
-      name: String,
-      value: String,
-      params: Map[String, Seq[String]],
-      messages: Messages
-    ): Option[String] = {
-      for {
-        repoName <- params.optionValue("repository") if repoName != value
-        userName <- params.optionValue("owner")
-        _ <- getRepositoryNamesOfUser(userName).find(_ == value)
-      } yield {
-        "Repository already exists."
+  private def renameRepositoryName: Constraint =
+    new Constraint() {
+      override def validate(
+        name: String,
+        value: String,
+        params: Map[String, Seq[String]],
+        messages: Messages
+      ): Option[String] = {
+        for {
+          repoName <- params.optionValue("repository") if repoName != value
+          userName <- params.optionValue("owner")
+          _ <- getRepositoryNamesOfUser(userName).find(_ == value)
+        } yield {
+          "Repository already exists."
+        }
       }
     }
-  }
 
   /**
-   *
    */
-  private def featureOption: Constraint = new Constraint() {
-    override def validate(
-      name: String,
-      value: String,
-      params: Map[String, Seq[String]],
-      messages: Messages
-    ): Option[String] =
-      if (Seq("DISABLE", "PRIVATE", "PUBLIC", "ALL").contains(value)) None else Some("Option is invalid.")
-  }
+  private def featureOption: Constraint =
+    new Constraint() {
+      override def validate(
+        name: String,
+        value: String,
+        params: Map[String, Seq[String]],
+        messages: Messages
+      ): Option[String] =
+        if (Seq("DISABLE", "PRIVATE", "PUBLIC", "ALL").contains(value)) None else Some("Option is invalid.")
+    }
 
   /**
    * Provides Constraint to validate the repository transfer user.
    */
-  private def transferUser: Constraint = new Constraint() {
-    override def validate(name: String, value: String, messages: Messages): Option[String] =
-      getAccountByUserName(value) match {
-        case None => Some("User does not exist.")
-        case Some(x) =>
-          if (x.userName == params("owner")) {
-            Some("This is current repository owner.")
-          } else {
-            params.get("repository").flatMap { repositoryName =>
-              getRepositoryNamesOfUser(x.userName).find(_ == repositoryName).map { _ =>
-                "User already has same repository."
+  private def transferUser: Constraint =
+    new Constraint() {
+      override def validate(name: String, value: String, messages: Messages): Option[String] =
+        getAccountByUserName(value) match {
+          case None => Some("User does not exist.")
+          case Some(x) =>
+            if (x.userName == params("owner")) {
+              Some("This is current repository owner.")
+            } else {
+              params.get("repository").flatMap { repositoryName =>
+                getRepositoryNamesOfUser(x.userName).find(_ == repositoryName).map { _ =>
+                  "User already has same repository."
+                }
               }
             }
-          }
-      }
-  }
+        }
+    }
 
-  private def mergeOptions = new ValueType[Seq[String]] {
-    override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
-      params.getOrElse("mergeOptions", Nil)
-    }
-    override def validate(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[(String, String)] = {
-      val mergeOptions = params.getOrElse("mergeOptions", Nil)
-      if (mergeOptions.isEmpty) {
-        Seq("mergeOptions" -> "At least one option must be enabled.")
-      } else if (!mergeOptions.forall(x => Seq("merge-commit", "squash", "rebase").contains(x))) {
-        Seq("mergeOptions" -> "mergeOptions are invalid.")
-      } else {
-        Nil
+  private def mergeOptions =
+    new ValueType[Seq[String]] {
+      override def convert(name: String, params: Map[String, Seq[String]], messages: Messages): Seq[String] = {
+        params.getOrElse("mergeOptions", Nil)
+      }
+      override def validate(
+        name: String,
+        params: Map[String, Seq[String]],
+        messages: Messages
+      ): Seq[(String, String)] = {
+        val mergeOptions = params.getOrElse("mergeOptions", Nil)
+        if (mergeOptions.isEmpty) {
+          Seq("mergeOptions" -> "At least one option must be enabled.")
+        } else if (!mergeOptions.forall(x => Seq("merge-commit", "squash", "rebase").contains(x))) {
+          Seq("mergeOptions" -> "mergeOptions are invalid.")
+        } else {
+          Nil
+        }
       }
     }
-  }
 
 }
diff --git a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala
index a6c8793..da2b5ba 100644
--- a/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala
+++ b/src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala
@@ -60,6 +60,7 @@
     with WebHookPullRequestService
     with WebHookPullRequestReviewCommentService
     with ProtectedBranchService
+    with RequestCache
 
 /**
  * The repository viewer.
diff --git a/src/main/scala/gitbucket/core/controller/WikiController.scala b/src/main/scala/gitbucket/core/controller/WikiController.scala
index d7de385..428e80f 100644
--- a/src/main/scala/gitbucket/core/controller/WikiController.scala
+++ b/src/main/scala/gitbucket/core/controller/WikiController.scala
@@ -24,6 +24,7 @@
     with WebHookService
     with ReadableUsersAuthenticator
     with ReferrerAuthenticator
+    with RequestCache
 
 trait WikiControllerBase extends ControllerBase {
   self: WikiService
diff --git a/src/main/scala/gitbucket/core/model/Activity.scala b/src/main/scala/gitbucket/core/model/Activity.scala
index 35c990e..a7ca6fb 100644
--- a/src/main/scala/gitbucket/core/model/Activity.scala
+++ b/src/main/scala/gitbucket/core/model/Activity.scala
@@ -1,5 +1,9 @@
 package gitbucket.core.model
 
+/**
+ * ActivityComponent has been deprecated, but keep it for binary compatibility.
+ */
+@deprecated("ActivityComponent has been deprecated, but keep it for binary compatibility.", "4.34.0")
 trait ActivityComponent extends TemplateComponent { self: Profile =>
   import profile.api._
   import self._
@@ -7,14 +11,7 @@
   lazy val Activities = TableQuery[Activities]
 
   class Activities(tag: Tag) extends Table[Activity](tag, "ACTIVITY") with BasicTemplate {
-    val activityId = column[Int]("ACTIVITY_ID", O AutoInc)
-    val activityUserName = column[String]("ACTIVITY_USER_NAME")
-    val activityType = column[String]("ACTIVITY_TYPE")
-    val message = column[String]("MESSAGE")
-    val additionalInfo = column[String]("ADDITIONAL_INFO")
-    val activityDate = column[java.util.Date]("ACTIVITY_DATE")
-    def * =
-      (userName, repositoryName, activityUserName, activityType, message, additionalInfo.?, activityDate, activityId) <> (Activity.tupled, Activity.unapply)
+    def * = ???
   }
 }
 
@@ -26,5 +23,5 @@
   message: String,
   additionalInfo: Option[String],
   activityDate: java.util.Date,
-  activityId: Int = 0
+  activityId: String
 )
diff --git a/src/main/scala/gitbucket/core/model/Profile.scala b/src/main/scala/gitbucket/core/model/Profile.scala
index ce1f96b..4351808 100644
--- a/src/main/scala/gitbucket/core/model/Profile.scala
+++ b/src/main/scala/gitbucket/core/model/Profile.scala
@@ -45,7 +45,7 @@
     with Profile
     with AccessTokenComponent
     with AccountComponent
-    with ActivityComponent
+    with ActivityComponent // ActivityComponent has been deprecated, but keep it for binary compatibility
     with CollaboratorComponent
     with CommitCommentComponent
     with CommitStatusComponent
diff --git a/src/main/scala/gitbucket/core/service/ActivityService.scala b/src/main/scala/gitbucket/core/service/ActivityService.scala
index 5064630..9b6dd8a 100644
--- a/src/main/scala/gitbucket/core/service/ActivityService.scala
+++ b/src/main/scala/gitbucket/core/service/ActivityService.scala
@@ -3,65 +3,169 @@
 import gitbucket.core.model.Activity
 import gitbucket.core.util.JGitUtil
 import gitbucket.core.model.Profile._
-import gitbucket.core.model.Profile.profile.blockingApi._
+import gitbucket.core.util.Directory._
+import org.json4s._
+import org.json4s.jackson.Serialization
+import org.json4s.jackson.Serialization.{read, write}
+
+import scala.util.Using
+import java.io.FileOutputStream
+import java.nio.charset.StandardCharsets
+import java.util.UUID
+
+import gitbucket.core.controller.Context
+import org.apache.commons.io.input.ReversedLinesFileReader
+
+import scala.collection.mutable.ListBuffer
 
 trait ActivityService {
+  self: RequestCache =>
 
-  def deleteOldActivities(limit: Int)(implicit s: Session): Int = {
-    Activities.map(_.activityId).sortBy(_ desc).drop(limit).firstOption.map { id =>
-      Activities.filter(_.activityId <= id.bind).delete
-    } getOrElse 0
+  private implicit val formats = Serialization.formats(NoTypeHints)
+
+  private def writeLog(activity: Activity): Unit = {
+    Using.resource(new FileOutputStream(ActivityLog, true)) { out =>
+      out.write((write(activity) + "\n").getBytes(StandardCharsets.UTF_8))
+    }
   }
 
-  def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit s: Session): List[Activity] =
-    Activities
-      .join(Repositories)
-      .on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
-      .filter {
-        case (t1, t2) =>
-          if (isPublic) {
-            (t1.activityUserName === activityUserName.bind) && (t2.isPrivate === false.bind)
-          } else {
-            (t1.activityUserName === activityUserName.bind)
+  def getActivitiesByUser(activityUserName: String, isPublic: Boolean)(implicit context: Context): List[Activity] = {
+    if (!ActivityLog.exists()) {
+      List.empty
+    } else {
+      val list = new ListBuffer[Activity]
+      Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
+        var json: String = null
+        while (list.length < 50 && { json = reader.readLine(); json } != null) {
+          val activity = read[Activity](json)
+          if (activity.activityUserName == activityUserName) {
+            if (isPublic == false) {
+              list += activity
+            } else {
+              if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
+                    .map(_.isPrivate)
+                    .getOrElse(true)) {
+                list += activity
+              }
+            }
           }
+        }
       }
-      .sortBy { case (t1, t2) => t1.activityId desc }
-      .map { case (t1, t2) => t1 }
-      .take(30)
-      .list
+      list.toList
+    }
+  }
 
-  def getRecentActivities()(implicit s: Session): List[Activity] =
-    Activities
-      .join(Repositories)
-      .on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
-      .filter { case (t1, t2) => t2.isPrivate === false.bind }
-      .sortBy { case (t1, t2) => t1.activityId desc }
-      .map { case (t1, t2) => t1 }
-      .take(30)
-      .list
+  def getRecentPublicActivities()(implicit context: Context): List[Activity] = {
+    if (!ActivityLog.exists()) {
+      List.empty
+    } else {
+      val list = new ListBuffer[Activity]
+      Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
+        var json: String = null
+        while (list.length < 50 && { json = reader.readLine(); json } != null) {
+          val activity = read[Activity](json)
+          if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
+                .map(_.isPrivate)
+                .getOrElse(true)) {
+            list += activity
+          }
+        }
+      }
+      list.toList
+    }
+  }
 
-  def getRecentActivitiesByOwners(owners: Set[String])(implicit s: Session): List[Activity] =
-    Activities
-      .join(Repositories)
-      .on((t1, t2) => t1.byRepository(t2.userName, t2.repositoryName))
-      .filter { case (t1, t2) => (t2.isPrivate === false.bind) || (t2.userName inSetBind owners) }
-      .sortBy { case (t1, t2) => t1.activityId desc }
-      .map { case (t1, t2) => t1 }
-      .take(30)
-      .list
+  def getRecentActivitiesByOwners(owners: Set[String])(implicit context: Context): List[Activity] = {
+    if (!ActivityLog.exists()) {
+      List.empty
+    } else {
+      val list = new ListBuffer[Activity]
+      Using.resource(new ReversedLinesFileReader(ActivityLog, StandardCharsets.UTF_8)) { reader =>
+        var json: String = null
+        while (list.length < 50 && { json = reader.readLine(); json } != null) {
+          val activity = read[Activity](json)
+          if (owners.contains(activity.userName)) {
+            list += activity
+          } else if (!getRepositoryInfoFromCache(activity.userName, activity.repositoryName)
+                       .map(_.isPrivate)
+                       .getOrElse(true)) {
+            list += activity
+          }
+        }
+      }
+      list.toList
+    }
+  }
 
-  def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String)(
-    implicit s: Session
-  ): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "create_repository",
-      s"[user:${activityUserName}] created [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  def recordCreateRepositoryActivity(userName: String, repositoryName: String, activityUserName: String): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "create_repository",
+        s"[user:${activityUserName}] created [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
+
+  def recordDeleteRepositoryActivity(userName: String, repositoryName: String, activityUserName: String): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "delete_repository",
+        s"[user:${activityUserName}] deleted [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
+    )
+  }
+
+  def recordTransferRepositoryActivity(
+    userName: String,
+    repositoryName: String,
+    oldUserName: String,
+    activityUserName: String
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "transfer_repository",
+        s"[user:${activityUserName}] transfered [repo:${oldUserName}/${repositoryName}] to [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
+    )
+  }
+
+  def recordRenameRepositoryActivity(
+    userName: String,
+    repositoryName: String,
+    oldRepositoryName: String,
+    activityUserName: String
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "rename_repository",
+        s"[user:${activityUserName}] renamed [repo:${userName}/${oldRepositoryName}] at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
+    )
+  }
 
   def recordCreateIssueActivity(
     userName: String,
@@ -69,16 +173,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "open_issue",
-      s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "open_issue",
+        s"[user:${activityUserName}] opened issue [issue:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCloseIssueActivity(
     userName: String,
@@ -86,16 +194,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "close_issue",
-      s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "close_issue",
+        s"[user:${activityUserName}] closed issue [issue:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordClosePullRequestActivity(
     userName: String,
@@ -103,16 +215,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "close_issue",
-      s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "close_issue",
+        s"[user:${activityUserName}] closed pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordReopenIssueActivity(
     userName: String,
@@ -120,16 +236,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "reopen_issue",
-      s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "reopen_issue",
+        s"[user:${activityUserName}] reopened issue [issue:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordReopenPullRequestActivity(
     userName: String,
@@ -137,16 +257,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "reopen_issue",
-      s"[user:${activityUserName}] reopened pull request [issue:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "reopen_issue",
+        s"[user:${activityUserName}] reopened pull request [issue:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCommentIssueActivity(
     userName: String,
@@ -154,16 +278,20 @@
     activityUserName: String,
     issueId: Int,
     comment: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "comment_issue",
-      s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
-      Some(cut(comment, 200)),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "comment_issue",
+        s"[user:${activityUserName}] commented on issue [issue:${userName}/${repositoryName}#${issueId}]",
+        Some(cut(comment, 200)),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCommentPullRequestActivity(
     userName: String,
@@ -171,16 +299,20 @@
     activityUserName: String,
     issueId: Int,
     comment: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "comment_issue",
-      s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
-      Some(cut(comment, 200)),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "comment_issue",
+        s"[user:${activityUserName}] commented on pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
+        Some(cut(comment, 200)),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCommentCommitActivity(
     userName: String,
@@ -188,32 +320,40 @@
     activityUserName: String,
     commitId: String,
     comment: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "comment_commit",
-      s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
-      Some(cut(comment, 200)),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "comment_commit",
+        s"[user:${activityUserName}] commented on commit [commit:${userName}/${repositoryName}@${commitId}]",
+        Some(cut(comment, 200)),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCreateWikiPageActivity(
     userName: String,
     repositoryName: String,
     activityUserName: String,
     pageName: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "create_wiki",
-      s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
-      Some(pageName),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "create_wiki",
+        s"[user:${activityUserName}] created the [repo:${userName}/${repositoryName}] wiki",
+        Some(pageName),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordEditWikiPageActivity(
     userName: String,
@@ -221,16 +361,20 @@
     activityUserName: String,
     pageName: String,
     commitId: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "edit_wiki",
-      s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
-      Some(pageName + ":" + commitId),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "edit_wiki",
+        s"[user:${activityUserName}] edited the [repo:${userName}/${repositoryName}] wiki",
+        Some(pageName + ":" + commitId),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordPushActivity(
     userName: String,
@@ -238,23 +382,27 @@
     activityUserName: String,
     branchName: String,
     commits: List[JGitUtil.CommitInfo]
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "push",
-      s"[user:${activityUserName}] pushed to [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
-      Some(
-        commits
-          .take(5)
-          .map { commit =>
-            commit.id + ":" + commit.shortMessage
-          }
-          .mkString("\n")
-      ),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "push",
+        s"[user:${activityUserName}] pushed to [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
+        Some(
+          commits
+            .take(5)
+            .map { commit =>
+              commit.id + ":" + commit.shortMessage
+            }
+            .mkString("\n")
+        ),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCreateTagActivity(
     userName: String,
@@ -262,16 +410,20 @@
     activityUserName: String,
     tagName: String,
     commits: List[JGitUtil.CommitInfo]
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "create_tag",
-      s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "create_tag",
+        s"[user:${activityUserName}] created tag [tag:${userName}/${repositoryName}#${tagName}] at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordDeleteTagActivity(
     userName: String,
@@ -279,61 +431,80 @@
     activityUserName: String,
     tagName: String,
     commits: List[JGitUtil.CommitInfo]
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "delete_tag",
-      s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "delete_tag",
+        s"[user:${activityUserName}] deleted tag ${tagName} at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordCreateBranchActivity(
     userName: String,
     repositoryName: String,
     activityUserName: String,
     branchName: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "create_branch",
-      s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "create_branch",
+        s"[user:${activityUserName}] created branch [branch:${userName}/${repositoryName}#${branchName}] at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordDeleteBranchActivity(
     userName: String,
     repositoryName: String,
     activityUserName: String,
     branchName: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "delete_branch",
-      s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "delete_branch",
+        s"[user:${activityUserName}] deleted branch ${branchName} at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
-  def recordForkActivity(userName: String, repositoryName: String, activityUserName: String, forkedUserName: String)(
-    implicit s: Session
-  ): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "fork",
-      s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
-      None,
-      currentDate
+  def recordForkActivity(
+    userName: String,
+    repositoryName: String,
+    activityUserName: String,
+    forkedUserName: String
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "fork",
+        s"[user:${activityUserName}] forked [repo:${userName}/${repositoryName}] to [repo:${forkedUserName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordPullRequestActivity(
     userName: String,
@@ -341,16 +512,20 @@
     activityUserName: String,
     issueId: Int,
     title: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "open_pullreq",
-      s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
-      Some(title),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "open_pullreq",
+        s"[user:${activityUserName}] opened pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
+        Some(title),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordMergeActivity(
     userName: String,
@@ -358,16 +533,20 @@
     activityUserName: String,
     issueId: Int,
     message: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "merge_pullreq",
-      s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
-      Some(message),
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "merge_pullreq",
+        s"[user:${activityUserName}] merged pull request [pullreq:${userName}/${repositoryName}#${issueId}]",
+        Some(message),
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   def recordReleaseActivity(
     userName: String,
@@ -375,16 +554,20 @@
     activityUserName: String,
     releaseName: String,
     tagName: String
-  )(implicit s: Session): Unit =
-    Activities insert Activity(
-      userName,
-      repositoryName,
-      activityUserName,
-      "release",
-      s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
-      None,
-      currentDate
+  ): Unit = {
+    writeLog(
+      Activity(
+        userName,
+        repositoryName,
+        activityUserName,
+        "release",
+        s"[user:${activityUserName}] released [release:${userName}/${repositoryName}/${tagName}:${releaseName}] at [repo:${userName}/${repositoryName}]",
+        None,
+        currentDate,
+        UUID.randomUUID().toString
+      )
     )
+  }
 
   private def cut(value: String, length: Int): String =
     if (value.length > length) value.substring(0, length) + "..." else value
diff --git a/src/main/scala/gitbucket/core/service/RepositoryService.scala b/src/main/scala/gitbucket/core/service/RepositoryService.scala
index 2e3d881..c04dd6c 100644
--- a/src/main/scala/gitbucket/core/service/RepositoryService.scala
+++ b/src/main/scala/gitbucket/core/service/RepositoryService.scala
@@ -1,6 +1,5 @@
 package gitbucket.core.service
 
-import gitbucket.core.api.JsonFormat
 import gitbucket.core.controller.Context
 import gitbucket.core.util._
 import gitbucket.core.util.SyntaxSugars._
@@ -9,14 +8,11 @@
 import gitbucket.core.model.Profile.profile.blockingApi._
 import gitbucket.core.model.Profile.dateColumnType
 import gitbucket.core.plugin.PluginRegistry
-import gitbucket.core.service.WebHookService.WebHookPushPayload
 import gitbucket.core.util.Directory.{getRepositoryDir, getRepositoryFilesDir, getTemporaryDir, getWikiRepositoryDir}
-import gitbucket.core.util.JGitUtil.{CommitInfo, FileInfo}
+import gitbucket.core.util.JGitUtil.FileInfo
 import org.apache.commons.io.FileUtils
 import org.eclipse.jgit.api.Git
-import org.eclipse.jgit.dircache.{DirCache, DirCacheBuilder}
 import org.eclipse.jgit.lib.{Repository => _, _}
-import org.eclipse.jgit.transport.{ReceiveCommand, ReceivePack}
 import scala.util.Using
 
 trait RepositoryService {
@@ -119,15 +115,6 @@
             }
             .update(newUserName, newRepositoryName)
 
-          // Updates activity fk before deleting repository because activity is sorted by activityId
-          // and it can't be changed by deleting-and-inserting record.
-          Activities.filter(_.byRepository(oldUserName, oldRepositoryName)).list.foreach { activity =>
-            Activities
-              .filter(_.activityId === activity.activityId.bind)
-              .map(x => (x.userName, x.repositoryName))
-              .update(newUserName, newRepositoryName)
-          }
-
           deleteRepositoryOnModel(oldUserName, oldRepositoryName)
 
           RepositoryWebHooks.insertAll(
@@ -213,50 +200,6 @@
             collaborators.map(_.copy(userName = newUserName, repositoryName = newRepositoryName)): _*
           )
 
-          // Update activity messages
-          Activities
-            .filter { t =>
-              (t.message like s"%:${oldUserName}/${oldRepositoryName}]%") ||
-              (t.message like s"%:${oldUserName}/${oldRepositoryName}#%") ||
-              (t.message like s"%:${oldUserName}/${oldRepositoryName}@%")
-            }
-            .map { t =>
-              t.activityId -> t.message
-            }
-            .list
-            .foreach {
-              case (activityId, message) =>
-                Activities
-                  .filter(_.activityId === activityId.bind)
-                  .map(_.message)
-                  .update(
-                    message
-                      .replace(
-                        s"[repo:${oldUserName}/${oldRepositoryName}]",
-                        s"[repo:${newUserName}/${newRepositoryName}]"
-                      )
-                      .replace(
-                        s"[branch:${oldUserName}/${oldRepositoryName}#",
-                        s"[branch:${newUserName}/${newRepositoryName}#"
-                      )
-                      .replace(
-                        s"[tag:${oldUserName}/${oldRepositoryName}#",
-                        s"[tag:${newUserName}/${newRepositoryName}#"
-                      )
-                      .replace(
-                        s"[pullreq:${oldUserName}/${oldRepositoryName}#",
-                        s"[pullreq:${newUserName}/${newRepositoryName}#"
-                      )
-                      .replace(
-                        s"[issue:${oldUserName}/${oldRepositoryName}#",
-                        s"[issue:${newUserName}/${newRepositoryName}#"
-                      )
-                      .replace(
-                        s"[commit:${oldUserName}/${oldRepositoryName}@",
-                        s"[commit:${newUserName}/${newRepositoryName}@"
-                      )
-                  )
-            }
           // Move git repository
           defining(getRepositoryDir(oldUserName, oldRepositoryName)) { dir =>
             if (dir.isDirectory) {
@@ -304,7 +247,7 @@
   }
 
   private def deleteRepositoryOnModel(userName: String, repositoryName: String)(implicit s: Session): Unit = {
-    Activities.filter(_.byRepository(userName, repositoryName)).delete
+//    Activities.filter(_.byRepository(userName, repositoryName)).delete
     Collaborators.filter(_.byRepository(userName, repositoryName)).delete
     CommitComments.filter(_.byRepository(userName, repositoryName)).delete
     IssueLabels.filter(_.byRepository(userName, repositoryName)).delete
diff --git a/src/main/scala/gitbucket/core/service/RequestCache.scala b/src/main/scala/gitbucket/core/service/RequestCache.scala
index d1b12de..485e769 100644
--- a/src/main/scala/gitbucket/core/service/RequestCache.scala
+++ b/src/main/scala/gitbucket/core/service/RequestCache.scala
@@ -1,9 +1,11 @@
 package gitbucket.core.service
 
-import gitbucket.core.model.{Session, Issue, Account}
+import gitbucket.core.model.{Account, Issue, Repository, Session}
 import gitbucket.core.util.Implicits
 import gitbucket.core.controller.Context
 import Implicits.request2Session
+import gitbucket.core.model.Profile.{Accounts, Repositories}
+import gitbucket.core.model.Profile.profile.blockingApi._
 
 /**
  * This service is used for a view helper mainly.
@@ -23,21 +25,41 @@
   private implicit def context2Session(implicit context: Context): Session =
     request2Session(context.request)
 
-  def getIssue(userName: String, repositoryName: String, issueId: String)(implicit context: Context): Option[Issue] = {
+  def getIssueFromCache(userName: String, repositoryName: String, issueId: String)(
+    implicit context: Context
+  ): Option[Issue] = {
     context.cache(s"issue.${userName}/${repositoryName}#${issueId}") {
       super.getIssue(userName, repositoryName, issueId)
     }
   }
 
-  def getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = {
+  def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = {
     context.cache(s"account.${userName}") {
       super.getAccountByUserName(userName)
     }
   }
 
-  def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = {
+  def getAccountByMailAddressFromCache(mailAddress: String)(implicit context: Context): Option[Account] = {
     context.cache(s"account.${mailAddress}") {
       super.getAccountByMailAddress(mailAddress)
     }
   }
+
+  def getRepositoryInfoFromCache(userName: String, repositoryName: String)(
+    implicit context: Context
+  ): Option[Repository] = {
+    context.cache(s"repository.${userName}/${repositoryName}") {
+      Repositories
+        .join(Accounts)
+        .on(_.userName === _.userName)
+        .filter {
+          case (t1, t2) =>
+            t1.byRepository(userName, repositoryName) && t2.removed === false.bind
+        }
+        .map {
+          case (t1, t2) => t1
+        }
+        .firstOption
+    }
+  }
 }
diff --git a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
index 1de4e1a..acc6f77 100644
--- a/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
+++ b/src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
@@ -240,7 +240,8 @@
     with WebHookPullRequestService
     with WebHookPullRequestReviewCommentService
     with CommitsService
-    with SystemSettingsService {
+    with SystemSettingsService
+    with RequestCache {
 
   private val logger = LoggerFactory.getLogger(classOf[CommitLogHook])
   private var existIds: Seq[String] = Nil
diff --git a/src/main/scala/gitbucket/core/servlet/InitializeListener.scala b/src/main/scala/gitbucket/core/servlet/InitializeListener.scala
index aa85d79..ad2f6a6 100644
--- a/src/main/scala/gitbucket/core/servlet/InitializeListener.scala
+++ b/src/main/scala/gitbucket/core/servlet/InitializeListener.scala
@@ -2,11 +2,10 @@
 
 import java.io.{File, FileOutputStream}
 
-import akka.event.Logging
 import com.typesafe.config.ConfigFactory
 import gitbucket.core.GitBucketCoreModule
 import gitbucket.core.plugin.PluginRegistry
-import gitbucket.core.service.{ActivityService, SystemSettingsService}
+import gitbucket.core.service.SystemSettingsService
 import gitbucket.core.util.DatabaseConfig
 import gitbucket.core.util.Directory._
 import gitbucket.core.util.JDBCUtil._
@@ -21,8 +20,6 @@
 
 import org.apache.commons.io.{FileUtils, IOUtils}
 import org.slf4j.LoggerFactory
-import akka.actor.{Actor, ActorSystem, Props}
-import com.typesafe.akka.extension.quartz.QuartzSchedulerExtension
 
 import scala.jdk.CollectionConverters._
 import scala.util.Using
@@ -35,23 +32,23 @@
 
   private val logger = LoggerFactory.getLogger(classOf[InitializeListener])
 
-  // ActorSystem for Quartz scheduler
-  private val system = ActorSystem(
-    "job",
-    ConfigFactory.parseString("""
-      |akka {
-      |  daemonic = on
-      |  coordinated-shutdown.run-by-jvm-shutdown-hook = off
-      |  quartz {
-      |    schedules {
-      |      Daily {
-      |        expression = "0 0 0 * * ?"
-      |      }
-      |    }
-      |  }
-      |}
-    """.stripMargin)
-  )
+//  // ActorSystem for Quartz scheduler
+//  private val system = ActorSystem(
+//    "job",
+//    ConfigFactory.parseString("""
+//      |akka {
+//      |  daemonic = on
+//      |  coordinated-shutdown.run-by-jvm-shutdown-hook = off
+//      |  quartz {
+//      |    schedules {
+//      |      Daily {
+//      |        expression = "0 0 0 * * ?"
+//      |      }
+//      |    }
+//      |  }
+//      |}
+//    """.stripMargin)
+//  )
 
   override def contextInitialized(event: ServletContextEvent): Unit = {
     val dataDir = event.getServletContext.getInitParameter("gitbucket.home")
@@ -95,10 +92,10 @@
       PluginRegistry.initialize(event.getServletContext, loadSystemSettings(), conn)
     }
 
-    // Start Quartz scheduler
-    val scheduler = QuartzSchedulerExtension(system)
-
-    scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
+//    // Start Quartz scheduler
+//    val scheduler = QuartzSchedulerExtension(system)
+//
+//    scheduler.schedule("Daily", system.actorOf(Props[DeleteOldActivityActor]), "DeleteOldActivity")
   }
 
   private def checkVersion(manager: JDBCVersionManager, conn: java.sql.Connection): Unit = {
@@ -172,8 +169,8 @@
   }
 
   override def contextDestroyed(event: ServletContextEvent): Unit = {
-    // Shutdown Quartz scheduler
-    system.terminate()
+//    // Shutdown Quartz scheduler
+//    system.terminate()
     // Shutdown plugins
     PluginRegistry.shutdown(event.getServletContext, loadSystemSettings())
     // Close datasource
@@ -181,21 +178,3 @@
   }
 
 }
-
-class DeleteOldActivityActor extends Actor with SystemSettingsService with ActivityService {
-
-  private val logger = Logging(context.system, this)
-
-  def receive = {
-    case s: String => {
-      loadSystemSettings().activityLogLimit.foreach { limit =>
-        if (limit > 0) {
-          Database() withTransaction { implicit session =>
-            val rows = deleteOldActivities(limit)
-            logger.info(s"Deleted ${rows} activity logs")
-          }
-        }
-      }
-    }
-  }
-}
diff --git a/src/main/scala/gitbucket/core/util/Directory.scala b/src/main/scala/gitbucket/core/util/Directory.scala
index 0ba5238..6c34797 100644
--- a/src/main/scala/gitbucket/core/util/Directory.scala
+++ b/src/main/scala/gitbucket/core/util/Directory.scala
@@ -29,6 +29,8 @@
 
   val GitBucketConf = new File(GitBucketHome, "gitbucket.conf")
 
+  val ActivityLog = new File(GitBucketHome, "activity.log")
+
   val RepositoryHome = s"${GitBucketHome}/repositories"
 
   val DatabaseHome = s"${GitBucketHome}/data"
diff --git a/src/main/scala/gitbucket/core/view/AvatarImageProvider.scala b/src/main/scala/gitbucket/core/view/AvatarImageProvider.scala
index 1c233e9..3df7c86 100644
--- a/src/main/scala/gitbucket/core/view/AvatarImageProvider.scala
+++ b/src/main/scala/gitbucket/core/view/AvatarImageProvider.scala
@@ -17,7 +17,7 @@
 
     val src = if (mailAddress.isEmpty) {
       // by user name
-      getAccountByUserName(userName).map { account =>
+      getAccountByUserNameFromCache(userName).map { account =>
         if (account.image.isEmpty && context.settings.gravatar) {
           s"""https://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress.toLowerCase)}?s=${size}&d=retro&r=g"""
         } else {
@@ -28,7 +28,7 @@
       }
     } else {
       // by mail address
-      getAccountByMailAddress(mailAddress).map { account =>
+      getAccountByMailAddressFromCache(mailAddress).map { account =>
         if (account.image.isEmpty && context.settings.gravatar) {
           s"""https://www.gravatar.com/avatar/${StringUtil.md5(account.mailAddress.toLowerCase)}?s=${size}&d=retro&r=g"""
         } else {
diff --git a/src/main/scala/gitbucket/core/view/LinkConverter.scala b/src/main/scala/gitbucket/core/view/LinkConverter.scala
index cbfac59..dbc76cc 100644
--- a/src/main/scala/gitbucket/core/view/LinkConverter.scala
+++ b/src/main/scala/gitbucket/core/view/LinkConverter.scala
@@ -16,7 +16,7 @@
     val userName = repository.repository.userName
     val repositoryName = repository.repository.repositoryName
 
-    getIssue(userName, repositoryName, issueId.toString) match {
+    getIssueFromCache(userName, repositoryName, issueId.toString) match {
       case Some(issue) =>
         s"""<a href="${context.path}/${userName}/${repositoryName}/${if (issue.isPullRequest) "pull" else "issues"}/${issueId}"><strong>${StringUtil
           .escapeHtml(title)}</strong> #${issueId}</a>"""
@@ -43,7 +43,7 @@
     escaped
     // convert username/project@SHA to link
       .replaceBy("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)@([a-f0-9]{40})(?=(\\W|$))".r) { m =>
-        getAccountByUserName(m.group(2)).map { _ =>
+        getAccountByUserNameFromCache(m.group(2)).map { _ =>
           s"""<code><a href="${context.path}/${m.group(2)}/${m.group(3)}/commit/${m.group(4)}">${m.group(2)}/${m.group(
             3
           )}@${m.group(4).substring(0, 7)}</a></code>"""
@@ -53,7 +53,7 @@
       // convert username/project#Num to link
       .replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)/([a-zA-Z0-9\\-_\\.]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) {
         m =>
-          getIssue(m.group(2), m.group(3), m.group(4)) match {
+          getIssueFromCache(m.group(2), m.group(3), m.group(4)) match {
             case Some(issue) if (issue.isPullRequest) =>
               Some(s"""<a href="${context.path}/${m.group(2)}/${m.group(3)}/pull/${m.group(4)}">${m.group(2)}/${m.group(
                 3
@@ -68,7 +68,7 @@
 
       // convert username@SHA to link
       .replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)@([a-f0-9]{40})(?=(\\W|$))").r) { m =>
-        getAccountByUserName(m.group(2)).map { _ =>
+        getAccountByUserNameFromCache(m.group(2)).map { _ =>
           s"""<code><a href="${context.path}/${m.group(2)}/${repository.name}/commit/${m.group(3)}">${m.group(2)}@${m
             .group(3)
             .substring(0, 7)}</a></code>"""
@@ -77,7 +77,7 @@
 
       // convert username#Num to link
       .replaceBy(("(?<=(^|\\W))([a-zA-Z0-9\\-_]+)" + issueIdPrefix + "([0-9]+)(?=(\\W|$))").r) { m =>
-        getIssue(m.group(2), repository.name, m.group(3)) match {
+        getIssueFromCache(m.group(2), repository.name, m.group(3)) match {
           case Some(issue) if (issue.isPullRequest) =>
             Some(s"""<a href="${context.path}/${m.group(2)}/${repository.name}/pull/${m.group(3)}">${m.group(2)}#${m
               .group(3)}</a>""")
@@ -92,7 +92,7 @@
       // convert issue id to link
       .replaceBy(("(?<=(^|\\W))(GH-|(?<!&)" + issueIdPrefix + ")([0-9]+)(?=(\\W|$))").r) { m =>
         val prefix = if (m.group(2) == "issue:") "#" else m.group(2)
-        getIssue(repository.owner, repository.name, m.group(3)) match {
+        getIssueFromCache(repository.owner, repository.name, m.group(3)) match {
           case Some(issue) if (issue.isPullRequest) =>
             Some(s"""<a href="${context.path}/${repository.owner}/${repository.name}/pull/${m.group(3)}">${prefix}${m
               .group(3)}</a>""")
@@ -106,7 +106,7 @@
 
       // convert @username to link
       .replaceBy("(?<=(^|\\W))@([a-zA-Z0-9\\-_\\.]+)(?=(\\W|$))".r) { m =>
-        getAccountByUserName(m.group(2)).map { _ =>
+        getAccountByUserNameFromCache(m.group(2)).map { _ =>
           s"""<a href="${context.path}/${m.group(2)}">@${m.group(2)}</a>"""
         }
       }
diff --git a/src/main/scala/gitbucket/core/view/helpers.scala b/src/main/scala/gitbucket/core/view/helpers.scala
index e9b1413..db35356 100644
--- a/src/main/scala/gitbucket/core/view/helpers.scala
+++ b/src/main/scala/gitbucket/core/view/helpers.scala
@@ -3,7 +3,6 @@
 import java.text.SimpleDateFormat
 import java.util.{Date, Locale, TimeZone}
 
-import com.nimbusds.jose.util.JSONObjectUtils
 import gitbucket.core.controller.Context
 import gitbucket.core.model.CommitState
 import gitbucket.core.model.PullRequest
@@ -196,7 +195,7 @@
 
   import scala.util.matching.Regex._
   implicit class RegexReplaceString(private val s: String) extends AnyVal {
-    def replaceAll(pattern: String, replacer: (Match) => String): String = {
+    def replaceAll(pattern: String)(replacer: Match => String): String = {
       pattern.r.replaceAllIn(s, (m: Match) => replacer(m).replace("$", "\\$"))
     }
   }
@@ -204,50 +203,64 @@
   /**
    * Convert link notations in the activity message.
    */
+  // format: off
   def activityMessage(message: String)(implicit context: Context): Html =
     Html(
       message
-        .replaceAll(
-          "\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
-          s"""<a href="${context.path}/$$1/$$2/issues/$$3">$$1/$$2#$$3</a>"""
-        )
-        .replaceAll(
-          "\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]",
-          s"""<a href="${context.path}/$$1/$$2/pull/$$3">$$1/$$2#$$3</a>"""
-        )
-        .replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]", s"""<a href="${context.path}/$$1/$$2\">$$1/$$2</a>""")
-        .replaceAll(
-          "\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
-          (m: Match) =>
-            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
-              .escapeHtml(
-                m.group(3)
-              )}</a>"""
-        )
-        .replaceAll(
-          "\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]",
-          (m: Match) =>
-            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil
-              .escapeHtml(
-                m.group(3)
-              )}</a>"""
-        )
-        .replaceAll("\\[user:([^\\s]+?)\\]", (m: Match) => user(m.group(1)).body)
-        .replaceAll(
-          "\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]",
-          (m: Match) =>
-            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m
-              .group(2)}@${m.group(3).substring(0, 7)}</a>"""
-        )
-        .replaceAll(
-          "\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?):(.+)\\]",
-          (m: Match) =>
-            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${StringUtil
-              .escapeHtml(
-                m.group(4)
-              )}</a>"""
-        )
+        .replaceAll("\\[issue:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/issues/${m.group(3)}">${m.group(1)}/${m.group(2)}#${m.group(3)}</a>"""
+          } else {
+            s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
+          }
+        }
+        .replaceAll("\\[pullreq:([^\\s]+?)/([^\\s]+?)#((\\d+))\\]"){ m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/pull/${m.group(3)}">${m.group(1)}/${m.group(2)}#${m.group(3)}</a>"""
+          } else {
+            s"${m.group(1)}/${m.group(2)}#${m.group(3)}"
+          }
+        }
+        .replaceAll("\\[repo:([^\\s]+?)/([^\\s]+?)\\]") { m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}">${m.group(1)}/${m.group(2)}</a>"""
+          } else {
+            s"${m.group(1)}/${m.group(2)}"
+          }
+        }
+        .replaceAll("\\[branch:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]") { m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
+          } else {
+            StringUtil.escapeHtml(m.group(3))
+          }
+        }
+        .replaceAll("\\[tag:([^\\s]+?)/([^\\s]+?)#([^\\s]+?)\\]") { m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/tree/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(3))}</a>"""
+          } else {
+            StringUtil.escapeHtml(m.group(3))
+          }
+        }
+        .replaceAll("\\[user:([^\\s]+?)\\]") { m =>
+          user(m.group(1)).body
+        }
+        .replaceAll("\\[commit:([^\\s]+?)/([^\\s]+?)\\@([^\\s]+?)\\]") { m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/commit/${m.group(3)}">${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}</a>"""
+          } else {
+            s"${m.group(1)}/${m.group(2)}@${m.group(3).substring(0, 7)}"
+          }
+        }
+        .replaceAll("\\[release:([^\\s]+?)/([^\\s]+?)/([^\\s]+?):(.+)\\]") { m =>
+          if (getRepositoryInfoFromCache(m.group(1), m.group(2)).isDefined) {
+            s"""<a href="${context.path}/${m.group(1)}/${m.group(2)}/releases/${encodeRefName(m.group(3))}">${StringUtil.escapeHtml(m.group(4))}</a>"""
+          } else {
+            StringUtil.escapeHtml(m.group(4))
+          }
+        }
     )
+  // format: off
 
   /**
    * Remove html tags from the given Html instance.
@@ -333,9 +346,9 @@
     content: Html
   )(implicit context: Context): Html =
     (if (mailAddress.isEmpty) {
-       getAccountByUserName(userName)
+       getAccountByUserNameFromCache(userName)
      } else {
-       getAccountByMailAddress(mailAddress)
+       getAccountByMailAddressFromCache(mailAddress)
      }).map { account =>
       Html(s"""<a href="${url(account.userName)}" class="${styleClass}">${content}</a>""")
     } getOrElse content
diff --git a/src/main/twirl/gitbucket/core/helper/activities.scala.html b/src/main/twirl/gitbucket/core/helper/activities.scala.html
index 306a539..8a9dfdf 100644
--- a/src/main/twirl/gitbucket/core/helper/activities.scala.html
+++ b/src/main/twirl/gitbucket/core/helper/activities.scala.html
@@ -7,21 +7,24 @@
   @activities.map { activity =>
     <div class="block">
       @(activity.activityType match {
-        case "open_issue"        => detailActivity(activity, "issue-opened")
-        case "comment_issue"     => detailActivity(activity, "comment-discussion")
-        case "comment_commit"    => detailActivity(activity, "comment-discussion")
-        case "close_issue"       => detailActivity(activity, "issue-closed")
-        case "reopen_issue"      => detailActivity(activity, "issue-reopened")
-        case "open_pullreq"      => detailActivity(activity, "git-pull-request")
-        case "merge_pullreq"     => detailActivity(activity, "git-merge")
-        case "release"           => detailActivity(activity, "package")
-        case "create_repository" => simpleActivity(activity, "repo")
-        case "create_branch"     => simpleActivity(activity, "git-branch")
-        case "delete_branch"     => simpleActivity(activity, "circle-slash")
-        case "create_tag"        => simpleActivity(activity, "tag")
-        case "delete_tag"        => simpleActivity(activity, "circle-slash")
-        case "fork"              => simpleActivity(activity, "repo-forked")
-        case "push"  => customActivity(activity, "git-commit"){
+        case "open_issue"          => simpleActivity(activity)
+        case "comment_issue"       => simpleActivity(activity)
+        case "comment_commit"      => simpleActivity(activity)
+        case "close_issue"         => simpleActivity(activity)
+        case "reopen_issue"        => simpleActivity(activity)
+        case "open_pullreq"        => simpleActivity(activity)
+        case "merge_pullreq"       => simpleActivity(activity)
+        case "release"             => simpleActivity(activity)
+        case "create_repository"   => simpleActivity(activity)
+        case "delete_repository"   => simpleActivity(activity)
+        case "rename_repository"   => simpleActivity(activity)
+        case "transfer_repository" => simpleActivity(activity)
+        case "create_branch"       => simpleActivity(activity)
+        case "delete_branch"       => simpleActivity(activity)
+        case "create_tag"          => simpleActivity(activity)
+        case "delete_tag"          => simpleActivity(activity)
+        case "fork"                => simpleActivity(activity)
+        case "push"  => customActivity(activity){
           <div class="small activity-message">
             {activity.additionalInfo.get.split("\n").reverse.take(4).zipWithIndex.map{ case (commit, i) =>
               if(i == 3){
@@ -37,12 +40,12 @@
             }}
           </div>
         }
-        case "create_wiki" => customActivity(activity, "book"){
+        case "create_wiki" => customActivity(activity){
           <div class="small activity-message">
             Created <a href={s"${context.path}/${activity.userName}/${activity.repositoryName}/wiki/${activity.additionalInfo.get}"}>{activity.additionalInfo.get}</a>.
           </div>
         }
-        case "edit_wiki" => customActivity(activity, "book"){
+        case "edit_wiki" => customActivity(activity){
           activity.additionalInfo.get.split(":") match {
             case Array(pageName, commitId) =>
               <div class="small activity-message">
@@ -60,26 +63,7 @@
   }
 }
 
-@detailActivity(activity: gitbucket.core.model.Activity, image: String) = {
-  @*
-  <div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
-  *@
-  <div>
-    <div class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</div>
-    <div class="strong">
-      @helpers.avatarLink(activity.activityUserName, 16)
-      @helpers.activityMessage(activity.message)
-    </div>
-    @activity.additionalInfo.map { additionalInfo =>
-      <div class=" activity-message">@additionalInfo</div>
-    }
-  </div>
-}
-
-@customActivity(activity: gitbucket.core.model.Activity, image: String)(additionalInfo: Any) = {
-  @*
-  <div class="activity-icon-large"><i class="mega-octicon octicon-@image"></i></div>
-  *@
+@customActivity(activity: gitbucket.core.model.Activity)(additionalInfo: Any) = {
   <div>
     <div class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</div>
     <div class="strong">
@@ -90,10 +74,7 @@
   </div>
 }
 
-@simpleActivity(activity: gitbucket.core.model.Activity, image: String) = {
-  @*
-  <div class="activity-icon-small"><i class="octicon octicon-@image"></i></div>
-  *@
+@simpleActivity(activity: gitbucket.core.model.Activity) = {
   <div>
     <span class="muted small">@gitbucket.core.helper.html.datetimeago(activity.activityDate)</span>
     <div>
diff --git a/src/test/scala/gitbucket/core/service/MergeServiceSpec.scala b/src/test/scala/gitbucket/core/service/MergeServiceSpec.scala
index 67f4bbc..f1daec7 100644
--- a/src/test/scala/gitbucket/core/service/MergeServiceSpec.scala
+++ b/src/test/scala/gitbucket/core/service/MergeServiceSpec.scala
@@ -14,7 +14,7 @@
 class MergeServiceSpec extends FunSpec {
   val service = new MergeService with AccountService with ActivityService with IssuesService with LabelsService
   with MilestonesService with RepositoryService with PrioritiesService with PullRequestService with CommitsService
-  with WebHookPullRequestService with WebHookPullRequestReviewCommentService {}
+  with WebHookPullRequestService with WebHookPullRequestReviewCommentService with RequestCache {}
   val branch = "master"
   val issueId = 10
   def initRepository(owner: String, name: String): File = {
diff --git a/src/test/scala/gitbucket/core/service/PullRequestServiceSpec.scala b/src/test/scala/gitbucket/core/service/PullRequestServiceSpec.scala
index 9cd3c20..6e7e946 100644
--- a/src/test/scala/gitbucket/core/service/PullRequestServiceSpec.scala
+++ b/src/test/scala/gitbucket/core/service/PullRequestServiceSpec.scala
@@ -18,7 +18,8 @@
     with PrioritiesService
     with WebHookService
     with WebHookPullRequestService
-    with WebHookPullRequestReviewCommentService {
+    with WebHookPullRequestReviewCommentService
+    with RequestCache {
 
   def swap(r: (Issue, PullRequest)) = (r._2 -> r._1)
 
diff --git a/src/test/scala/gitbucket/core/service/ServiceSpecBase.scala b/src/test/scala/gitbucket/core/service/ServiceSpecBase.scala
index 4c53b32..3148ed8 100644
--- a/src/test/scala/gitbucket/core/service/ServiceSpecBase.scala
+++ b/src/test/scala/gitbucket/core/service/ServiceSpecBase.scala
@@ -99,7 +99,7 @@
   lazy val dummyService = new RepositoryService with AccountService with ActivityService with IssuesService
   with MergeService with PullRequestService with CommitsService with CommitStatusService with LabelsService
   with MilestonesService with PrioritiesService with WebHookService with WebHookPullRequestService
-  with WebHookPullRequestReviewCommentService {
+  with WebHookPullRequestReviewCommentService with RequestCache {
     override def fetchAsPullRequest(
       userName: String,
       repositoryName: String,
diff --git a/src/test/scala/gitbucket/core/service/WebHookServiceSpec.scala b/src/test/scala/gitbucket/core/service/WebHookServiceSpec.scala
index 744b7ac..6bbb8e0 100644
--- a/src/test/scala/gitbucket/core/service/WebHookServiceSpec.scala
+++ b/src/test/scala/gitbucket/core/service/WebHookServiceSpec.scala
@@ -7,7 +7,7 @@
 class WebHookServiceSpec extends FunSuite with ServiceSpecBase {
   lazy val service = new WebHookPullRequestService with AccountService with ActivityService with RepositoryService
   with MergeService with PullRequestService with IssuesService with CommitsService with LabelsService
-  with MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService
+  with MilestonesService with PrioritiesService with WebHookPullRequestReviewCommentService with RequestCache
 
   test("WebHookPullRequestService.getPullRequestsByRequestForWebhook") {
     withTestDB { implicit session =>
diff --git a/src/test/scala/gitbucket/core/view/AvatarImageProviderSpec.scala b/src/test/scala/gitbucket/core/view/AvatarImageProviderSpec.scala
index 2004bed..fdf03dc 100644
--- a/src/test/scala/gitbucket/core/view/AvatarImageProviderSpec.scala
+++ b/src/test/scala/gitbucket/core/view/AvatarImageProviderSpec.scala
@@ -169,8 +169,9 @@
       context: Context
     ): Html = getAvatarImageHtml(userName, size, mailAddress, tooltip)
 
-    override def getAccountByMailAddress(mailAddress: String)(implicit context: Context): Option[Account] = account
-    override def getAccountByUserName(userName: String)(implicit context: Context): Option[Account] = account
+    override def getAccountByMailAddressFromCache(mailAddress: String)(implicit context: Context): Option[Account] =
+      account
+    override def getAccountByUserNameFromCache(userName: String)(implicit context: Context): Option[Account] = account
   }
 
 }