<commit_before>package com.cognifide.gradle.aem.common.instance.check

import com.cognifide.gradle.aem.common.instance.InstanceSync
import com.cognifide.gradle.aem.common.instance.service.osgi.Bundle
import com.cognifide.gradle.common.CommonException
import java.util.concurrent.TimeUnit

class HelpCheck(group: CheckGroup) : DefaultCheck(group) {

    /**
     * After longer inactivity time, try helping instance going back to healthy state.
     */
    val stateTime = aem.obj.long { convention(TimeUnit.MINUTES.toMillis(8)) }

    /**
     * Bundle with these states are considered for forcing start.
     */
    val bundleStartStates = aem.obj.strings {
        convention(listOf(
                Bundle.STATE_RESOLVED,
                Bundle.STATE_INSTALLED
        ))
    }

    /**
     * Repeat bundle starting few times (brute-forcing).
     */
    var bundleStartRetry = common.retry { afterSquaredSecond(3) }

    /**
     * Time to wait after starting bundles.
     */
    val bundleStartDelay = aem.obj.long { convention(TimeUnit.SECONDS.toMillis(3)) }

    override fun check() {
        if (progress.stateTime >= stateTime.get()) {
            progress.stateData.getOrPut(STATE_HELPED) {
                help()
                true
            }
        }
    }

    private fun help() = sync {
        startBundles()
    }

    private fun InstanceSync.startBundles() {
        logger.info("Trying to start OSGi bundles on $instance")
        var startable = listOf<Bundle>()

        try {
            bundleStartRetry.withCountdown<Unit, CommonException>("start bundles on '${instance.name}'") {
                startable = startableBundles()
                if (startable.isNotEmpty()) {
                    startBundles(startable)
                    startable = startableBundles()
                    if (startable.isNotEmpty()) {
                        throw HelpException("Starting bundles to be repeated on $instance!")
                    }
                }
            }
        } catch (e: HelpException) {
            logger.warn("Bundles (${startable.size}) cannot be started automatically on $instance:\n" +
                    startable.joinToString("\n"))
        }
    }

    private fun InstanceSync.startableBundles(): List<Bundle> = osgi.bundles.filter {
        !it.fragment && bundleStartStates.get().contains(it.state)
    }

    private fun InstanceSync.startBundles(bundles: List<Bundle>) {
        common.parallel.poolEach(bundles) { startBundle(it) }
        Thread.sleep(bundleStartDelay.get())
    }

    private fun InstanceSync.startBundle(it: Bundle) = try {
        osgi.startBundle(it.symbolicName)
    } catch (e: CommonException) {
        logger.debug("Cannot start bundle on $instance!", e)
    }

    companion object {
        private const val STATE_HELPED = "helped"
    }
}<commit_msg>Await up helper ignores<commit_after>package com.cognifide.gradle.aem.common.instance.check

import com.cognifide.gradle.aem.common.instance.InstanceSync
import com.cognifide.gradle.aem.common.instance.service.osgi.Bundle
import com.cognifide.gradle.common.CommonException
import java.util.concurrent.TimeUnit

class HelpCheck(group: CheckGroup) : DefaultCheck(group) {

    /**
     * After longer inactivity time, try helping instance going back to healthy state.
     */
    val stateTime = aem.obj.long { convention(TimeUnit.MINUTES.toMillis(8)) }

    /**
     * Bundle with these states are considered for forcing start.
     */
    val bundleStartStates = aem.obj.strings {
        convention(listOf(
                Bundle.STATE_RESOLVED,
                Bundle.STATE_INSTALLED
        ))
    }

    /**
     * Repeat bundle starting few times (brute-forcing).
     */
    var bundleStartRetry = common.retry { afterSquaredSecond(3) }

    /**
     * Time to wait after starting bundles.
     */
    val bundleStartDelay = aem.obj.long { convention(TimeUnit.SECONDS.toMillis(3)) }

    override fun check() {
        if (progress.stateTime >= stateTime.get()) {
            progress.stateData.getOrPut(STATE_HELPED) {
                help()
                true
            }
        }
    }

    private fun help() = sync {
        startBundles()
    }

    private fun InstanceSync.startBundles() {
        logger.info("Trying to start OSGi bundles on $instance")
        var startable = listOf<Bundle>()

        try {
            bundleStartRetry.withCountdown<Unit, CommonException>("start bundles on '${instance.name}'") {
                startable = startableBundles()
                if (startable.isNotEmpty()) {
                    startBundles(startable)
                    startable = startableBundles()
                    if (startable.isNotEmpty()) {
                        throw HelpException("Starting bundles to be repeated on $instance!")
                    }
                }
            }
        } catch (e: HelpException) {
            logger.warn("Bundles (${startable.size}) cannot be started automatically on $instance:\n" +
                    startable.joinToString("\n"))
        }
    }

    private fun ignoredBundles() = group.checks.filterIsInstance<BundlesCheck>()
            .firstOrNull()?.symbolicNamesIgnored?.get()
            ?: listOf<String>()

    private fun InstanceSync.startableBundles(): List<Bundle> = osgi.bundles.asSequence()
            .filter { !ignoredBundles().contains(it.symbolicName) }
            .filter { !it.fragment && bundleStartStates.get().contains(it.state) }
            .toList()

    private fun InstanceSync.startBundles(bundles: List<Bundle>) {
        common.parallel.poolEach(bundles) { startBundle(it) }
        Thread.sleep(bundleStartDelay.get())
    }

    private fun InstanceSync.startBundle(bundle: Bundle) = try {
        osgi.startBundle(bundle.symbolicName)
    } catch (e: CommonException) {
        logger.debug("Cannot start bundle on $instance!", e)
    }

    companion object {
        private const val STATE_HELPED = "helped"
    }
}
{'fraction_non_alphanumeric': 0.10691613765452723, 'fraction_numerical': 0.0010023387905111927, 'mean_word_length': 2.217087587318646, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3405384', 'n_tokens_mistral': 1747, 'n_tokens_neox': 1675, 'n_words': 341}