From 44db99895de6b73d96958586a621ddaa707add99 Mon Sep 17 00:00:00 2001 From: Stratos Pavlakis Date: Fri, 23 Aug 2024 10:50:17 +0300 Subject: [PATCH 1/2] feat: Allow specifying thread priority Although not widely recommended as a practice due to differences between platforms since Java uses native Threads, I believe it is worth testing out its impact on web applications where we clearly want web requests (served by acceptor threads and request processing threads) to not be "blocked" by background jobs. --- README.md | 6 ++++++ .../outbox/TransactionalOutboxBuilder.kt | 12 +++++++++++- .../FixedThreadPoolExecutorServiceFactory.kt | 4 +++- .../integration/TransactionalOutboxImplSpec.groovy | 2 +- .../FixedThreadPoolExecutorServiceFactorySpec.groovy | 4 +++- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 269de2c..b9e6b25 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,12 @@ class OutboxConfiguration( return TransactionalOutboxBuilder .make(clock) .withHandlers(outboxHandlers) + // Ideally you want your thread pool < db connection pool size or similar + .withThreadPoolSize(5) + // Override the default Thread priority with caution + // If you are facing performance issues, you should + // adjust the thread pool size first. + // .withThreadPriority(Thread.NORM_PRIORITY) .withMonitorLocksProvider(monitorLocksProvider) .withCleanupLocksProvider(cleanupLocksProvider) .withStore(outboxStore) diff --git a/core/src/main/kotlin/io/github/bluegroundltd/outbox/TransactionalOutboxBuilder.kt b/core/src/main/kotlin/io/github/bluegroundltd/outbox/TransactionalOutboxBuilder.kt index 742bbc2..c77b3d3 100644 --- a/core/src/main/kotlin/io/github/bluegroundltd/outbox/TransactionalOutboxBuilder.kt +++ b/core/src/main/kotlin/io/github/bluegroundltd/outbox/TransactionalOutboxBuilder.kt @@ -36,6 +36,7 @@ class TransactionalOutboxBuilder( BuildStep { private val handlers: MutableMap = mutableMapOf() private var threadPoolSize: Int? = null + private var threadPriority: Int? = null private var threadPoolTimeOut: Duration = DEFAULT_THREAD_POOL_TIMEOUT private var decorators: MutableList = mutableListOf() private lateinit var monitorLocksProvider: OutboxLocksProvider @@ -132,6 +133,14 @@ class TransactionalOutboxBuilder( return this } + /** + * Sets the priority for the threads in the thread pool. + */ + override fun withThreadPriority(threadPriority: Int): BuildStep { + this.threadPriority = threadPriority + return this + } + /** * Sets the thread pool timeout upon shutdown for the outbox. */ @@ -156,7 +165,7 @@ class TransactionalOutboxBuilder( * Builds the outbox. */ override fun build(): TransactionalOutbox { - val executorServiceFactory = FixedThreadPoolExecutorServiceFactory(threadPoolSize) + val executorServiceFactory = FixedThreadPoolExecutorServiceFactory(threadPoolSize, threadPriority) val outboxItemFactory = OutboxItemFactory(clock, handlers.toMap(), rerunAfterDuration) return TransactionalOutboxImpl( @@ -198,6 +207,7 @@ interface InstantOutboxPublisherStep { interface BuildStep { fun withThreadPoolSize(threadPoolSize: Int): BuildStep + fun withThreadPriority(threadPriority: Int): BuildStep fun withThreadPoolTimeOut(threadPoolTimeOut: Duration): BuildStep fun addProcessorDecorator(decorator: OutboxItemProcessorDecorator): BuildStep fun build(): TransactionalOutbox diff --git a/core/src/main/kotlin/io/github/bluegroundltd/outbox/executor/FixedThreadPoolExecutorServiceFactory.kt b/core/src/main/kotlin/io/github/bluegroundltd/outbox/executor/FixedThreadPoolExecutorServiceFactory.kt index d87b609..99ebbd8 100644 --- a/core/src/main/kotlin/io/github/bluegroundltd/outbox/executor/FixedThreadPoolExecutorServiceFactory.kt +++ b/core/src/main/kotlin/io/github/bluegroundltd/outbox/executor/FixedThreadPoolExecutorServiceFactory.kt @@ -11,9 +11,11 @@ import java.util.concurrent.Executors */ internal class FixedThreadPoolExecutorServiceFactory( threadPoolSize: Int? = null, + threadPriority: Int? = null, private val threadNameFormat: String = DEFAULT_THREAD_NAME_FORMAT ) { private val threadPoolSize = threadPoolSize ?: DEFAULT_THREAD_POOL_SIZE + private val threadPriority = threadPriority ?: Thread.NORM_PRIORITY companion object { private const val DEFAULT_THREAD_POOL_SIZE = 10 @@ -25,7 +27,7 @@ internal class FixedThreadPoolExecutorServiceFactory( logger.debug("Creating fixed thread pool with size: $threadPoolSize and name format \"$threadNameFormat\"") return Executors.newFixedThreadPool( threadPoolSize, - ThreadFactoryBuilder().setNameFormat(threadNameFormat).build() + ThreadFactoryBuilder().setNameFormat(threadNameFormat).setPriority(threadPriority).build() ) } } diff --git a/core/src/test/groovy/io/github/bluegroundltd/outbox/integration/TransactionalOutboxImplSpec.groovy b/core/src/test/groovy/io/github/bluegroundltd/outbox/integration/TransactionalOutboxImplSpec.groovy index 82f5df5..070ee3a 100644 --- a/core/src/test/groovy/io/github/bluegroundltd/outbox/integration/TransactionalOutboxImplSpec.groovy +++ b/core/src/test/groovy/io/github/bluegroundltd/outbox/integration/TransactionalOutboxImplSpec.groovy @@ -60,7 +60,7 @@ class TransactionalOutboxImplSpec extends Specification { instantOutboxPublisher, outboxItemFactory, DURATION_ONE_HOUR, - new FixedThreadPoolExecutorServiceFactory(1, "").make(), + new FixedThreadPoolExecutorServiceFactory(1, null, "").make(), [], DURATION_ONE_NANO, processingHostComposer diff --git a/core/src/test/groovy/io/github/bluegroundltd/outbox/unit/executor/FixedThreadPoolExecutorServiceFactorySpec.groovy b/core/src/test/groovy/io/github/bluegroundltd/outbox/unit/executor/FixedThreadPoolExecutorServiceFactorySpec.groovy index 25f3e6b..14696fe 100644 --- a/core/src/test/groovy/io/github/bluegroundltd/outbox/unit/executor/FixedThreadPoolExecutorServiceFactorySpec.groovy +++ b/core/src/test/groovy/io/github/bluegroundltd/outbox/unit/executor/FixedThreadPoolExecutorServiceFactorySpec.groovy @@ -27,9 +27,10 @@ class FixedThreadPoolExecutorServiceFactorySpec extends UnitTestSpecification { def "Should create a FixedThreadPool ExecutorService with custom configuration"() { given: def expectedThreadPoolSize = 5 + def expectedThreadPriority = Thread.MIN_PRIORITY when: - def factory = new FixedThreadPoolExecutorServiceFactory(5, "") + def factory = new FixedThreadPoolExecutorServiceFactory(5, Thread.MIN_PRIORITY, "") then: def executorService = factory.make() @@ -43,5 +44,6 @@ class FixedThreadPoolExecutorServiceFactorySpec extends UnitTestSpecification { and: threadPoolExecutorService.getCorePoolSize() == expectedThreadPoolSize threadPoolExecutorService.getMaximumPoolSize() == expectedThreadPoolSize + threadPoolExecutorService.getThreadFactory().newThread({}).getPriority() == expectedThreadPriority } } From 04e4da34e53ee1651d1a3686dff74957701a45a5 Mon Sep 17 00:00:00 2001 From: Chris Aslanoglou Date: Fri, 23 Aug 2024 11:30:21 +0300 Subject: [PATCH 2/2] chore: bump core lib version to 2.1.0 [no-jira] --- README.md | 2 +- core/gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b9e6b25..b167b50 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Transactional Outbox is published on `mavenCentral`. In order to use it just add ```gradle -implementation("io.github.bluegroundltd:transactional-outbox-core:2.0.4") +implementation("io.github.bluegroundltd:transactional-outbox-core:2.1.0") ``` diff --git a/core/gradle.properties b/core/gradle.properties index 3ba3a77..4972a8e 100644 --- a/core/gradle.properties +++ b/core/gradle.properties @@ -1,6 +1,6 @@ GROUP=io.github.bluegroundltd POM_ARTIFACT_ID=transactional-outbox-core -VERSION_NAME=2.0.4 +VERSION_NAME=2.1.0 POM_NAME=Transactional Outbox Core POM_DESCRIPTION=Easily implement the transactional outbox pattern in your JVM application