Skip to content

Commit f659469

Browse files
authored
Merge pull request #524 from RADAR-base/coroutines
Coroutines
2 parents d7644a7 + 9fff4c7 commit f659469

File tree

62 files changed

+1448
-969
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1448
-969
lines changed

.github/workflows/scheduled_snyk.yaml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ jobs:
88
env:
99
REPORT_FILE: test.json
1010
steps:
11-
- uses: actions/checkout@master
11+
- uses: actions/checkout@v3
1212
- uses: snyk/actions/setup@master
13+
with:
14+
snyk-version: v1.931.0
1315

14-
- uses: actions/setup-java@v2
16+
- uses: actions/setup-java@v3
1517
with:
16-
distribution: zulu
18+
distribution: temurin
1719
java-version: 17
1820

1921
- name: Setup Gradle
@@ -27,3 +29,11 @@ jobs:
2729
--configuration-matching='^runtimeClasspath$'
2830
--json-file-output=${{ env.REPORT_FILE }}
2931
--org=radar-base
32+
33+
- name: Report new vulnerabilities
34+
uses: thehyve/report-vulnerability@master
35+
with:
36+
report-file: ${{ env.REPORT_FILE }}
37+
env:
38+
TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
if: ${{ failure() }}

.github/workflows/snyk.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ jobs:
77
security:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: actions/checkout@master
10+
- uses: actions/checkout@v3
1111
- uses: snyk/actions/setup@master
12+
with:
13+
snyk-version: v1.931.0
1214

13-
- uses: actions/setup-java@v2
15+
- uses: actions/setup-java@v3
1416
with:
15-
distribution: zulu
17+
distribution: temurin
1618
java-version: 17
1719

1820
- name: Setup Gradle
@@ -23,7 +25,7 @@ jobs:
2325
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
2426
run: >
2527
snyk test
26-
--severity-threshold=high
2728
--configuration-matching='^runtimeClasspath$'
2829
--fail-on=upgradable
2930
--org=radar-base
31+
--severity-threshold=high

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ MAINTAINER Joris Borgdorff <[email protected]>, Yatharth Ranjan<yatharth.ranjan@k
3232
LABEL description="RADAR-base output data restructuring"
3333

3434
ENV RADAR_OUTPUT_RESTRUCTURE_OPTS="" \
35-
JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -XX:+UseG1GC -XX:MaxHeapFreeRatio=10 -XX:MinHeapFreeRatio=10"
35+
JAVA_OPTS="-XX:+UseG1GC -XX:MaxHeapFreeRatio=10 -XX:MinHeapFreeRatio=10"
3636

3737
COPY --from=builder /code/build/third-party/* /usr/lib/
3838
COPY --from=builder /code/build/scripts/* /usr/bin/

build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ dependencies {
5050
runtimeOnly("org.xerial.snappy:snappy-java:$snappyVersion")
5151

5252
implementation(kotlin("reflect"))
53+
val coroutinesVersion: String by project
54+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
5355

5456
val jacksonVersion: String by project
5557
api(platform("com.fasterxml.jackson:jackson-bom:$jacksonVersion"))
@@ -95,6 +97,7 @@ dependencies {
9597

9698
val radarSchemasVersion: String by project
9799
testImplementation("org.radarbase:radar-schemas-commons:$radarSchemasVersion")
100+
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
98101

99102
val junitVersion: String by project
100103
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ dependencyUpdateVersion=0.42.0
77
nexusPublishVersion=1.1.0
88
jsoupVersion=1.14.3
99

10+
coroutinesVersion=1.6.1
1011
avroVersion=1.11.0
1112
snappyVersion=1.1.8.4
1213
jacksonVersion=2.13.2.20220328

restructure.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
service:
22
# Whether to run the application as a polling service.
3-
enable: false
3+
enable: true
44
# Polling interval in seconds.
55
interval: 30
66

@@ -118,7 +118,7 @@ cleaner:
118118
# Enable cleaning up old source files
119119
enable: true
120120
# Interval in seconds to clean data
121-
interval: 1260 # 21 minutes
121+
interval: 50 # 21 minutes
122122
# Number of days after which a source file is considered old
123123
age: 7
124124

src/integrationTest/java/org/radarbase/output/RestructureS3IntegrationTest.kt

Lines changed: 86 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package org.radarbase.output
22

33
import io.minio.*
44
import io.minio.ObjectWriteArgs.MAX_PART_SIZE
5+
import kotlinx.coroutines.*
6+
import kotlinx.coroutines.test.runTest
57
import org.junit.jupiter.api.Assertions.assertEquals
68
import org.junit.jupiter.api.Test
79
import org.radarbase.output.config.*
10+
import org.radarbase.output.util.SuspendedCloseable.Companion.useSuspended
811
import org.radarbase.output.util.Timer
912
import org.radarbase.output.util.bucketBuild
1013
import org.radarbase.output.util.objectBuild
@@ -13,7 +16,7 @@ import java.nio.file.Paths
1316

1417
class RestructureS3IntegrationTest {
1518
@Test
16-
fun integration() {
19+
fun integration() = runTest {
1720
Timer.isEnabled = true
1821
val sourceConfig = S3Config(
1922
endpoint ="http://localhost:9000",
@@ -38,77 +41,109 @@ class RestructureS3IntegrationTest {
3841
}
3942

4043
val resourceFiles = listOf(
41-
"application_server_status/partition=1/application_server_status+1+0000000018+0000000020.avro",
42-
"application_server_status/partition=1/application_server_status+1+0000000021.avro",
43-
"android_phone_acceleration/partition=0/android_phone_acceleration+0+0003018784.avro"
44+
"application_server_status/partition=1/application_server_status+1+0000000018+0000000020.avro",
45+
"application_server_status/partition=1/application_server_status+1+0000000021.avro",
46+
"android_phone_acceleration/partition=0/android_phone_acceleration+0+0003018784.avro",
4447
)
4548
val targetFiles = resourceFiles.map { Paths.get("in/$it") }
46-
resourceFiles.forEachIndexed { i, resourceFile ->
47-
javaClass.getResourceAsStream("/$resourceFile").use { statusFile ->
48-
sourceClient.putObject(PutObjectArgs.Builder().objectBuild(sourceConfig.bucket, targetFiles[i]) {
49-
stream(statusFile, -1, MAX_PART_SIZE)
50-
})
49+
resourceFiles.mapIndexed { i, resourceFile ->
50+
launch(Dispatchers.IO) {
51+
this@RestructureS3IntegrationTest.javaClass.getResourceAsStream("/$resourceFile")
52+
.useSuspended { statusFile ->
53+
sourceClient.putObject(PutObjectArgs.Builder()
54+
.objectBuild(sourceConfig.bucket, targetFiles[i]) {
55+
stream(statusFile, -1, MAX_PART_SIZE)
56+
})
57+
}
5158
}
52-
}
59+
}.joinAll()
5360

5461
application.start()
5562

5663
val targetClient = targetConfig.createS3Client()
57-
val files = targetClient.listObjects(ListObjectsArgs.Builder().bucketBuild(targetConfig.bucket) {
58-
prefix("output")
59-
recursive(true)
60-
useUrlEncodingType(false)
61-
})
62-
.map { it.get().objectName() }
63-
.toList()
6464

6565
application.redisHolder.execute { redis ->
66-
assertEquals(1L, redis.del("offsets/application_server_status.json"))
67-
assertEquals(1L, redis.del("offsets/android_phone_acceleration.json"))
66+
launch { assertEquals(1L, redis.del("offsets/application_server_status.json")) }
67+
launch { assertEquals(1L, redis.del("offsets/android_phone_acceleration.json")) }
6868
}
6969

7070
val firstParticipantOutput = "output/STAGING_PROJECT/1543bc93-3c17-4381-89a5-c5d6272b827c/application_server_status"
7171
val secondParticipantOutput = "output/radar-test-root/4ab9b985-6eec-4e51-9a29-f4c571c89f99/android_phone_acceleration"
72-
assertEquals(
73-
listOf(
74-
"$firstParticipantOutput/20200128_1300.csv",
75-
"$firstParticipantOutput/20200128_1400.csv",
76-
"$firstParticipantOutput/schema-application_server_status.json",
77-
"$secondParticipantOutput/20200528_1000.csv",
78-
"$secondParticipantOutput/schema-android_phone_acceleration.json"),
79-
files)
80-
81-
println(targetClient.getObject(GetObjectArgs.builder()
82-
.bucketBuild(targetConfig.bucket) {
83-
`object`("$firstParticipantOutput/20200128_1300.csv")
84-
}
85-
).readBytes().toString(UTF_8))
8672

87-
val csvContents = """
73+
val files = coroutineScope {
74+
launch(Dispatchers.IO) {
75+
val csvContents = """
8876
key.projectId,key.userId,key.sourceId,value.time,value.serverStatus,value.ipAddress
8977
STAGING_PROJECT,1543bc93-3c17-4381-89a5-c5d6272b827c,99caf236-bbe6-4eed-9c63-fba77349821d,1.58021982003E9,CONNECTED,
9078
STAGING_PROJECT,1543bc93-3c17-4381-89a5-c5d6272b827c,99caf236-bbe6-4eed-9c63-fba77349821d,1.58021982003E9,CONNECTED,
9179
9280
""".trimIndent()
93-
assertEquals(csvContents, targetClient.getObject(GetObjectArgs.Builder()
94-
.bucketBuild(targetConfig.bucket) {
95-
`object`("$firstParticipantOutput/20200128_1300.csv")
96-
})
97-
.readBytes()
98-
.toString(UTF_8))
99-
100-
targetFiles.forEach {
101-
sourceClient.removeObject(RemoveObjectArgs.Builder()
102-
.objectBuild(sourceConfig.bucket, it))
103-
}
104-
sourceClient.removeBucket(RemoveBucketArgs.Builder().bucketBuild(sourceConfig.bucket))
105-
files.forEach {
106-
targetClient.removeObject(RemoveObjectArgs.Builder().bucketBuild(targetConfig.bucket) {
107-
`object`(it)
108-
})
81+
82+
val targetContent = targetClient.getObject(GetObjectArgs.Builder()
83+
.bucketBuild(targetConfig.bucket) {
84+
`object`("$firstParticipantOutput/20200128_1300.csv")
85+
}).use { response ->
86+
response.readBytes()
87+
}
88+
89+
assertEquals(csvContents, targetContent.toString(UTF_8))
90+
}
91+
92+
withContext(Dispatchers.IO) {
93+
targetClient.listObjects(ListObjectsArgs.Builder()
94+
.bucketBuild(targetConfig.bucket) {
95+
prefix("output")
96+
recursive(true)
97+
useUrlEncodingType(false)
98+
})
99+
.map { it.get().objectName() }
100+
.toHashSet()
101+
}
109102
}
110-
targetClient.removeBucket(RemoveBucketArgs.Builder().bucketBuild(targetConfig.bucket))
111103

104+
assertEquals(
105+
hashSetOf(
106+
"$firstParticipantOutput/20200128_1300.csv",
107+
"$firstParticipantOutput/20200128_1400.csv",
108+
"$firstParticipantOutput/schema-application_server_status.json",
109+
"$secondParticipantOutput/20200528_1000.csv",
110+
"$secondParticipantOutput/schema-android_phone_acceleration.json",
111+
),
112+
files,
113+
)
114+
115+
coroutineScope {
116+
// delete source files
117+
launch {
118+
targetFiles.map {
119+
launch(Dispatchers.IO) {
120+
sourceClient.removeObject(RemoveObjectArgs.Builder()
121+
.objectBuild(sourceConfig.bucket, it))
122+
}
123+
}.joinAll()
124+
125+
launch(Dispatchers.IO) {
126+
sourceClient.removeBucket(RemoveBucketArgs.Builder()
127+
.bucketBuild(sourceConfig.bucket))
128+
}
129+
}
130+
131+
// delete target files
132+
launch {
133+
files.map {
134+
launch(Dispatchers.IO) {
135+
targetClient.removeObject(RemoveObjectArgs.Builder()
136+
.bucketBuild(targetConfig.bucket) {
137+
`object`(it)
138+
})
139+
}
140+
}.joinAll()
141+
launch(Dispatchers.IO) {
142+
targetClient.removeBucket(RemoveBucketArgs.Builder()
143+
.bucketBuild(targetConfig.bucket))
144+
}
145+
}
146+
}
112147
println(Timer)
113148
}
114149
}

src/integrationTest/java/org/radarbase/output/accounting/OffsetRangeRedisTest.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package org.radarbase.output.accounting
22

3+
import kotlinx.coroutines.test.runTest
34
import org.junit.jupiter.api.AfterEach
45
import org.junit.jupiter.api.Assertions.*
56
import org.junit.jupiter.api.BeforeEach
67
import org.junit.jupiter.api.Test
78
import org.radarbase.output.accounting.OffsetRedisPersistence.Companion.redisOffsetReader
9+
import org.radarbase.output.util.SuspendedCloseable.Companion.useSuspended
810
import redis.clients.jedis.JedisPool
911
import java.io.IOException
1012
import java.nio.file.Path
@@ -27,16 +29,18 @@ class OffsetRangeRedisTest {
2729

2830
@AfterEach
2931
fun tearDown() {
30-
redisHolder.execute { it.del(testFile.toString()) }
32+
runTest {
33+
redisHolder.execute { it.del(testFile.toString()) }
34+
}
3135
}
3236

3337
@Test
3438
@Throws(IOException::class)
35-
fun readEmpty() {
39+
fun readEmpty() = runTest {
3640
assertNull(offsetPersistence.read(testFile))
3741

3842
// will create on write
39-
offsetPersistence.writer(testFile).close()
43+
offsetPersistence.writer(this@runTest, testFile).closeAndJoin()
4044

4145
assertEquals(true, offsetPersistence.read(testFile)?.isEmpty)
4246

@@ -47,8 +51,8 @@ class OffsetRangeRedisTest {
4751

4852
@Test
4953
@Throws(IOException::class)
50-
fun write() {
51-
offsetPersistence.writer(testFile).use { rangeFile ->
54+
fun write() = runTest {
55+
offsetPersistence.writer(this@runTest, testFile).useSuspended { rangeFile ->
5256
rangeFile.add(TopicPartitionOffsetRange.parseFilename("a+0+0+1", lastModified))
5357
rangeFile.add(TopicPartitionOffsetRange.parseFilename("a+0+1+2", lastModified))
5458
}
@@ -67,8 +71,8 @@ class OffsetRangeRedisTest {
6771

6872
@Test
6973
@Throws(IOException::class)
70-
fun cleanUp() {
71-
offsetPersistence.writer(testFile).use { rangeFile ->
74+
fun cleanUp() = runTest {
75+
offsetPersistence.writer(this@runTest, testFile).useSuspended { rangeFile ->
7276
rangeFile.add(TopicPartitionOffsetRange.parseFilename("a+0+0+1", lastModified))
7377
rangeFile.add(TopicPartitionOffsetRange.parseFilename("a+0+1+2", lastModified))
7478
rangeFile.add(TopicPartitionOffsetRange.parseFilename("a+0+4+4", lastModified))

0 commit comments

Comments
 (0)