Pagination + store event
This commit is contained in:
parent
181b1630be
commit
d246403f74
@ -16,7 +16,6 @@ class OperationsController(
|
|||||||
|
|
||||||
@PostMapping("/start")
|
@PostMapping("/start")
|
||||||
fun startProcess(@RequestBody req: StartProcessRequest): ResponseEntity<Map<String, String>> {
|
fun startProcess(@RequestBody req: StartProcessRequest): ResponseEntity<Map<String, String>> {
|
||||||
val referenceId = commandService.startProcess(req)
|
|
||||||
return when (val result = commandService.startProcess(req)) {
|
return when (val result = commandService.startProcess(req)) {
|
||||||
is CommandService.StartResult.Accepted -> ResponseEntity
|
is CommandService.StartResult.Accepted -> ResponseEntity
|
||||||
.accepted()
|
.accepted()
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.controller
|
||||||
|
|
||||||
|
|
||||||
|
import no.iktdev.eventi.models.store.PersistedTask
|
||||||
|
import no.iktdev.mediaprocessing.coordinator.services.TaskService
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.dto.PagedTasks
|
||||||
|
import org.springframework.web.bind.annotation.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tasks")
|
||||||
|
class TaskController(
|
||||||
|
private val taskService: TaskService,
|
||||||
|
) {
|
||||||
|
|
||||||
|
@GetMapping("/active")
|
||||||
|
fun getActiveTasks(): List<PersistedTask> =
|
||||||
|
taskService.getActiveTasks()
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
fun getPagedTasks(
|
||||||
|
@RequestParam(defaultValue = "0") page: Int,
|
||||||
|
@RequestParam(defaultValue = "50") size: Int,
|
||||||
|
): PagedTasks =
|
||||||
|
taskService.getPagedTasks(page, size)
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
fun getTask(@PathVariable id: UUID): PersistedTask? =
|
||||||
|
taskService.getTaskById(id)
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import mu.KotlinLogging
|
|||||||
import no.iktdev.eventi.events.EventListener
|
import no.iktdev.eventi.events.EventListener
|
||||||
import no.iktdev.eventi.models.Event
|
import no.iktdev.eventi.models.Event
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CollectedEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CollectedEvent
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ManualAllowCompletionEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskResultEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskResultEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StoreContentAndMetadataTaskCreatedEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StoreContentAndMetadataTaskCreatedEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.tasks.StoreContentAndMetadataTask
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.tasks.StoreContentAndMetadataTask
|
||||||
@ -21,7 +22,16 @@ class StoreContentAndMetadataListener: EventListener() {
|
|||||||
event: Event,
|
event: Event,
|
||||||
history: List<Event>
|
history: List<Event>
|
||||||
): Event? {
|
): Event? {
|
||||||
val useEvent = event as? MigrateContentToStoreTaskResultEvent ?: return null
|
if (event !is MigrateContentToStoreTaskResultEvent && event !is ManualAllowCompletionEvent)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val useEvent = if (event is ManualAllowCompletionEvent) {
|
||||||
|
history.lastOrNull { it is MigrateContentToStoreTaskResultEvent } as? MigrateContentToStoreTaskResultEvent
|
||||||
|
?: return null
|
||||||
|
} else {
|
||||||
|
event as MigrateContentToStoreTaskResultEvent
|
||||||
|
}
|
||||||
|
|
||||||
val collectionEvent = history.lastOrNull { it is CollectedEvent } as? CollectedEvent
|
val collectionEvent = history.lastOrNull { it is CollectedEvent } as? CollectedEvent
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
@ -39,6 +49,12 @@ class StoreContentAndMetadataListener: EventListener() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!projection.canStoreAutomatically()) {
|
||||||
|
log.info { "Not storing content and metadata automatically for collection: $collection @ ${useEvent.referenceId}" }
|
||||||
|
log.info { "A manual allow completion event is required to proceed." }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val exportInfo = ContentExport(
|
val exportInfo = ContentExport(
|
||||||
collection = collection,
|
collection = collection,
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
package no.iktdev.mediaprocessing.coordinator.services
|
||||||
|
|
||||||
|
import no.iktdev.eventi.models.store.PersistedTask
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.dto.PagedTasks
|
||||||
|
import no.iktdev.mediaprocessing.shared.database.stores.TaskStore
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class TaskService {
|
||||||
|
|
||||||
|
|
||||||
|
fun getActiveTasks(): List<PersistedTask> {
|
||||||
|
return TaskStore.findActiveTasks()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPagedTasks(page: Int, size: Int): PagedTasks {
|
||||||
|
return TaskStore.getPagedTasks(page, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTaskById(taskId: UUID): PersistedTask? {
|
||||||
|
return TaskStore.findByTaskId(taskId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package no.iktdev.mediaprocessing.shared.common.dto
|
||||||
|
|
||||||
|
import no.iktdev.eventi.models.store.PersistedTask
|
||||||
|
|
||||||
|
data class PagedTasks(
|
||||||
|
val content: List<PersistedTask>,
|
||||||
|
val page: Int,
|
||||||
|
val size: Int,
|
||||||
|
val total: Long
|
||||||
|
)
|
||||||
@ -1,34 +1,7 @@
|
|||||||
package no.iktdev.mediaprocessing.shared.common.event_task_contract
|
package no.iktdev.mediaprocessing.shared.common.event_task_contract
|
||||||
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ConvertTaskResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.FileAddedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.FileReadyEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.FileRemovedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaParsedInfoEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserEncodeResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserEncodeTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserExtractTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserExtractResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StartProcessingEvent
|
|
||||||
import no.iktdev.eventi.models.Event
|
import no.iktdev.eventi.models.Event
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CollectedEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.*
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ConvertTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CoordinatorReadStreamsResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CoordinatorReadStreamsTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CoverDownloadResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.CoverDownloadTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MetadataSearchTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaStreamParsedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaTracksDetermineSubtitleTypeEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaTracksEncodeSelectedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaTracksExtractSelectedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MetadataSearchResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskResultEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserEncodePerformedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.ProcesserExtractPerformedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StoreContentAndMetadataTaskCreatedEvent
|
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StoreContentAndMetadataTaskResultEvent
|
|
||||||
|
|
||||||
object EventRegistry {
|
object EventRegistry {
|
||||||
fun getEvents(): List<Class<out Event>> {
|
fun getEvents(): List<Class<out Event>> {
|
||||||
@ -48,6 +21,8 @@ object EventRegistry {
|
|||||||
FileReadyEvent::class.java,
|
FileReadyEvent::class.java,
|
||||||
FileRemovedEvent::class.java,
|
FileRemovedEvent::class.java,
|
||||||
|
|
||||||
|
ManualAllowCompletionEvent::class.java,
|
||||||
|
|
||||||
MediaParsedInfoEvent::class.java,
|
MediaParsedInfoEvent::class.java,
|
||||||
MediaStreamParsedEvent::class.java,
|
MediaStreamParsedEvent::class.java,
|
||||||
MediaTracksDetermineSubtitleTypeEvent::class.java,
|
MediaTracksDetermineSubtitleTypeEvent::class.java,
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
package no.iktdev.mediaprocessing.shared.common.event_task_contract.events
|
||||||
|
|
||||||
|
import no.iktdev.eventi.models.Event
|
||||||
|
|
||||||
|
class ManualAllowCompletionEvent: Event() {
|
||||||
|
}
|
||||||
@ -4,12 +4,18 @@ import no.iktdev.eventi.models.Event
|
|||||||
import no.iktdev.eventi.models.store.TaskStatus
|
import no.iktdev.eventi.models.store.TaskStatus
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaParsedInfoEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MediaParsedInfoEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskResultEvent
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.MigrateContentToStoreTaskResultEvent
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StartFlow
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.event_task_contract.events.StartProcessingEvent
|
||||||
import no.iktdev.mediaprocessing.shared.common.model.ContentExport
|
import no.iktdev.mediaprocessing.shared.common.model.ContentExport
|
||||||
import no.iktdev.mediaprocessing.shared.common.model.MigrateStatus
|
import no.iktdev.mediaprocessing.shared.common.model.MigrateStatus
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class StoreProjection(val events: List<Event>) {
|
class StoreProjection(val events: List<Event>) {
|
||||||
|
|
||||||
|
fun canStoreAutomatically(): Boolean {
|
||||||
|
val manualEvent = events.filterIsInstance<StartProcessingEvent>().lastOrNull()
|
||||||
|
return manualEvent?.data?.flow != StartFlow.Manual
|
||||||
|
}
|
||||||
|
|
||||||
fun projectMetadata(): ContentExport.MetadataExport? {
|
fun projectMetadata(): ContentExport.MetadataExport? {
|
||||||
val metadata = CollectProjection(events).metadata
|
val metadata = CollectProjection(events).metadata
|
||||||
|
|||||||
@ -5,17 +5,48 @@ import no.iktdev.eventi.models.Task
|
|||||||
import no.iktdev.eventi.models.store.PersistedTask
|
import no.iktdev.eventi.models.store.PersistedTask
|
||||||
import no.iktdev.eventi.models.store.TaskStatus
|
import no.iktdev.eventi.models.store.TaskStatus
|
||||||
import no.iktdev.eventi.stores.TaskStore
|
import no.iktdev.eventi.stores.TaskStore
|
||||||
|
import no.iktdev.mediaprocessing.shared.common.dto.PagedTasks
|
||||||
import no.iktdev.mediaprocessing.shared.database.tables.TasksTable
|
import no.iktdev.mediaprocessing.shared.database.tables.TasksTable
|
||||||
import no.iktdev.mediaprocessing.shared.database.withTransaction
|
import no.iktdev.mediaprocessing.shared.database.withTransaction
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.insert
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
|
||||||
import org.jetbrains.exposed.sql.update
|
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.util.UUID
|
import java.util.*
|
||||||
|
|
||||||
object TaskStore: TaskStore {
|
object TaskStore: TaskStore {
|
||||||
|
|
||||||
|
fun getPagedTasks(page: Int, size: Int): PagedTasks {
|
||||||
|
return withTransaction {
|
||||||
|
val total = TasksTable.selectAll().count()
|
||||||
|
val rows = TasksTable
|
||||||
|
.selectAll()
|
||||||
|
.orderBy(TasksTable.persistedAt, SortOrder.DESC)
|
||||||
|
.limit(size).offset(start = (page * size).toLong())
|
||||||
|
.map { it ->
|
||||||
|
PersistedTask(
|
||||||
|
id = it[TasksTable.id].value.toLong(),
|
||||||
|
referenceId = it[TasksTable.referenceId],
|
||||||
|
status = it[TasksTable.status],
|
||||||
|
taskId = it[TasksTable.taskId],
|
||||||
|
task = it[TasksTable.task],
|
||||||
|
data = it[TasksTable.data],
|
||||||
|
claimed = it[TasksTable.claimed],
|
||||||
|
claimedBy = it[TasksTable.claimedBy],
|
||||||
|
consumed = it[TasksTable.consumed],
|
||||||
|
lastCheckIn = it[TasksTable.lastCheckIn],
|
||||||
|
persistedAt = it[TasksTable.persistedAt]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
PagedTasks(
|
||||||
|
content = rows,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
total = total
|
||||||
|
)
|
||||||
|
}.getOrDefault(PagedTasks(emptyList(), page, size, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun persist(task: Task) {
|
override fun persist(task: Task) {
|
||||||
val asData = ZDS.WGson.toJson(task)
|
val asData = ZDS.WGson.toJson(task)
|
||||||
val taskName = task::class.simpleName ?: run {
|
val taskName = task::class.simpleName ?: run {
|
||||||
@ -99,6 +130,28 @@ object TaskStore: TaskStore {
|
|||||||
}.getOrDefault(emptyList())
|
}.getOrDefault(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun findActiveTasks(): List<PersistedTask> {
|
||||||
|
return withTransaction {
|
||||||
|
TasksTable.selectAll()
|
||||||
|
.where { (TasksTable.status inList listOf(TaskStatus.Pending, TaskStatus.InProgress)) and (TasksTable.consumed eq false) }
|
||||||
|
.map {
|
||||||
|
PersistedTask(
|
||||||
|
id = it[TasksTable.id].value.toLong(),
|
||||||
|
referenceId = it[TasksTable.referenceId],
|
||||||
|
status = it[TasksTable.status],
|
||||||
|
taskId = it[TasksTable.taskId],
|
||||||
|
task = it[TasksTable.task],
|
||||||
|
data = it[TasksTable.data],
|
||||||
|
claimed = it[TasksTable.claimed],
|
||||||
|
claimedBy = it[TasksTable.claimedBy],
|
||||||
|
consumed = it[TasksTable.consumed],
|
||||||
|
lastCheckIn = it[TasksTable.lastCheckIn],
|
||||||
|
persistedAt = it[TasksTable.persistedAt]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.getOrDefault(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
override fun claim(taskId: UUID, workerId: String): Boolean {
|
override fun claim(taskId: UUID, workerId: String): Boolean {
|
||||||
return withTransaction {
|
return withTransaction {
|
||||||
TasksTable.update({
|
TasksTable.update({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user