Skip to content

Clear CompoundAnnotation Cache on Task Changes #8756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions app/controllers/AnnotationController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import models.annotation.AnnotationState.Cancelled
import models.annotation._
import models.dataset.{DatasetDAO, DatasetService}
import models.project.ProjectDAO
import models.task.TaskDAO
import models.task.{TaskDAO, TaskService}
import models.team.{TeamDAO, TeamService}
import models.user.time._
import models.user.{User, UserDAO, UserService}
Expand Down Expand Up @@ -52,6 +52,7 @@ class AnnotationController @Inject()(
tracingStoreService: TracingStoreService,
provider: AnnotationInformationProvider,
annotationRestrictionDefaults: AnnotationRestrictionDefaults,
taskService: TaskService,
analyticsService: AnalyticsService,
slackNotificationService: SlackNotificationService,
mailchimpClient: MailchimpClient,
Expand Down Expand Up @@ -158,6 +159,7 @@ class AnnotationController @Inject()(
_ = logger.info(
s"Reopening annotation $id, new state will be ${AnnotationState.Active.toString}, access context: ${request.identity.toStringAnonymous}")
_ <- annotationDAO.updateState(annotation._id, AnnotationState.Active) ?~> "annotation.invalid"
_ <- Fox.runOptional(annotation._task)(taskService.clearCompoundCache)
updatedAnnotation <- provider.provideAnnotation(typ, id, request.identity) ~> NOT_FOUND
json <- annotationService.publicWrites(updatedAnnotation, Some(request.identity)) ?~> "annotation.write.failed"
} yield JsonOk(json, Messages("annotation.reopened"))
Expand Down Expand Up @@ -298,13 +300,14 @@ class AnnotationController @Inject()(

def cancel(typ: String, id: ObjectId): Action[AnyContent] = sil.SecuredAction.async { implicit request =>
def tryToCancel(annotation: Annotation) =
annotation match {
case t if t.typ == AnnotationType.Task =>
(annotation._task, annotation.typ) match {
case (Some(taskId), AnnotationType.Task) =>
logger.info(
s"Canceling annotation $id, new state will be ${AnnotationState.Cancelled.toString}, access context: ${request.identity.toStringAnonymous}")
annotationDAO.updateState(annotation._id, Cancelled).map { _ =>
JsonOk(Messages("task.finished"))
}
s"Canceling task annotation $id, new state will be ${AnnotationState.Cancelled}, access context: ${request.identity.toStringAnonymous}")
for {
_ <- Fox.runIf(annotation.state == AnnotationState.Finished)(taskService.clearCompoundCache(taskId))
_ <- annotationDAO.updateState(annotation._id, Cancelled)
} yield JsonOk(Messages("task.finished"))
case _ =>
Fox.successful(JsonOk(Messages("annotation.finished")))
}
Expand Down
1 change: 1 addition & 0 deletions app/models/annotation/AnnotationService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ class AnnotationService @Inject()(
for {
_ <- annotationDAO.updateModified(annotation._id, Instant.now)
_ <- annotationDAO.updateState(annotation._id, AnnotationState.Finished)
_ <- Fox.runOptional(annotation._task)(taskService.clearCompoundCache)
} yield {
if (annotation._task.isEmpty)
"annotation.finished"
Expand Down
6 changes: 4 additions & 2 deletions app/models/annotation/AnnotationStore.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class AnnotationStore @Inject()(

private def requestFromCache(id: AnnotationIdentifier): Option[Fox[Annotation]] = {
val handler = annotationInformationHandlerSelector.informationHandlers(id.annotationType)
if (handler.cache) {
if (handler.useCache) {
val cached = getFromCache(id)
cached
} else
Expand All @@ -37,7 +37,7 @@ class AnnotationStore @Inject()(
for {
annotation <- handler.provideAnnotation(id.identifier, user)
} yield {
if (handler.cache) {
if (handler.useCache) {
storeInCache(id, annotation)
}
annotation
Expand All @@ -60,4 +60,6 @@ class AnnotationStore @Inject()(
case None => Empty
}
}

def removeFromCache(id: AnnotationIdentifier): Unit = temporaryAnnotationStore.remove(id.toUniqueString)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ trait AnnotationInformationHandler extends FoxImplicits {

implicit val ec: ExecutionContext

def cache: Boolean = true
def useCache: Boolean = true

def provideAnnotation(identifier: ObjectId, user: Option[User])(implicit ctx: DBAccessContext): Fox[Annotation]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class SavedTracingInformationHandler @Inject()(
with Formatter
with FoxImplicits {

override val cache = false
override val useCache = false

override def nameForAnnotation(annotation: Annotation)(implicit ctx: DBAccessContext): Fox[String] =
for {
Expand Down
11 changes: 10 additions & 1 deletion app/models/task/TaskService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.scalableminds.util.objectid.ObjectId
import com.scalableminds.util.tools.{Fox, FoxImplicits}

import javax.inject.Inject
import models.annotation.{Annotation, AnnotationDAO, AnnotationType}
import models.annotation.{Annotation, AnnotationDAO, AnnotationIdentifier, AnnotationStore, AnnotationType}
import models.dataset.DatasetDAO
import models.project.ProjectDAO
import models.team.TeamDAO
Expand All @@ -19,10 +19,12 @@ import scala.concurrent.ExecutionContext
class TaskService @Inject()(conf: WkConf,
datasetDAO: DatasetDAO,
scriptDAO: ScriptDAO,
annotationStore: AnnotationStore,
userService: UserService,
annotationDAO: AnnotationDAO,
taskTypeDAO: TaskTypeDAO,
teamDAO: TeamDAO,
taskDAO: TaskDAO,
scriptService: ScriptService,
taskTypeService: TaskTypeService,
projectDAO: ProjectDAO)(implicit ec: ExecutionContext)
Expand Down Expand Up @@ -88,4 +90,11 @@ class TaskService @Inject()(conf: WkConf,
activeCount <- Fox.fromFuture(annotationDAO.countActiveByTask(task._id, AnnotationType.Task).getOrElse(0))
} yield TaskStatus(task.pendingInstances, activeCount, task.totalInstances - (activeCount + task.pendingInstances))

def clearCompoundCache(taskId: ObjectId): Fox[Unit] =
for {
task <- taskDAO.findOne(taskId)(GlobalAccessContext)
_ = annotationStore.removeFromCache(AnnotationIdentifier(AnnotationType.CompoundTask, task._id))
_ = annotationStore.removeFromCache(AnnotationIdentifier(AnnotationType.CompoundProject, task._project))
_ = annotationStore.removeFromCache(AnnotationIdentifier(AnnotationType.CompoundTaskType, task._taskType))
} yield ()
}
2 changes: 2 additions & 0 deletions unreleased_changes/8756.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Fixed
- Fixed that compound (merged) views of tasks, projects and task types would sometimes show outdated annotation data, leaving out the data from recently finished tasks annotations.