
io.infinitic.transport.pulsar.PulsarStarter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of infinitic-transport-pulsar Show documentation
Show all versions of infinitic-transport-pulsar Show documentation
Infinitic Orchestration Framework
/**
* "Commons Clause" License Condition v1.0
*
* The Software is provided to you by the Licensor under the License, as defined
* below, subject to the following condition.
*
* Without limiting other conditions in the License, the grant of rights under the
* License will not include, and the License does not grant to you, the right to
* Sell the Software.
*
* For purposes of the foregoing, “Sell” means practicing any or all of the rights
* granted to you under the License to provide to third parties, for a fee or
* other consideration (including without limitation fees for hosting or
* consulting/ support services related to the Software), a product or service
* whose value derives, entirely or substantially, from the functionality of the
* Software. Any license notice or attribution required by the License must also
* include this Commons Clause License Condition notice.
*
* Software: Infinitic
*
* License: MIT License (https://opensource.org/licenses/MIT)
*
* Licensor: infinitic.io
*/
package io.infinitic.transport.pulsar
import io.infinitic.clients.InfiniticClient
import io.infinitic.common.clients.ClientFactory
import io.infinitic.common.clients.ClientStarter
import io.infinitic.common.clients.SendToClient
import io.infinitic.common.clients.messages.ClientEnvelope
import io.infinitic.common.clients.messages.ClientMessage
import io.infinitic.common.data.ClientName
import io.infinitic.common.data.MillisDuration
import io.infinitic.common.messages.Envelope
import io.infinitic.common.messages.Message
import io.infinitic.common.tasks.data.TaskName
import io.infinitic.common.tasks.executors.SendToTaskExecutor
import io.infinitic.common.tasks.executors.SendToTaskExecutorAfter
import io.infinitic.common.tasks.executors.messages.TaskExecutorEnvelope
import io.infinitic.common.tasks.executors.messages.TaskExecutorMessage
import io.infinitic.common.tasks.tags.SendToTaskTag
import io.infinitic.common.tasks.tags.messages.TaskTagEnvelope
import io.infinitic.common.tasks.tags.messages.TaskTagMessage
import io.infinitic.common.tasks.tags.storage.TaskTagStorage
import io.infinitic.common.workers.WorkerRegister
import io.infinitic.common.workers.WorkerStarter
import io.infinitic.common.workflows.data.workflows.WorkflowName
import io.infinitic.common.workflows.engine.SendToWorkflowEngine
import io.infinitic.common.workflows.engine.SendToWorkflowEngineAfter
import io.infinitic.common.workflows.engine.messages.WorkflowEngineEnvelope
import io.infinitic.common.workflows.engine.messages.WorkflowEngineMessage
import io.infinitic.common.workflows.engine.storage.WorkflowStateStorage
import io.infinitic.common.workflows.tags.SendToWorkflowTag
import io.infinitic.common.workflows.tags.messages.WorkflowTagEnvelope
import io.infinitic.common.workflows.tags.messages.WorkflowTagMessage
import io.infinitic.common.workflows.tags.storage.WorkflowTagStorage
import io.infinitic.tasks.executor.TaskExecutor
import io.infinitic.tasks.tag.TaskTagEngine
import io.infinitic.transport.pulsar.topics.ClientTopics
import io.infinitic.transport.pulsar.topics.TaskTopics
import io.infinitic.transport.pulsar.topics.TopicNames
import io.infinitic.transport.pulsar.topics.TopicType
import io.infinitic.transport.pulsar.topics.WorkflowTaskTopics
import io.infinitic.transport.pulsar.topics.WorkflowTopics
import io.infinitic.workflows.engine.WorkflowEngine
import io.infinitic.workflows.tag.WorkflowTagEngine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import mu.KotlinLogging
import org.apache.pulsar.client.api.PulsarClient
class PulsarStarter(
client: PulsarClient,
private val topicNames: TopicNames,
private val workerName: String
) : ClientStarter, WorkerStarter {
private val logger = KotlinLogging.logger {}
private val zero = MillisDuration.ZERO
private val clientName = ClientName(workerName)
private val pulsarProducer = PulsarProducer(client)
private val pulsarConsumer = PulsarConsumer(client)
override fun CoroutineScope.startWorkflowTag(workflowName: WorkflowName, workflowTagStorage: WorkflowTagStorage, concurrency: Int) {
val tagEngine = WorkflowTagEngine(
clientName,
workflowTagStorage,
sendToWorkflowTag,
sendToWorkflowEngine,
sendToClient
)
start(
executor = { message: WorkflowTagMessage -> tagEngine.handle(message) },
topicType = WorkflowTopics.TAG,
concurrency = concurrency,
name = "$workflowName"
)
}
override fun CoroutineScope.startWorkflowEngine(workflowName: WorkflowName, workflowStateStorage: WorkflowStateStorage, concurrency: Int) {
val workflowEngine = WorkflowEngine(
clientName,
workflowStateStorage,
sendToClient,
sendToTaskTag,
sendToTaskExecutor,
sendToWorkflowTaskExecutor(workflowName),
sendToWorkflowTag,
sendToWorkflowEngine,
sendToWorkflowEngineAfter
)
start(
executor = { message: WorkflowEngineMessage -> workflowEngine.handle(message) },
topicType = WorkflowTopics.ENGINE,
concurrency = concurrency,
name = "$workflowName"
)
}
override fun CoroutineScope.startWorkflowDelay(workflowName: WorkflowName, concurrency: Int) {
start(
executor = sendToWorkflowEngine,
topicType = WorkflowTopics.DELAY,
concurrency = concurrency,
name = "$workflowName"
)
}
override fun CoroutineScope.startTaskTag(taskName: TaskName, taskTagStorage: TaskTagStorage, concurrency: Int) {
val tagEngine = TaskTagEngine(
clientName,
taskTagStorage,
sendToClient
)
start(
executor = { message: TaskTagMessage -> tagEngine.handle(message) },
topicType = TaskTopics.TAG,
concurrency = concurrency,
name = "$taskName"
)
}
override fun CoroutineScope.startTaskExecutor(taskName: TaskName, concurrency: Int, workerRegister: WorkerRegister, clientFactory: ClientFactory) {
val taskExecutor = TaskExecutor(
clientName,
workerRegister,
sendToTaskExecutorAfter,
sendToTaskTag,
sendToWorkflowEngine,
sendToClient,
clientFactory
)
start(
executor = { message: TaskExecutorMessage -> taskExecutor.handle(message) },
topicType = TaskTopics.EXECUTOR,
concurrency = concurrency,
name = "$taskName"
)
}
override fun CoroutineScope.startWorkflowTaskExecutor(workflowName: WorkflowName, concurrency: Int, workerRegister: WorkerRegister, clientFactory: ClientFactory) {
val taskExecutor = TaskExecutor(
clientName,
workerRegister,
sendToWorkflowTaskExecutorAfter(workflowName),
{}, // Workflow tasks do not have tags
sendToWorkflowEngine,
sendToClient,
clientFactory
)
start(
executor = { message: TaskExecutorMessage -> taskExecutor.handle(message) },
topicType = WorkflowTaskTopics.EXECUTOR,
concurrency = concurrency,
name = "$workflowName"
)
}
override fun CoroutineScope.startClientResponse(client: InfiniticClient) {
start(
executor = { message: ClientMessage -> client.handle(message) },
topicType = ClientTopics.RESPONSE,
concurrency = 1,
name = client.name
)
}
override val sendToWorkflowTag: SendToWorkflowTag = run {
val topicType = WorkflowTopics.TAG
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: WorkflowTagMessage ->
val topic = topicNames.topic(topicType, message.workflowName)
pulsarProducer.send(
message, zero, topic, producerName, "${message.workflowTag}"
)
}
}
private val sendToTaskTag: SendToTaskTag = run {
val topicType = TaskTopics.TAG
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: TaskTagMessage ->
val topic = topicNames.topic(topicType, message.taskName)
pulsarProducer.send(
message, zero, topic, producerName, "${message.taskTag}",
)
}
}
private val sendToTaskExecutor: SendToTaskExecutor = run {
val topicType = TaskTopics.EXECUTOR
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: TaskExecutorMessage ->
val topic = topicNames.topic(topicType, message.taskName)
pulsarProducer.send(
message, zero, topic, producerName
)
}
}
override val sendToWorkflowEngine: SendToWorkflowEngine = run {
val topicType = WorkflowTopics.ENGINE
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: WorkflowEngineMessage ->
val topic = topicNames.topic(topicType, message.workflowName)
pulsarProducer.send(
message, zero, topic, producerName, "${message.workflowId}"
)
}
}
private val sendToClient: SendToClient = run {
val topicType = ClientTopics.RESPONSE
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: ClientMessage ->
val topic = topicNames.topic(topicType, message.recipientName)
pulsarProducer.send(
message, zero, topic, producerName
)
}
}
private val sendToTaskExecutorAfter: SendToTaskExecutorAfter = run {
val topicType = TaskTopics.EXECUTOR
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: TaskExecutorMessage, after: MillisDuration ->
val topic = topicNames.topic(topicType, message.taskName)
pulsarProducer.send(
message, after, topic, producerName
)
}
}
private fun sendToWorkflowTaskExecutor(workflowName: WorkflowName): SendToTaskExecutor {
val topicType = WorkflowTaskTopics.EXECUTOR
val producerName = topicNames.producerName(workerName, topicType)
val topic = topicNames.topic(topicType, workflowName)
return { message: TaskExecutorMessage ->
pulsarProducer.send(
message, zero, topic, producerName
)
}
}
private fun sendToWorkflowTaskExecutorAfter(workflowName: WorkflowName): SendToTaskExecutorAfter {
val topicType = WorkflowTaskTopics.EXECUTOR
val producerName = topicNames.producerName(workerName, topicType)
val topic = topicNames.topic(topicType, workflowName)
return { message: TaskExecutorMessage, after: MillisDuration ->
pulsarProducer.send(
message, after, topic, producerName
)
}
}
private val sendToWorkflowEngineAfter: SendToWorkflowEngineAfter = run {
val topicType = WorkflowTopics.DELAY
val producerName = topicNames.producerName(workerName, topicType)
return@run { message: WorkflowEngineMessage, after: MillisDuration ->
if (after > 0) {
val topic = topicNames.topic(topicType, message.workflowName)
pulsarProducer.send(
message, after, topic, producerName
)
} else {
sendToWorkflowEngine(message)
}
}
}
internal inline fun > CoroutineScope.start(
crossinline executor: suspend (T) -> Unit,
topicType: TopicType,
concurrency: Int,
name: String
) {
if (isActive) {
with(pulsarConsumer) {
startConsumer(
executor = executor,
topic = topicNames.topic(topicType, name),
subscriptionName = topicType.subscriptionName,
subscriptionType = topicType.subscriptionType,
consumerName = topicNames.consumerName(workerName, topicType),
concurrency = concurrency,
topicDLQ = topicNames.topicDLQ(topicType, name)
)
}
} else {
logger.warn("Coroutine not active, cannot start consumer ${topicNames.consumerName(workerName, topicType)}")
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy