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

kdux.tools.BatchEnhancer.kt Maven / Gradle / Ivy

package kdux.tools

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.mattshoe.shoebox.kdux.Enhancer
import org.mattshoe.shoebox.kdux.Store
import kotlin.time.Duration
import kotlin.time.TimeSource

/**
 * An enhancer that batches actions based on a specified time duration. Actions are accumulated
 * in a batch, and when the elapsed time since the start of the batch exceeds the specified
 * `batchDuration`, all actions in the batch are dispatched to the store at once.
 *
 * This enhancer is useful in scenarios where you want to delay processing actions and
 * dispatch them together to minimize state updates or improve performance.
 *
 * Note that batched actions will not be dispatched until the next dispatch call after the
 * [batchDuration] expires.
 *
 * @param batchDuration The duration for which actions are accumulated before being dispatched.
 *                      Once this duration is exceeded, the batch of actions is dispatched at the
 *                      next call to dispatch.
 */
class BatchEnhancer(
    private val batchDuration: Duration
): Enhancer {

    init {
        require(batchDuration > Duration.ZERO) {
            "Batch duration must be greater than zero."
        }
    }

    override fun enhance(store: Store): Store {
        return object : Store {

            private val timeSource = TimeSource.Monotonic
            private val now: TimeSource.Monotonic.ValueTimeMark get() = timeSource.markNow()
            private var batchStart = now
            private val elapsedTime: Duration get() = now.minus(batchStart)
            private val batch = mutableListOf()
            private val batchMutex = Mutex()

            override val state: Flow
                get() = store.state
            override val currentState: State
                get() = store.currentState

            override suspend fun dispatch(action: Action) {
                val actionsToDispatch = mutableListOf()
                batchMutex.withLock {
                    batch.add(action)

                    if (elapsedTime > batchDuration) {
                        actionsToDispatch.addAll(batch)
                        batch.clear()
                        batchStart = now
                    }
                }

                actionsToDispatch.forEach {
                    store.dispatch(it)
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy