Skip to content

Commit c21fc32

Browse files
[TH2-5178] implemented gRPC backpressure for the Execute method (#21)
* Updated libraries
1 parent d2a057d commit c21fc32

File tree

13 files changed

+291
-67
lines changed

13 files changed

+291
-67
lines changed

.github/workflows/build-dev-release.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,4 @@ jobs:
165165
needs: [ app-version, publish-docker, build-and-publish-core-java ]
166166
uses: th2-net/.github/.github/workflows/compaund-git-tag-push.yml@main
167167
with:
168-
runsOn: ${{ inputs.runsOn }}
169168
tagName: ${{ needs.app-version.outputs.version }}-dev

.github/workflows/build-release.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,4 @@ jobs:
124124
needs: [ app-version, publish-docker, build-and-publish-core-java ]
125125
uses: th2-net/.github/.github/workflows/compaund-git-tag-push.yml@main
126126
with:
127-
runsOn: ${{ inputs.runsOn }}
128127
tagName: ${{ needs.app-version.outputs.version }}

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# th2-read-db 0.8.0
1+
# th2-read-db 0.9.0
22

33
The read-db is a component for extracting data from databases using JDBC technology. If database has JDBC driver the read can work with the database
44

@@ -339,10 +339,25 @@ spec:
339339

340340
## Changes
341341

342+
### 0.9.0
343+
344+
+ implemented gRPC backpressure for the `Execute` method
345+
+ updated jdbc:
346+
+ mysql-connector-j:`8.3.0`
347+
+ ojdbc11:`23.3.0.23.09`
348+
+ postgresql:`42.7.3`
349+
+ updated:
350+
+ common:`5.10.0-dev`
351+
+ grpc-common:`4.4.0-dev`
352+
+ common-utils:`2.2.2-dev`
353+
+ common-utils:`2.2.2-dev`
354+
342355
### 0.8.0
343356

344357
+ implemented the `Load` gRPC method.
345358
+ fixed the catching java Error such as OutOfMemoryError problem
359+
+ updated bom:`4.6.0`
360+
346361

347362
### 0.7.0
348363

app/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ dependencies {
1212
implementation(project(":read-db-core"))
1313

1414
//region Drivers
15-
runtimeOnly("org.postgresql:postgresql:42.6.0") {
15+
runtimeOnly("org.postgresql:postgresql:42.7.3") {
1616
because("prostresql support")
1717
}
18-
runtimeOnly("com.mysql:mysql-connector-j:8.1.0") {
18+
runtimeOnly("com.mysql:mysql-connector-j:8.3.0") {
1919
because("mysql support")
2020
}
21-
runtimeOnly("com.oracle.database.jdbc:ojdbc11:23.2.0.0") {
21+
runtimeOnly("com.oracle.database.jdbc:ojdbc11:23.3.0.23.09") {
2222
because("oracle support")
2323
}
2424
runtimeOnly("com.microsoft.sqlserver:mssql-jdbc:12.4.0.jre11") {

app/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
kotlin.code.style=official
2-
release_version=0.8.0
2+
release_version=0.9.0
33
description=read-db component for extracting data from databases using JDBC technology

core/build.gradle.kts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ configurations.all {
1818
dependencies {
1919
implementation(project(":grpc-read-db"))
2020

21-
implementation("com.exactpro.th2:common:5.7.1-dev")
22-
implementation("com.exactpro.th2:common-utils:2.2.0-dev")
21+
implementation("com.exactpro.th2:common:5.10.0-dev")
22+
implementation("com.exactpro.th2:common-utils:2.2.2-dev")
2323
implementation("com.exactpro.th2:lw-data-provider-utils:0.0.1-dev")
2424

2525
implementation("org.slf4j:slf4j-api")
@@ -28,7 +28,7 @@ dependencies {
2828
because("connection pool")
2929
}
3030
implementation("org.apache.commons:commons-text")
31-
implementation("com.opencsv:opencsv:5.8") {
31+
implementation("com.opencsv:opencsv:5.9") {
3232
because("publishes raw messages in csv format")
3333
}
3434

@@ -42,7 +42,7 @@ dependencies {
4242
testImplementation("org.mockito.kotlin:mockito-kotlin:5.1.0")
4343
testImplementation("io.strikt:strikt-core:0.34.1")
4444

45-
testImplementation(platform("org.testcontainers:testcontainers-bom:1.19.0"))
45+
testImplementation(platform("org.testcontainers:testcontainers-bom:1.19.7"))
4646
testImplementation("org.testcontainers:testcontainers")
4747
testImplementation("org.testcontainers:mysql")
4848
testImplementation("org.testcontainers:oracle-xe")
@@ -51,10 +51,10 @@ dependencies {
5151

5252
testImplementation("com.exactpro.th2:junit-jupiter-integration:0.0.1")
5353

54-
testRuntimeOnly("com.mysql:mysql-connector-j:8.1.0") {
54+
testRuntimeOnly("com.mysql:mysql-connector-j:8.3.0") {
5555
because("mysql support")
5656
}
57-
testRuntimeOnly("com.oracle.database.jdbc:ojdbc11:23.2.0.0") {
57+
testRuntimeOnly("com.oracle.database.jdbc:ojdbc11:23.3.0.23.09") {
5858
because("oracle support")
5959
}
6060
}

core/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
kotlin.code.style=official
2-
release_version=0.8.0
2+
release_version=0.9.0
33
description=core part of read db to create an application with required JDBC drivers in the classpath

core/src/main/kotlin/com/exactpro/th2/read/db/app/DataBaseReader.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class DataBaseReader(
157157
LOGGER.info { "Reader closed" }
158158
}
159159

160-
private fun TableRow.transferTo(sourceId: DataSourceId, vararg listeners: RowListener) {
160+
private suspend fun TableRow.transferTo(sourceId: DataSourceId, vararg listeners: RowListener) {
161161
listeners.forEach { listener ->
162162
runCatchingException { listener.onRow(sourceId, this) }.onFailure {
163163
LOGGER.error(it) { "error during row processing by listener ${listener::class}" }

core/src/main/kotlin/com/exactpro/th2/read/db/core/ResultListener.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 Exactpro (Exactpro Systems Limited)
2+
* Copyright 2022-2024 Exactpro (Exactpro Systems Limited)
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,5 +22,5 @@ interface ResultListener : RowListener {
2222
}
2323

2424
fun interface RowListener {
25-
fun onRow(sourceId: DataSourceId, row: TableRow)
25+
suspend fun onRow(sourceId: DataSourceId, row: TableRow)
2626
}

core/src/main/kotlin/com/exactpro/th2/read/db/impl/grpc/DataBaseReaderGrpcServer.kt

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ import com.exactpro.th2.read.db.impl.grpc.util.toModel
4444
import com.google.protobuf.Empty
4545
import com.google.protobuf.Message
4646
import io.grpc.Status
47+
import io.grpc.StatusRuntimeException
48+
import io.grpc.stub.ServerCallStreamObserver
4749
import io.grpc.stub.StreamObserver
50+
import kotlinx.coroutines.channels.Channel
51+
import kotlinx.coroutines.channels.ClosedReceiveChannelException
4852
import mu.KotlinLogging
4953
import java.time.Instant
5054
import java.util.concurrent.TimeUnit
@@ -58,8 +62,8 @@ class DataBaseReaderGrpcServer(
5862
private val onEvent: OnEvent,
5963
) : ReadDbGrpc.ReadDbImplBase() {
6064
override fun execute(request: QueryRequest, responseObserver: StreamObserver<QueryResponse>) {
61-
execute("execute", request, responseObserver) { event, parentEventId, _ ->
62-
GrpcExecuteListener(responseObserver, event) {
65+
execute("execute", request, responseObserver) { event, parentEventId, executionId ->
66+
GrpcExecuteListener(responseObserver, executionId, event) {
6367
onEvent.accept(it, parentEventId)
6468
}
6569
}
@@ -155,8 +159,8 @@ class DataBaseReaderGrpcServer(
155159
event.bodyData(executeQueryRequest.toBody(executionId))
156160
app.executeQuery(
157161
executeQueryRequest,
158-
createListener(event, parentEventId, executionId),
159-
) { row ->
162+
createListener(event, parentEventId, executionId)
163+
) { row ->
160164
row.copy(associatedMessageType = associatedMessageType, executionId = executionId)
161165
}
162166
} catch (ex: Exception) {
@@ -168,31 +172,64 @@ class DataBaseReaderGrpcServer(
168172
}
169173

170174
private class GrpcExecuteListener(
171-
private val observer: StreamObserver<QueryResponse>,
175+
streamObserver: StreamObserver<QueryResponse>,
176+
private val executionId: Long,
172177
private val event: Event,
173178
private val onEvent: (Event) -> Unit,
174179
) : ResultListener {
175-
override fun onRow(sourceId: DataSourceId, row: TableRow) {
176-
requireNotNull(row.executionId) {
177-
"'Execution id' is null for row: $row"
180+
private val channel = Channel<Unit>(1)
181+
private val observer = streamObserver as ServerCallStreamObserver<QueryResponse>
182+
183+
init {
184+
observer.setOnReadyHandler {
185+
channel.trySend(Unit)
186+
}
187+
observer.setOnCancelHandler {
188+
LOGGER.warn { "gRPC request is canceled for '$executionId' execution" }
189+
channel.close()
190+
}
191+
}
192+
193+
override suspend fun onRow(sourceId: DataSourceId, row: TableRow) {
194+
check(executionId == row.executionId) {
195+
"'Execution id' isn't equal to '$executionId', row: $row"
196+
}
197+
try {
198+
if (observer.isCancelled) {
199+
return
200+
}
201+
if (!observer.isReady) {
202+
channel.receive()
203+
}
204+
205+
observer.onNext(
206+
QueryResponse.newBuilder()
207+
.putRows(row)
208+
.setExecutionId(row.executionId)
209+
.build()
210+
)
211+
} catch (e: RuntimeException) {
212+
if (e is ClosedReceiveChannelException || e is StatusRuntimeException) {
213+
LOGGER.error(e) { "Couldn't send next gRPC message by gRPC connection problem for '$executionId' execution" }
214+
} else {
215+
throw e
216+
}
178217
}
179-
observer.onNext(
180-
QueryResponse.newBuilder()
181-
.putRows(row)
182-
.setExecutionId(row.executionId)
183-
.build()
184-
)
185218
}
186219

187220
override fun onError(error: Throwable) {
188-
observer.onError(error)
221+
if (!observer.isCancelled) {
222+
observer.onError(error)
223+
}
189224
event.endTimestamp()
190225
.exception(error, true)
191226
.also(onEvent)
192227
}
193228

194229
override fun onComplete() {
195-
observer.onCompleted()
230+
if (!observer.isCancelled) {
231+
observer.onCompleted()
232+
}
196233
event.endTimestamp()
197234
.also(onEvent)
198235
}
@@ -206,7 +243,7 @@ class DataBaseReaderGrpcServer(
206243
) : ResultListener {
207244
private val counter = AtomicLong()
208245

209-
override fun onRow(sourceId: DataSourceId, row: TableRow) {
246+
override suspend fun onRow(sourceId: DataSourceId, row: TableRow) {
210247
check(report.executionId == row.executionId) {
211248
"'Execution id' isn't equal to '${report.executionId}', row: $row"
212249
}

0 commit comments

Comments
 (0)