All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.infobip.kafkistry.service.background.BackgroundJobIssuesRegistry.kt Maven / Gradle / Ivy

The newest version!
package com.infobip.kafkistry.service.background

import com.infobip.kafkistry.utils.deepToString
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.util.concurrent.ConcurrentHashMap

@Service
class BackgroundJobIssuesRegistry {

    private val log = LoggerFactory.getLogger(BackgroundJobIssuesRegistry::class.java)

    private val issues = ConcurrentHashMap()
    private val lastSuccesses = ConcurrentHashMap()

    fun doCapturingException(job: BackgroundJob, clearAfter: Long = 0, execution: () -> Unit) {
        execCapturingException(job, clearAfter, execution)
    }

    fun  execCapturingException(job: BackgroundJob, clearAfter: Long = 0, execution: () -> T): Result {
        val jobExecution = newExecution(job)
        return try {
            val result = execution()
            val prevIssue = issues[job.key]
            if (prevIssue != null && System.currentTimeMillis() >= prevIssue.timestamp + clearAfter) {
                jobExecution.succeeded()
            } else {
                jobExecution.succeededSoftly()
            }
            Result.success(result)
        } catch (ex: Throwable) {
            jobExecution.failed(ex.deepToString())
            log.error("{} failed with exception", job, ex)
            Result.failure(ex)
        }
    }

    fun newExecution(job: BackgroundJob) = JobExecution(job, System.currentTimeMillis())

    inner class JobExecution(
        private val job: BackgroundJob,
        private val startTime: Long,
    ) {

        private fun durationMs() = System.currentTimeMillis() - startTime

        fun succeededSoftly() {
            lastSuccesses[job.key] = job.toSuccessStatus(startTime, durationMs())
        }

        fun succeeded() {
            issues.remove(job.key)
            lastSuccesses[job.key] = job.toSuccessStatus(startTime, durationMs())
        }

        fun failed(message: String) {
            issues[job.key] = BackgroundJobIssue(job, message, startTime, durationMs())
            lastSuccesses.remove(job.key)
        }

    }

    fun clearJob(job: BackgroundJob) {
        issues.remove(job.key)
        lastSuccesses.remove(job.key)
    }

    fun currentIssues(): List {
        return issues.values.sortedBy { it.job.key.jobClass }
    }

    fun currentGroupedIssues(): List {
        return currentIssues()
            .groupBy { with(it.job.key) { cluster ?: category } }
            .map { (group, issues) ->
                BackgroundJobIssuesGroup(group, issues)
            }
    }

    fun currentStatuses(): List {
        return sequence {
            currentIssues().forEach {
                yield(it.toFailureStatus())
            }
            yieldAll(lastSuccesses.values)
        }.sortedBy { it.timestamp }.toList()
    }

    private fun BackgroundJobIssue.toFailureStatus() = BackgroundJobStatus(
        job = job, timestamp = timestamp, lastSuccess = false, lastFailureMessage = failureMessage, lastDurationMs = durationMs,
    )

    private fun BackgroundJob.toSuccessStatus(timestamp: Long, durationMs: Long) = BackgroundJobStatus(
        job = this, timestamp = timestamp, lastSuccess = true, lastFailureMessage = null, lastDurationMs = durationMs,
    )
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy