Fix storing empty-trash task

It was wrongly stored using RPeriodicTask directly, but the higher
level `UserTask` must be used instead, because this ensures a
correctly scoped periodic task using the `updateOneTask` method. Since
this is a system task, it can be given a fixed ID which makes it now
safe even if stored using RPeriodicTask directly.

The bug resulted in multiple empty-trash tasks to be inserted (on each
restart).

Refs: #347
This commit is contained in:
eikek 2021-08-19 00:24:10 +02:00
parent e85bd1267c
commit 90421599ea
7 changed files with 37 additions and 18 deletions

View File

@ -25,6 +25,8 @@ case class EmptyTrashArgs(
def makeSubject: String =
s"Empty Trash: Remove older than ${minAge.toJava}"
def periodicTaskId: Ident =
EmptyTrashArgs.periodicTaskId(collective)
}
object EmptyTrashArgs {
@ -33,6 +35,9 @@ object EmptyTrashArgs {
val defaultSchedule = CalEvent.unsafe("*-*-1/7 03:00:00")
def periodicTaskId(coll: Ident): Ident =
Ident.unsafe(s"docspell") / taskName / coll
implicit val jsonEncoder: Encoder[EmptyTrashArgs] =
deriveEncoder[EmptyTrashArgs]
implicit val jsonDecoder: Decoder[EmptyTrashArgs] =

View File

@ -40,6 +40,8 @@ import docspell.store.records.{REmptyTrashSetting, RJobLog}
import emil.javamail._
import org.http4s.blaze.client.BlazeClientBuilder
import org.http4s.client.Client
import docspell.store.usertask.UserTaskStore
import docspell.store.usertask.UserTaskScope
final class JoexAppImpl[F[_]: Async](
cfg: Config,
@ -91,9 +93,15 @@ final class JoexAppImpl[F[_]: Async](
REmptyTrashSetting.findForAllCollectives(OCollective.EmptyTrash.default, 50)
)
.evalMap(es =>
EmptyTrashTask.periodicTask(EmptyTrashArgs(es.cid, es.minAge), es.schedule)
UserTaskStore(store).use { uts =>
val args = EmptyTrashArgs(es.cid, es.minAge)
uts.updateOneTask(
UserTaskScope(args.collective),
args.makeSubject.some,
EmptyTrashTask.userTask(args, es.schedule)
)
}
)
.evalMap(pstore.insert)
.compile
.drain

View File

@ -13,8 +13,8 @@ import fs2.Stream
import docspell.backend.ops.{OItem, OItemSearch}
import docspell.common._
import docspell.joex.scheduler._
import docspell.store.records.{RItem, RPeriodicTask}
import docspell.store.usertask.{UserTask, UserTaskScope}
import docspell.store.records.RItem
import docspell.store.usertask.UserTask
import com.github.eikek.calev.CalEvent
@ -26,19 +26,15 @@ object EmptyTrashTask {
private val pageSize = 20
def periodicTask[F[_]: Sync](args: EmptyTrashArgs, ce: CalEvent): F[RPeriodicTask] =
Ident
.randomId[F]
.flatMap(id =>
UserTask(
id,
EmptyTrashArgs.taskName,
true,
ce,
None,
args
).encode.toPeriodicTask(UserTaskScope(args.collective), args.makeSubject.some)
)
def userTask(args: EmptyTrashArgs, ce: CalEvent): UserTask[EmptyTrashArgs] =
UserTask(
args.periodicTaskId,
EmptyTrashArgs.taskName,
true,
ce,
None,
args
)
def apply[F[_]: Async](
itemOps: OItem[F],

View File

@ -0,0 +1,3 @@
-- note this is only for users of nightly releases
DELETE FROM "periodic_task"
WHERE "task" = 'empty-trash';

View File

@ -0,0 +1,3 @@
-- note this is only for users of nightly releases
DELETE FROM `periodic_task`
WHERE `task` = 'empty-trash';

View File

@ -0,0 +1,3 @@
-- note this is only for users of nightly releases
DELETE FROM "periodic_task"
WHERE "task" = 'empty-trash';

View File

@ -81,7 +81,8 @@ trait UserTaskStore[F[_]] {
*
* Unlike `updateTask`, this ensures that there is at most one task of some name in the
* db. Multiple same tasks (task with same name) may not be allowed to run, depending
* on what they do. This is not ensured by the database, though.
* on what they do. This is not ensured by the database, though. The task is identified
* by task name, submitter and group.
*
* If there are currently multiple tasks with same name as `ut` for the user `account`,
* they will all be removed and the given task inserted!