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

org.enodeframework.common.io.IOHelper.kt Maven / Gradle / Ivy

There is a newer version: 1.1.10
Show newest version
package org.enodeframework.common.io

import org.enodeframework.common.exception.IORuntimeException
import org.enodeframework.common.function.Action1
import org.enodeframework.common.function.Action2
import org.enodeframework.common.function.DelayedTask
import org.enodeframework.common.function.Func
import org.enodeframework.common.utilities.Ensure
import org.slf4j.LoggerFactory
import java.time.Duration
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException

/**
 * @author [email protected]
 */
object IOHelper {

    private val logger = LoggerFactory.getLogger(IOHelper::class.java)

    @JvmStatic
    fun  tryAsyncActionRecursively(
            asyncActionName: String,
            asyncAction: Func>,
            successAction: Action1,
            getContextInfoFunc: Func,
            failedAction: Action2?,
            retryTimes: Int,
            retryWhenFailed: Boolean) {
        tryAsyncActionRecursively(asyncActionName, asyncAction, successAction, getContextInfoFunc, failedAction, retryTimes, retryWhenFailed, 3, 1000)
    }

    @JvmStatic
    fun  tryAsyncActionRecursively(
            asyncActionName: String,
            asyncAction: Func>,
            successAction: Action1,
            getContextInfoFunc: Func,
            failedAction: Action2?,
            retryTimes: Int,
            retryWhenFailed: Boolean,
            maxRetryTimes: Int,
            retryInterval: Int) {
        val asyncTaskExecutionContext = AsyncTaskExecutionContext(asyncActionName, asyncAction, successAction, getContextInfoFunc, failedAction, retryTimes, retryWhenFailed, maxRetryTimes, retryInterval)
        asyncTaskExecutionContext.execute()
    }

    @JvmStatic
    fun  tryAsyncActionRecursivelyWithoutResult(
            asyncActionName: String,
            asyncAction: Func>,
            successAction: Action1,
            getContextInfoFunc: Func,
            failedAction: Action2?,
            retryTimes: Int,
            retryWhenFailed: Boolean) {
        val asyncTaskExecutionContext = AsyncTaskExecutionContext(asyncActionName, asyncAction, successAction, getContextInfoFunc, failedAction, retryTimes, retryWhenFailed, 3, 1000)
        asyncTaskExecutionContext.execute()
    }

    @JvmStatic
    fun  tryIOFuncAsync(func: Func>, funcName: String): CompletableFuture {
        Ensure.notNull(func, "func")
        Ensure.notNull(funcName, "funcName")
        return try {
            func.apply()
        } catch (ex: Exception) {
            throw IORuntimeException(String.format("%s failed.", funcName), ex)
        }
    }

    internal class AsyncTaskExecutionContext(private val actionName: String, asyncAction: Func>, successAction: Action1, contextInfoFunc: Func, failedAction: Action2?, retryTimes: Int, retryWhenFailed: Boolean, maxRetryTimes: Int, retryInterval: Int) {
        private val asyncAction: Func>
        private val successAction: Action1
        private val contextInfoFunc: Func
        private val failedAction: Action2?
        private var currentRetryTimes: Int
        private val retryWhenFailed: Boolean
        private val maxRetryTimes: Int
        private val retryInterval: Int
        fun execute() {
            var asyncResult = CompletableFuture()
            try {
                asyncResult = asyncAction.apply()
            } catch (ex: Exception) {
                asyncResult.completeExceptionally(ex)
            }
            if (asyncResult.isCancelled) {
                asyncResult.exceptionally { ex: Throwable ->
                    logger.error("Task '{}' was cancelled, contextInfo: {}, current retryTimes: {}.",
                            actionName,
                            getContextInfo(contextInfoFunc),
                            currentRetryTimes, ex)
                    executeFailedAction(ex, String.format("Task '%s' was cancelled.", actionName))
                    null
                }
                return
            }
            asyncResult
                    .thenAccept { result: TAsyncResult ->
                        executeSuccessAction(result)
                    }
                    .exceptionally { ex: Throwable ->
                        processTaskException(ex)
                        null
                    }
        }

        private fun executeRetryAction() {
            try {
                if (currentRetryTimes >= maxRetryTimes) {
                    DelayedTask.startDelayedTask(Duration.ofMillis(retryInterval.toLong())) { doRetry() }
                } else {
                    doRetry()
                }
            } catch (ex: Exception) {
                logger.error("Failed to execute the retryAction, actionName:{}, contextInfo:{}", actionName, getContextInfo(contextInfoFunc), ex)
            }
        }

        private fun doRetry() {
            currentRetryTimes++
            execute()
        }

        private fun executeSuccessAction(result: TAsyncResult) {
            try {
                successAction.apply(result)
            } catch (ex: Exception) {
                logger.error("Failed to execute the successAction, actionName:{}, contextInfo:{}", actionName, getContextInfo(contextInfoFunc), ex)
            }
        }

        private fun executeFailedAction(e: Throwable, errorMessage: String?) {
            try {
                failedAction?.apply(e, errorMessage)
            } catch (ex: Exception) {
                logger.error("Failed to execute the failedAction of action:{}, contextInfo:{}", actionName, getContextInfo(contextInfoFunc), ex)
            }
        }

        private fun getContextInfo(func: Func): String? {
            return try {
                func.apply()
            } catch (ex: Exception) {
                logger.error("Failed to execute the getContextInfoFunc.", ex)
                ""
            }
        }

        private fun processTaskException(exception: Throwable) {
            if (exception is IORuntimeException) {
                logger.error("Async task '{}' has io exception, contextInfo:{}, current retryTimes:{}, try to run the async task again.", actionName, getContextInfo(contextInfoFunc), currentRetryTimes, exception)
                executeRetryAction()
            } else if (exception is CompletionException && exception.cause is IORuntimeException) {
                logger.error("Async task '{}' has io exception, contextInfo:{}, current retryTimes:{}, try to run the async task again.", actionName, getContextInfo(contextInfoFunc), currentRetryTimes, exception)
                executeRetryAction()
            } else {
                logger.error("Task '{}' has unknown exception, contextInfo:{}, current retryTimes:{}", actionName, getContextInfo(contextInfoFunc), currentRetryTimes, exception)
                if (retryWhenFailed) {
                    executeRetryAction()
                } else {
                    executeFailedAction(exception, exception.message)
                }
            }
        }

        init {
            this.successAction = successAction
            this.contextInfoFunc = contextInfoFunc
            this.failedAction = failedAction
            this.currentRetryTimes = retryTimes
            this.retryWhenFailed = retryWhenFailed
            this.maxRetryTimes = maxRetryTimes
            this.retryInterval = retryInterval
            this.asyncAction = asyncAction
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy