Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RefreshApplicationServiceImpl(
private val deleteApplicationDirectoryService: DeleteApplicationDirectoryService,
private val queryVolumePort: QueryVolumePort
) : RefreshApplicationService {
@Lock("#application.id", waitTime = 1000 * 10, leaseTime = 1000 * 60 * 3)
@Lock("#application.id", waitTime = 1000 * 10, leaseTime = 1000 * 60 * 30)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | πŸ—οΈ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 락 κ΅¬ν˜„μ΄ leaseλ₯Ό μžλ™ κ°±μ‹ ν•˜λŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.
rg -n -C 10 'interface LockPort|fun lock\s*\(|tryLock|leaseTime|lockPort\.lock' --glob '*.kt' . || true

# refresh 전체 μ‹€ν–‰ κ²½λ‘œμ™€ κ΄€λ ¨ ν…ŒμŠ€νŠΈλ₯Ό ν™•μΈν•©λ‹ˆλ‹€.
rg -n -C 12 'refresh\s*\(|RefreshApplicationServiceImpl|`@Lock`' --glob '*.kt' . || true

Repository: dolong2/dcd

Length of output: 44041


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- RedissonLockAdapter.kt ---'
cat -n src/main/kotlin/com/dcd/server/infrastructure/global/adapter/RedissonLockAdapter.kt

printf '%s\n' '--- RefreshApplicationServiceImpl.kt ---'
cat -n src/main/kotlin/com/dcd/server/core/domain/application/service/impl/RefreshApplicationServiceImpl.kt

printf '%s\n' '--- build timeout and lock dependencies ---'
rg -n -C 8 'buildImage|waitFor|timeout|redisson|redisson-spring' --glob '*.kt' --glob '*.gradle*' --glob 'gradle.properties' --glob 'pom.xml' .

Repository: dolong2/dcd

Length of output: 50367


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Docker build implementation ---'
sed -n '180,215p' src/main/kotlin/com/dcd/server/infrastructure/global/thirdparty/docker/DockerCommandExecutor.kt

printf '%s\n' '--- Redisson lock configuration ---'
rg -n -C 5 'setLockWatchdogTimeout|lockWatchdogTimeout|tryLock\s*\(' \
  src/main/kotlin src/test/kotlin build.gradle.kts

printf '%s\n' '--- Deterministic lease-path check ---'
python3 - <<'PY'
from pathlib import Path

adapter = Path("src/main/kotlin/com/dcd/server/infrastructure/global/adapter/RedissonLockAdapter.kt").read_text()
service = Path("src/main/kotlin/com/dcd/server/core/domain/application/service/impl/RefreshApplicationServiceImpl.kt").read_text()
docker = Path("src/main/kotlin/com/dcd/server/infrastructure/global/thirdparty/docker/DockerCommandExecutor.kt").read_text()

print("fixed_lease_call:", "tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS)" in adapter)
print("refresh_lease_ms:", "1000 * 60 * 30" in service)
print("build_waits_for_completion:", ".awaitCompletion()" in docker)
print("build_timeout_literal_near_implementation:",
      "timeout" in docker[ docker.find("override fun buildImage"):docker.find("override fun buildImage") + 2500 ].lower())
PY

Repository: dolong2/dcd

Length of output: 7748


refresh 전체 μ‹€ν–‰ μ‹œκ°„μ„ κ³ λ €ν•˜μ—¬ 락 μž„λŒ€ μ‹œκ°„μ„ μ„€μ •ν•˜μ„Έμš”.

RedissonLockAdapterλŠ” κ³ μ •λœ leaseTime으둜 락을 νšλ“ν•˜λ©° μžλ™ 갱신을 μˆ˜ν–‰ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이미지 λΉŒλ“œλŠ” μ΅œλŒ€ 30λΆ„ λŒ€κΈ°ν•˜κ³ , λ³΅μ œμ™€ 후속 μž‘μ—…λ„ μ‹€ν–‰ν•˜λ―€λ‘œ 락은 refresh μ™„λ£Œ 전에 만료될 수 μžˆμŠ΅λ‹ˆλ‹€. 락 μžλ™ 갱신을 μ μš©ν•˜κ±°λ‚˜ μΆ©λΆ„νžˆ κΈ΄ μž„λŒ€ μ‹œκ°„μ„ μ„€μ •ν•˜κ³ , λ™μ‹œ refresh 싀행을 μ°¨λ‹¨ν•˜λŠ” 톡합 ν…ŒμŠ€νŠΈλ₯Ό μΆ”κ°€ν•˜μ„Έμš”.

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/kotlin/com/dcd/server/core/domain/application/service/impl/RefreshApplicationServiceImpl.kt`
at line 22, Update the `@Lock` configuration on refresh in
RefreshApplicationServiceImpl to cover the full refresh execution time,
including the maximum image-build wait, replication, and follow-up work; since
RedissonLockAdapter does not auto-renew fixed leases, use a sufficiently long
lease or enable the supported renewal behavior, and add an integration test
proving concurrent refresh executions remain blocked until the first refresh
completes.

override suspend fun refresh(application: Application) {
val applicationType = application.applicationType
when(applicationType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class DockerCommandExecutor(
override fun buildImage(application: Application) {
val dockerfilePath = "./${application.directoryName}/Dockerfile"
try {
dockerClient.buildImageCmd()
val completed = dockerClient.buildImageCmd()
.withDockerfile(java.io.File(dockerfilePath))
.withTags(setOf("${application.containerName}:${application.version}"))
.exec(object : BuildImageResultCallback() {
Expand All @@ -191,7 +191,12 @@ class DockerCommandExecutor(
super.onNext(item)
}
})
.awaitCompletion(120, java.util.concurrent.TimeUnit.SECONDS)
.awaitCompletion(30, TimeUnit.MINUTES)
if (!completed) {
throw DockerCommandException(application, FailureCase.IMAGE_BUILD_FAILURE, "이미지 λΉŒλ“œμ€‘ νƒ€μž„μ•„μ›ƒμ΄ λ°œμƒν•¨.")
}
} catch (e: DockerCommandException) {
throw e
Comment on lines +198 to +199

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ—„οΈ Data Integrity & Integration | 🟠 Major | ⚑ Quick win

DockerCommandException을 μ™ΈλΆ€ ν˜ΈμΆœμžμ—κ²Œ κ·ΈλŒ€λ‘œ μ „λ‹¬ν•˜μ„Έμš”.

buildImageμ—μ„œ μ˜ˆμ™Έλ₯Ό λ‹€μ‹œ λ˜μ Έλ„ execute의 Line 52-54κ°€ 이λ₯Ό λ‹€μ‹œ 작고 RuntimeException으둜 λ³€ν™˜ν•©λ‹ˆλ‹€. λ”°λΌμ„œ νƒ€μž„μ•„μ›ƒ μ˜ˆμ™Έκ°€ DockerCommandException으둜 ν˜ΈμΆœμžμ—κ²Œ μ „λ‹¬λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. FailureCase.IMAGE_BUILD_FAILUREλ₯Ό ν™•μΈν•˜λŠ” 후속 μ²˜λ¦¬λ„ 이 정보λ₯Ό 받을 수 μ—†μŠ΅λ‹ˆλ‹€.

νƒ€μž„μ•„μ›ƒ μ˜ˆμ™Έλ₯Ό κ·ΈλŒ€λ‘œ 전달해야 ν•œλ‹€λ©΄ μ™ΈλΆ€ catchμ—μ„œ 이벀트λ₯Ό λ°œν–‰ν•œ ν›„ throw exλ₯Ό μ‹€ν–‰ν•˜μ„Έμš”.

μˆ˜μ • μ˜ˆμ‹œ
             eventPublisher.publishEvent(
                 ChangeApplicationStatusEvent(
                     ApplicationStatus.FAILURE,
                     ex.application,
                     ex.failureCase,
                     ex.message
                 )
             )
-            throw RuntimeException("Docker command execution failed for application ${ex.application.name}")
+            throw ex
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/kotlin/com/dcd/server/infrastructure/global/thirdparty/docker/DockerCommandExecutor.kt`
around lines 198 - 199, Update the outer exception handling in execute so
DockerCommandException remains unchanged for external callers: publish the
required event, then rethrow the original exception instead of converting it to
RuntimeException. Preserve the existing buildImage catch behavior and ensure
FailureCase.IMAGE_BUILD_FAILURE follow-up handling can receive
DockerCommandException.

} catch (e: Exception) {
throw DockerCommandException(application, FailureCase.IMAGE_BUILD_FAILURE, e.message)
}
Expand Down
Loading