From b98ef922c02aa10a8514f2a827e17b56e7a2d74a Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Thu, 31 Aug 2017 16:24:44 -0700 Subject: Autocreate pubsub topics on publisher creation --- src/main/scala/xyz/driver/core/pubsub.scala | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/scala/xyz/driver/core/pubsub.scala b/src/main/scala/xyz/driver/core/pubsub.scala index e7e5d4a..d8e64e7 100644 --- a/src/main/scala/xyz/driver/core/pubsub.scala +++ b/src/main/scala/xyz/driver/core/pubsub.scala @@ -4,7 +4,7 @@ import akka.http.scaladsl.marshalling._ import akka.http.scaladsl.unmarshalling.{Unmarshal, Unmarshaller} import akka.stream.Materializer import com.google.api.core.{ApiFutureCallback, ApiFutures} -import com.google.cloud.pubsub.spi.v1.{AckReplyConsumer, MessageReceiver, Publisher, Subscriber} +import com.google.cloud.pubsub.spi.v1._ import com.google.protobuf.ByteString import com.google.pubsub.v1.{PubsubMessage, SubscriptionName, TopicName} import com.typesafe.scalalogging.Logger @@ -21,14 +21,25 @@ object pubsub { def publish(message: Message): Future[Result] } - class GooglePubsubPublisher[Message](projectId: String, topicName: String, log: Logger)( + class GooglePubsubPublisher[Message](projectId: String, topic: String, log: Logger, autoCreate: Boolean = true)( implicit messageMarshaller: Marshaller[Message, String], ex: ExecutionContext ) extends PubsubPublisher[Message] { type Result = Id[PubsubMessage] - private val publisher = Publisher.defaultBuilder(TopicName.create(projectId, topicName)).build() + private val topicName = TopicName.create(projectId, topic) + + private val publisher = { + if (autoCreate) { + val adminClient = TopicAdminClient.create() + val topicExists = Try(adminClient.getTopic(topicName)).isSuccess + if (!topicExists) { + adminClient.createTopic(topicName) + } + } + Publisher.defaultBuilder(topicName).build() + } override def publish(message: Message): Future[Id[PubsubMessage]] = { @@ -44,12 +55,12 @@ object pubsub { messageIdFuture, new ApiFutureCallback[String]() { override def onSuccess(messageId: String): Unit = { - log.info(s"Published a message with topic $topicName, message id $messageId: $messageString") + log.info(s"Published a message with topic $topic, message id $messageId: $messageString") promise.complete(Try(Id[PubsubMessage](messageId))) } override def onFailure(t: Throwable): Unit = { - log.warn(s"Failed to publish a message with topic $topicName: $message", t) + log.warn(s"Failed to publish a message with topic $topic: $message", t) promise.complete(Failure(t)) } } -- cgit v1.2.3 From c09fc3b87e4cf99c57cb393098b7dbd729688442 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Thu, 31 Aug 2017 18:48:16 -0700 Subject: Proposed solution for autocreating subscriptions --- src/main/scala/xyz/driver/core/pubsub.scala | 35 ++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/scala/xyz/driver/core/pubsub.scala b/src/main/scala/xyz/driver/core/pubsub.scala index d8e64e7..fcd096d 100644 --- a/src/main/scala/xyz/driver/core/pubsub.scala +++ b/src/main/scala/xyz/driver/core/pubsub.scala @@ -6,7 +6,7 @@ import akka.stream.Materializer import com.google.api.core.{ApiFutureCallback, ApiFutures} import com.google.cloud.pubsub.spi.v1._ import com.google.protobuf.ByteString -import com.google.pubsub.v1.{PubsubMessage, SubscriptionName, TopicName} +import com.google.pubsub.v1.{PubsubMessage, PushConfig, SubscriptionName, TopicName} import com.typesafe.scalalogging.Logger import scala.concurrent.{ExecutionContext, Future, Promise} @@ -90,12 +90,13 @@ object pubsub { def stopListening(): Unit } - class GooglePubsubSubscriber[Message](projectId: String, - subscriptionId: String, - receiver: Message => Future[Unit], - log: Logger)(implicit messageMarshaller: Unmarshaller[String, Message], - mat: Materializer, - ex: ExecutionContext) + class GooglePubsubSubscriber[Message]( + projectId: String, + subscriptionId: String, + receiver: Message => Future[Unit], + log: Logger, + autoCreateSettings: Option[GooglePubsubSubscriber.SubscriptionSettings] = None + )(implicit messageMarshaller: Unmarshaller[String, Message], mat: Materializer, ex: ExecutionContext) extends PubsubSubscriber { private val subscriptionName = SubscriptionName.create(projectId, subscriptionId) @@ -110,7 +111,21 @@ object pubsub { } } - private val subscriber = Subscriber.defaultBuilder(subscriptionName, messageReceiver).build() + private val subscriber = { + autoCreateSettings.foreach { subscriptionSettings => + val adminClient = SubscriptionAdminClient.create() + val subscriptionExists = Try(adminClient.getSubscription(subscriptionName)).isSuccess + if (!subscriptionExists) { + val topicName = TopicName.create(projectId, subscriptionSettings.topic) + adminClient.createSubscription(subscriptionName, + topicName, + subscriptionSettings.pushConfig, + subscriptionSettings.ackDeadlineSeconds) + } + } + + Subscriber.defaultBuilder(subscriptionName, messageReceiver).build() + } subscriber.startAsync() @@ -119,6 +134,10 @@ object pubsub { } } + object GooglePubsubSubscriber { + final case class SubscriptionSettings(topic: String, pushConfig: PushConfig, ackDeadlineSeconds: Int) + } + class FakePubsubSubscriber extends PubsubSubscriber { def stopListening(): Unit = () } -- cgit v1.2.3