Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move PubSub to infrastructure as code #104

Merged
merged 6 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/check_gcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ env:
APP_LOG_LEVEL: ${{ secrets.APP_LOG_LEVEL }}
APP_NETWORK_HTML_LOG_LEVEL: ${{ secrets.APP_NETWORK_HTML_LOG_LEVEL }}
APP_NETWORK_JSON_LOG_LEVEL: ${{ secrets.APP_NETWORK_JSON_LOG_LEVEL }}
APP_PUBLIC_URL: ${{ secrets.APP_PUBLIC_URL }}
SEARCH_PRELOAD_PUBSUB_TOPIC: ${{ secrets.SEARCH_PRELOAD_PUBSUB_TOPIC }}

jobs:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/deploy_gcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ env:
APP_LOG_LEVEL: ${{ secrets.APP_LOG_LEVEL }}
APP_NETWORK_HTML_LOG_LEVEL: ${{ secrets.APP_NETWORK_HTML_LOG_LEVEL }}
APP_NETWORK_JSON_LOG_LEVEL: ${{ secrets.APP_NETWORK_JSON_LOG_LEVEL }}
APP_PUBLIC_URL: ${{ secrets.APP_PUBLIC_URL }}
SEARCH_PRELOAD_PUBSUB_TOPIC: ${{ secrets.SEARCH_PRELOAD_PUBSUB_TOPIC }}

jobs:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The project can be run locally and on the cloud - in this case Google Cloud via
- `Firebase Admin`
- `Service Account User`
- `Service Usage Admin`
- `Pub/Sub Admin`
3. Export a JSON API key for your Service Account and call it `credentials-gcp-infra.json`.
4. [Signup and Install Pulumi](https://www.pulumi.com/docs/clouds/gcp/get-started/begin/#install-pulumi).
5. Create a Pulumi access token and login locally using `pulumi login`.
Expand All @@ -44,7 +45,7 @@ The project can be run locally and on the cloud - in this case Google Cloud via
- `pulumi config set gcp:project GCP_PROJECT_ID`
10. Run `pulumi up` to automatically create the required project infrastructure.
11. Find your new `firebase-adminsdk` Service Account and give it the following additional roles:
- `Pub/Sub Admin`, for managing the PubSub subscriptions
- `Pub/Sub Publisher`, for publishing messages to PubSub topics
12. Export a JSON API key for your `firebase-adminsdk` Service Account and call it `credentials-gcp-app.json` - the app will need it later.
</details>

Expand Down Expand Up @@ -82,7 +83,6 @@ SLACK_MONITORING_URL=YOUR_SLACK_MONITORING_URL
APP_LOG_LEVEL=debug|verbose|error|info
APP_NETWORK_HTML_LOG_LEVEL=all|info|none
APP_NETWORK_JSON_LOG_LEVEL=all|info|none
APP_PUBLIC_URL=YOUR_PUBLIC_APP_URL
SEARCH_PRELOAD_PUBSUB_TOPIC=TOPIC_NAME
```
6. Copy the `credentials-gcp-app.json` Service Account JSON API key to the root of the project.
Expand Down
5 changes: 0 additions & 5 deletions backend/common-kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ buildkonfig {
name = "APP_NETWORK_JSON_LOG_LEVEL",
value = getLocalSecret(rootProject, "APP_NETWORK_JSON_LOG_LEVEL")
)
buildConfigField(
type = com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING,
name = "APP_PUBLIC_URL",
value = getLocalSecret(rootProject, "APP_PUBLIC_URL")
)
buildConfigField(
type = com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING,
name = "SEARCH_PRELOAD_PUBSUB_TOPIC",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ data class AppConfig(
val logLevel: String,
val networkHtmlLogLevel: String,
val networkJsonLogLevel: String,
val publicUrl: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ object CommonKotlinModule : DiModule() {
logLevel = BuildConfig.APP_LOG_LEVEL,
networkHtmlLogLevel = BuildConfig.APP_NETWORK_HTML_LOG_LEVEL,
networkJsonLogLevel = BuildConfig.APP_NETWORK_JSON_LOG_LEVEL,
publicUrl = BuildConfig.APP_PUBLIC_URL.removeSuffix("/"),
)

private fun provideLogger(appConfig: AppConfig): Logger {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,5 @@ import arrow.core.Either
import com.gchristov.thecodinglove.commonservicedata.Handler

interface PubSubHandler : Handler {

fun pubSubConfig(): PubSubConfig

suspend fun handlePubSubRequest(request: PubSubRequest): Either<Throwable, Unit>

data class PubSubConfig(val topic: String)
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.gchristov.thecodinglove.commonservice

import co.touchlab.kermit.Logger
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import com.gchristov.thecodinglove.commonkotlin.di.DiModule
import com.gchristov.thecodinglove.commonservicedata.http.HttpService
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubPublisher
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubSubscription
import com.gchristov.thecodinglove.commonkotlin.AppConfig
import com.gchristov.thecodinglove.commonkotlin.di.DiModule
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import org.kodein.di.DI
import org.kodein.di.bindProvider
import org.kodein.di.bindSingleton
Expand All @@ -21,12 +19,6 @@ object CommonServiceModule : DiModule() {
bindProvider { provideHttpService(log = instance()) }
bindSingleton { providePubSubDecoder(jsonSerializer = instance()) }
bindSingleton { providePubSubPublisher() }
bindProvider {
providePubSubSubscription(
log = instance(),
appConfig = instance(),
)
}
}
}
}
Expand All @@ -35,9 +27,4 @@ expect fun provideHttpService(log: Logger): HttpService

expect fun providePubSubPublisher(): PubSubPublisher

expect fun providePubSubSubscription(
log: Logger,
appConfig: AppConfig,
): PubSubSubscription

expect fun providePubSubDecoder(jsonSerializer: JsonSerializer.Default): PubSubDecoder
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,26 @@ package com.gchristov.thecodinglove.commonservice.pubsub
import arrow.core.Either
import arrow.core.flatMap
import co.touchlab.kermit.Logger
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import com.gchristov.thecodinglove.commonservice.BaseHttpHandler
import com.gchristov.thecodinglove.commonservicedata.http.HttpRequest
import com.gchristov.thecodinglove.commonservicedata.http.HttpResponse
import com.gchristov.thecodinglove.commonservicedata.http.sendEmpty
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubHandler
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubSubscription
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import kotlinx.coroutines.CoroutineDispatcher
import kotlin.io.encoding.ExperimentalEncodingApi

abstract class BasePubSubHandler(
dispatcher: CoroutineDispatcher,
jsonSerializer: JsonSerializer,
log: Logger,
private val pubSubSubscription: PubSubSubscription,
private val pubSubDecoder: PubSubDecoder,
) : BaseHttpHandler(
dispatcher,
jsonSerializer = jsonSerializer,
log = log,
), PubSubHandler {
override suspend fun initialise(): Either<Throwable, Unit> {
val pubSubConfig = pubSubConfig()
val httpConfig = httpConfig()
return super.initialise().flatMap {
pubSubSubscription.initialise(
topic = pubSubConfig.topic,
httpPath = httpConfig.path,
)
}
}

/**
* Decodes and exposes the PubSub message to subclasses. A success response is always sent to the [response] after
* the PubSub message has been handled.,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
package com.gchristov.thecodinglove.commonservice

import co.touchlab.kermit.Logger
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import com.gchristov.thecodinglove.commonservice.http.ExpressHttpService
import com.gchristov.thecodinglove.commonservice.pubsub.GoogleCloudPubSubDecoder
import com.gchristov.thecodinglove.commonservice.pubsub.GoogleCloudPubSubExternals
import com.gchristov.thecodinglove.commonservice.pubsub.GoogleCloudPubSubPublisher
import com.gchristov.thecodinglove.commonservice.pubsub.GoogleCloudPubSubSubscription
import com.gchristov.thecodinglove.commonservicedata.http.HttpService
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubPublisher
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubSubscription
import com.gchristov.thecodinglove.commonkotlin.AppConfig
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer

actual fun provideHttpService(log: Logger): HttpService = ExpressHttpService(log)

actual fun providePubSubPublisher(): PubSubPublisher = GoogleCloudPubSubPublisher(pubSub = PubSub)

actual fun providePubSubSubscription(
log: Logger,
appConfig: AppConfig,
): PubSubSubscription = GoogleCloudPubSubSubscription(
log = log,
pubSub = PubSub,
appConfig = appConfig,
)

actual fun providePubSubDecoder(
jsonSerializer: JsonSerializer.Default
): PubSubDecoder = GoogleCloudPubSubDecoder(jsonSerializer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,6 @@ internal external object GoogleCloudPubSubExternals {
}

class Topic {
fun exists(): Promise<Array<Boolean>>

fun create(): Promise<Topic>

fun subscription(name: String): Subscription

fun publish(message: Buffer): Promise<String>
}

class Subscription {
fun exists(): Promise<Array<Boolean>>

fun create(options: kotlin.js.Json?): Promise<Subscription>
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ import com.gchristov.thecodinglove.commonkotlin.error
import com.gchristov.thecodinglove.commonservice.pubsub.BasePubSubHandler
import com.gchristov.thecodinglove.commonservicedata.http.HttpHandler
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubHandler
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubRequest
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubSubscription
import com.gchristov.thecodinglove.searchdata.domain.PreloadSearchPubSubMessage
import com.gchristov.thecodinglove.searchdata.domain.SearchConfig
import com.gchristov.thecodinglove.searchdata.usecase.PreloadSearchResultUseCase
import io.ktor.http.*
import kotlinx.coroutines.CoroutineDispatcher
Expand All @@ -24,14 +21,11 @@ class PreloadSearchPubSubHandler(
private val jsonSerializer: JsonSerializer,
private val log: Logger,
private val preloadSearchResultUseCase: PreloadSearchResultUseCase,
pubSubSubscription: PubSubSubscription,
pubSubDecoder: PubSubDecoder,
private val searchConfig: SearchConfig,
) : BasePubSubHandler(
dispatcher = dispatcher,
jsonSerializer = jsonSerializer,
log = log,
pubSubSubscription = pubSubSubscription,
pubSubDecoder = pubSubDecoder,
) {
private val tag = this::class.simpleName
Expand All @@ -42,10 +36,6 @@ class PreloadSearchPubSubHandler(
contentType = ContentType.Application.Json,
)

override fun pubSubConfig() = PubSubHandler.PubSubConfig(
topic = searchConfig.preloadPubSubTopic,
)

override suspend fun handlePubSubRequest(request: PubSubRequest): Either<Throwable, Unit> =
request.decodeBodyFromJson(
jsonSerializer = jsonSerializer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package com.gchristov.thecodinglove.search

import co.touchlab.kermit.Logger
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubSubscription
import com.gchristov.thecodinglove.commonkotlin.di.DiModule
import com.gchristov.thecodinglove.commonkotlin.JsonSerializer
import com.gchristov.thecodinglove.searchdata.domain.SearchConfig
import com.gchristov.thecodinglove.commonkotlin.di.DiModule
import com.gchristov.thecodinglove.commonservicedata.pubsub.PubSubDecoder
import com.gchristov.thecodinglove.searchdata.usecase.PreloadSearchResultUseCase
import com.gchristov.thecodinglove.searchdata.usecase.SearchUseCase
import kotlinx.coroutines.Dispatchers
Expand All @@ -30,9 +28,7 @@ object SearchModule : DiModule() {
jsonSerializer = instance(),
log = instance(),
preloadSearchResultUseCase = instance(),
pubSubSubscription = instance(),
pubSubSubDecoder = instance(),
searchConfig = instance(),
)
}
}
Expand All @@ -53,16 +49,12 @@ object SearchModule : DiModule() {
jsonSerializer: JsonSerializer.Default,
log: Logger,
preloadSearchResultUseCase: PreloadSearchResultUseCase,
pubSubSubscription: PubSubSubscription,
pubSubSubDecoder: PubSubDecoder,
searchConfig: SearchConfig,
): PreloadSearchPubSubHandler = PreloadSearchPubSubHandler(
dispatcher = Dispatchers.Default,
jsonSerializer = jsonSerializer,
log = log,
preloadSearchResultUseCase = preloadSearchResultUseCase,
pubSubSubscription = pubSubSubscription,
pubSubDecoder = pubSubSubDecoder,
searchConfig = searchConfig,
)
}
Loading