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

io.infinitic.pulsar.PulsarInfiniticProducerAsync.kt Maven / Gradle / Ivy

/**
 * "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.pulsar

import io.infinitic.common.data.MillisDuration
import io.infinitic.common.messages.Message
import io.infinitic.common.transport.ClientTopic
import io.infinitic.common.transport.InfiniticProducerAsync
import io.infinitic.common.transport.NamingTopic
import io.infinitic.common.transport.Topic
import io.infinitic.pulsar.producers.Producer
import io.infinitic.pulsar.resources.PulsarResources
import io.infinitic.pulsar.resources.envelope
import io.infinitic.pulsar.resources.initWhenProducing
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.apache.pulsar.client.api.PulsarClientException.AlreadyClosedException
import org.apache.pulsar.client.api.PulsarClientException.TopicDoesNotExistException
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException

class PulsarInfiniticProducerAsync(
  private val producer: Producer,
  private val pulsarResources: PulsarResources
) : InfiniticProducerAsync {

  private var suggestedName: String? = null

  // If [suggestedName] is provided, we check that no other is connected with it
  // If [suggestedName] is not provided, Pulsar will provide a unique name
  private val uniqueName: String by lazy {
    runBlocking(Dispatchers.IO) {
      val namingTopic = with(pulsarResources) { NamingTopic.forEntity(null, true) }
      // Get unique name
      producer.getUniqueName(namingTopic, suggestedName).getOrThrow()
    }
  }

  // (if set, must be done before sending the first message)
  override var producerName: String
    get() = uniqueName
    set(value) {
      suggestedName = value
    }

  override suspend fun  internalSendToAsync(
    message: T,
    topic: Topic,
    after: MillisDuration
  ): CompletableFuture {
    val topicFullName =
        with(pulsarResources) { topic.forEntity(message.entity(), topic.initWhenProducing) }

    return producer.sendAsync(
        topic.envelope(message),
        after,
        topicFullName,
        producerName,
        key = message.key(),
    ).exceptionally { throwable ->
      if (topic.canIgnore(throwable)) Unit
      else throw throwable
    }
  }

  private fun Topic<*>.canIgnore(throwable: Throwable): Boolean = when (this) {
    // If response topic does not exist, it means the client closed
    // If producer is already closed, it means that the topics existed, was used, but does not exist anymore
    // in those cases, we are ok not to send this message
    is ClientTopic -> (throwable is TopicDoesNotExistException || (throwable is CompletionException && throwable.cause is AlreadyClosedException))
    else -> false
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy