Skip to content
Snippets Groups Projects
TaskManager.kt 4.07 KiB
Newer Older
package de.fraunhofer.iem.dataprovider.taskManager
import de.fraunhofer.iem.dataprovider.gitlab.GitConfiguration
import de.fraunhofer.iem.dataprovider.logger.getLogger
import de.fraunhofer.iem.dataprovider.taskManager.tasks.CloneGitTask
import de.fraunhofer.iem.dataprovider.taskManager.tasks.GetGitlabProjectTask
import de.fraunhofer.iem.dataprovider.taskManager.tasks.GitProject
import de.fraunhofer.iem.dataprovider.taskManager.tasks.OdcTask
import jakarta.annotation.PreDestroy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.channels.actor
import org.springframework.stereotype.Component
import java.util.*


sealed class Event
class RepoChangedEvent(val gitConfiguration: GitConfiguration, val repoId: Long) : Event()

sealed class TaskDone : Event() {
    abstract val taskId: UUID
}

class GitCloneDone(override val taskId: UUID, val outputDirectory: String) : TaskDone()
class GetGitlabProjectDone(override val taskId: UUID, val gitProject: GitProject) : TaskDone()
class ProcessTaskDone(override val taskId: UUID, val message: String) : TaskDone()
 * The Task Manager takes tasks and distributes them to
 * underlying workers. Internally it uses a channel
 * to manage incoming tasks.
class TaskManager(private val config: Config) {
    // The used default dispatcher is ok for CPU-bound workloads. However,
    // if they block for a long time it's better to use a custom thread
    // pool solution.
    private val worker = Worker("Worker")
    // Should be used for long-running tasks, which DON'T use CPU power and
    // are non-blocking
Jan-Niclas Strüwer's avatar
Jan-Niclas Strüwer committed
    private val ioWorker = Worker("IO-Worker", CoroutineScope(Dispatchers.IO))
    // Should be used for long-running CPU heavy tasks, which potentially block.
    // private val customWorker = getCustomThreadpoolWorker()
    private val mainScope = CoroutineScope(Dispatchers.Default)
    private val actor: SendChannel<Event> = mainScope.taskActor()
    suspend fun addEvent(event: Event) {
        actor.send(event)
    @OptIn(ObsoleteCoroutinesApi::class)  // This API is meant to be improved since 2017... so this should be good to use.
    // IntelliJ might tell u that it is ok to remove <ITask> from the actor declaration.
    // IT IS NOT! this will lead to very strange gradle compile errors!
    private fun CoroutineScope.taskActor() = actor<Event> {
        with(MyActor()) {
            for (task in channel) {
                onReceive(task)
            }
        }
    }

    @PreDestroy
        actor.close()
        worker.close()
        ioWorker.close()
    }

    /**
     * The state in this internal class is thread safe.
     * See https://kotlinlang.org/docs/shared-mutable-state-and-concurrency.html#actors
     * It is used to manage e.g. fixed task sequences, as well as react to general events.
     */
    private inner class MyActor {

        private val logger = getLogger(javaClass)
        suspend fun onReceive(event: Event) {
            logger.info("[${Thread.currentThread().name}] add task called in Task Manager $event")

            when (event) {
                is RepoChangedEvent -> {
                    ioWorker.addTask(GetGitlabProjectTask(event.repoId, event.gitConfiguration, ::addEvent))
                is GetGitlabProjectDone -> {
                    worker.addTask(
                        CloneGitTask(
                            event.gitProject,
                            ::addEvent,
                            config.gitProjectPath
                is GitCloneDone -> {
                    worker.addTask(OdcTask(event.outputDirectory, event.outputDirectory, ::addEvent))
                }
                else -> {
                    logger.info("Received event without special handling associated $event")
            logger.info("[${Thread.currentThread().name}] add task finished in Task Manager $event")

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.