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

ai.platon.pulsar.protocol.browser.driver.ConcurrentStatefulDriverPool.kt Maven / Gradle / Ivy

The newest version!
package ai.platon.pulsar.protocol.browser.driver

import ai.platon.pulsar.common.getLogger
import ai.platon.pulsar.common.warnInterruptible
import ai.platon.pulsar.skeleton.crawl.fetch.driver.AbstractWebDriver
import ai.platon.pulsar.skeleton.crawl.fetch.driver.WebDriver
import kotlinx.coroutines.runBlocking
import java.util.*
import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.TimeUnit

class ConcurrentStatefulDriverPool(
    private val browserManager: BrowserManager,
    private val capacity: Int
) {
    private val logger = getLogger(this)

    /**
     * Keep standby drivers
     * */
    private val _standbyDrivers = ArrayBlockingQueue(2 * capacity)
    /**
     * Keep working drivers
     * */
    private val _workingDrivers = ConcurrentLinkedQueue()
    /**
     * Keep retired drivers
     * */
    private val _retiredDrivers = ConcurrentLinkedQueue()
    /**
     * Keep closed drivers
     * */
    private val _closedDrivers = ConcurrentLinkedQueue()

    /**
     * Keep standby drivers
     * */
    val standbyDrivers: Queue get() = _standbyDrivers
    /**
     * Keep working drivers
     * */
    val workingDrivers: Queue get() = _workingDrivers
    /**
     * Keep retired drivers
     * */
    val retiredDrivers: Queue get() = _retiredDrivers
    /**
     * Keep closed drivers
     * */
    val closedDrivers: Queue get() = _closedDrivers

    @get:Synchronized
    val activeDriverCount get() = workingDrivers.size + standbyDrivers.size

    @Throws(InterruptedException::class)
    @Synchronized
    fun poll(timeout: Long, unit: TimeUnit): WebDriver? {
        val driver = _standbyDrivers.poll(timeout, unit)
        if (driver is AbstractWebDriver) {
            driver.startWork()
            _workingDrivers.add(driver)
        }
        return driver
    }

    @Synchronized
    fun offer(driver: WebDriver) {
        require(driver is AbstractWebDriver)
        
        if (!driver.isRecyclable) {
            // this driver is not recyclable, it should keep open
            return
        }

        driver.free()
        _workingDrivers.remove(driver)
        _standbyDrivers.offer(driver)
    }

    @Synchronized
    fun close(driver: WebDriver) {
        require(driver is AbstractWebDriver)
        driver.retire()
        _standbyDrivers.remove(driver)
        _workingDrivers.remove(driver)
        _retiredDrivers.remove(driver)
        _closedDrivers.add(driver)

        runCatching { browserManager.closeDriver(driver) }.onFailure { warnInterruptible(this, it) }

        // require(driver.isQuit)
    }

    @Synchronized
    fun retire() {
        val drivers = _standbyDrivers + _workingDrivers
        _standbyDrivers.clear()
        _workingDrivers.clear()
        _retiredDrivers.addAll(drivers)

        drivers.forEach { driver ->
            require(driver is AbstractWebDriver)
            // cancel the driver so the fetch task return immediately
            driver.cancel()
            // retire the driver, so it should not be used to fetch pages anymore
            driver.retire()
            // stop the driver so no more resource it uses
            kotlin.runCatching { runBlocking { driver.stop() } }.onFailure { warnInterruptible(this, it) }
        }
    }

    @Synchronized
    fun cancelAll() {
        _workingDrivers.forEach { (it as? AbstractWebDriver)?.cancel() }
    }

    @Synchronized
    fun clear() {
        standbyDrivers.clear()
        workingDrivers.clear()
        retiredDrivers.clear()
        closedDrivers.clear()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy