mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-06 07:05:59 +00:00
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:
parent
e85bd1267c
commit
90421599ea
@ -25,6 +25,8 @@ case class EmptyTrashArgs(
|
|||||||
def makeSubject: String =
|
def makeSubject: String =
|
||||||
s"Empty Trash: Remove older than ${minAge.toJava}"
|
s"Empty Trash: Remove older than ${minAge.toJava}"
|
||||||
|
|
||||||
|
def periodicTaskId: Ident =
|
||||||
|
EmptyTrashArgs.periodicTaskId(collective)
|
||||||
}
|
}
|
||||||
|
|
||||||
object EmptyTrashArgs {
|
object EmptyTrashArgs {
|
||||||
@ -33,6 +35,9 @@ object EmptyTrashArgs {
|
|||||||
|
|
||||||
val defaultSchedule = CalEvent.unsafe("*-*-1/7 03:00:00")
|
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] =
|
implicit val jsonEncoder: Encoder[EmptyTrashArgs] =
|
||||||
deriveEncoder[EmptyTrashArgs]
|
deriveEncoder[EmptyTrashArgs]
|
||||||
implicit val jsonDecoder: Decoder[EmptyTrashArgs] =
|
implicit val jsonDecoder: Decoder[EmptyTrashArgs] =
|
||||||
|
@ -40,6 +40,8 @@ import docspell.store.records.{REmptyTrashSetting, RJobLog}
|
|||||||
import emil.javamail._
|
import emil.javamail._
|
||||||
import org.http4s.blaze.client.BlazeClientBuilder
|
import org.http4s.blaze.client.BlazeClientBuilder
|
||||||
import org.http4s.client.Client
|
import org.http4s.client.Client
|
||||||
|
import docspell.store.usertask.UserTaskStore
|
||||||
|
import docspell.store.usertask.UserTaskScope
|
||||||
|
|
||||||
final class JoexAppImpl[F[_]: Async](
|
final class JoexAppImpl[F[_]: Async](
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
@ -91,9 +93,15 @@ final class JoexAppImpl[F[_]: Async](
|
|||||||
REmptyTrashSetting.findForAllCollectives(OCollective.EmptyTrash.default, 50)
|
REmptyTrashSetting.findForAllCollectives(OCollective.EmptyTrash.default, 50)
|
||||||
)
|
)
|
||||||
.evalMap(es =>
|
.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
|
.compile
|
||||||
.drain
|
.drain
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ import fs2.Stream
|
|||||||
import docspell.backend.ops.{OItem, OItemSearch}
|
import docspell.backend.ops.{OItem, OItemSearch}
|
||||||
import docspell.common._
|
import docspell.common._
|
||||||
import docspell.joex.scheduler._
|
import docspell.joex.scheduler._
|
||||||
import docspell.store.records.{RItem, RPeriodicTask}
|
import docspell.store.records.RItem
|
||||||
import docspell.store.usertask.{UserTask, UserTaskScope}
|
import docspell.store.usertask.UserTask
|
||||||
|
|
||||||
import com.github.eikek.calev.CalEvent
|
import com.github.eikek.calev.CalEvent
|
||||||
|
|
||||||
@ -26,19 +26,15 @@ object EmptyTrashTask {
|
|||||||
|
|
||||||
private val pageSize = 20
|
private val pageSize = 20
|
||||||
|
|
||||||
def periodicTask[F[_]: Sync](args: EmptyTrashArgs, ce: CalEvent): F[RPeriodicTask] =
|
def userTask(args: EmptyTrashArgs, ce: CalEvent): UserTask[EmptyTrashArgs] =
|
||||||
Ident
|
UserTask(
|
||||||
.randomId[F]
|
args.periodicTaskId,
|
||||||
.flatMap(id =>
|
EmptyTrashArgs.taskName,
|
||||||
UserTask(
|
true,
|
||||||
id,
|
ce,
|
||||||
EmptyTrashArgs.taskName,
|
None,
|
||||||
true,
|
args
|
||||||
ce,
|
)
|
||||||
None,
|
|
||||||
args
|
|
||||||
).encode.toPeriodicTask(UserTaskScope(args.collective), args.makeSubject.some)
|
|
||||||
)
|
|
||||||
|
|
||||||
def apply[F[_]: Async](
|
def apply[F[_]: Async](
|
||||||
itemOps: OItem[F],
|
itemOps: OItem[F],
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
-- note this is only for users of nightly releases
|
||||||
|
DELETE FROM "periodic_task"
|
||||||
|
WHERE "task" = 'empty-trash';
|
@ -0,0 +1,3 @@
|
|||||||
|
-- note this is only for users of nightly releases
|
||||||
|
DELETE FROM `periodic_task`
|
||||||
|
WHERE `task` = 'empty-trash';
|
@ -0,0 +1,3 @@
|
|||||||
|
-- note this is only for users of nightly releases
|
||||||
|
DELETE FROM "periodic_task"
|
||||||
|
WHERE "task" = 'empty-trash';
|
@ -81,7 +81,8 @@ trait UserTaskStore[F[_]] {
|
|||||||
*
|
*
|
||||||
* Unlike `updateTask`, this ensures that there is at most one task of some name in the
|
* 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
|
* 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`,
|
* 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!
|
* they will all be removed and the given task inserted!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user