Skip to content

Commit dabfe5f

Browse files
committed
fix: recording statistics randomly failing due to lack of ongoing DB session to join fetch stats history
1 parent 9f12ef9 commit dabfe5f

File tree

3 files changed

+33
-32
lines changed

3 files changed

+33
-32
lines changed

ambassador-application/src/main/kotlin/com/roche/ambassador/analysis/AnalysisService.kt

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,27 @@ import com.roche.ambassador.model.project.Project
1111
import com.roche.ambassador.model.source.ProjectSources
1212
import com.roche.ambassador.storage.project.ProjectEntity
1313
import com.roche.ambassador.storage.project.ProjectEntityRepository
14+
import com.roche.ambassador.storage.project.ProjectStatisticsHistory
15+
import com.roche.ambassador.storage.project.ProjectStatisticsHistoryRepository
1416
import kotlinx.coroutines.CoroutineScope
1517
import kotlinx.coroutines.launch
1618
import org.springframework.stereotype.Service
19+
import org.springframework.transaction.PlatformTransactionManager
1720
import org.springframework.transaction.annotation.Propagation
1821
import org.springframework.transaction.annotation.Transactional
22+
import org.springframework.transaction.support.TransactionTemplate
1923

2024
@Service
2125
internal class AnalysisService(
2226
private val scorecardConfiguration: ScorecardConfiguration,
2327
private val projectEntityRepository: ProjectEntityRepository,
28+
private val projectStatisticsHistoryRepository: ProjectStatisticsHistoryRepository,
2429
private val projectSources: ProjectSources,
30+
platformTransactionManager: PlatformTransactionManager,
2531
concurrencyProvider: ConcurrencyProvider
2632
) {
2733

34+
private val transactionTemplate: TransactionTemplate = TransactionTemplate(platformTransactionManager)
2835
private val analysisScope: CoroutineScope = CoroutineScope(concurrencyProvider.getSupportingDispatcher())
2936
private val calculator: ScorecardCalculator = ScorecardCalculator(scorecardConfiguration)
3037

@@ -45,7 +52,7 @@ internal class AnalysisService(
4552
}
4653

4754
// TODO run async
48-
@Transactional(propagation = Propagation.REQUIRES_NEW)
55+
@Transactional
4956
fun analyzeAll() {
5057
val total = projectEntityRepository.countAllBySubscribed(true)
5158
val progressMonitor: ProgressMonitor = LoggingProgressMonitor(total, 2, AnalysisService::class)
@@ -57,16 +64,19 @@ internal class AnalysisService(
5764
}
5865

5966
private fun analyze(entity: ProjectEntity, progressMonitor: ProgressMonitor) {
60-
analysisScope.launch {
61-
try {
62-
entity.project = analyze(entity.project)
63-
entity.updateScore(entity.project)
64-
entity.recordStatistics()
65-
projectEntityRepository.save(entity)
66-
progressMonitor.success()
67-
} catch (e: Throwable) {
68-
log.error("Failed to analyze project '{}' (id={}).", entity.project.fullName, entity.project.id, e)
69-
progressMonitor.failure()
67+
transactionTemplate.execute {
68+
analysisScope.launch {
69+
try {
70+
entity.project = analyze(entity.project)
71+
entity.updateScore(entity.project)
72+
val savedEntity = projectEntityRepository.save(entity)
73+
val historyEntry = ProjectStatisticsHistory.from(savedEntity)
74+
projectStatisticsHistoryRepository.save(historyEntry)
75+
progressMonitor.success()
76+
} catch (e: Throwable) {
77+
log.error("Failed to analyze project '{}' (id={}).", entity.project.fullName, entity.project.id, e)
78+
progressMonitor.failure()
79+
}
7080
}
7181
}
7282
}

ambassador-storage/src/main/kotlin/com/roche/ambassador/storage/project/ProjectEntity.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,6 @@ class ProjectEntity(
6464

6565
fun wasIndexedBefore(otherDate: LocalDate): Boolean = lastIndexedDate.isBefore(otherDate.atStartOfDay())
6666

67-
fun recordStatistics(): ProjectStatisticsHistory {
68-
val historyEntry = ProjectStatisticsHistory.from(this)
69-
statsHistory.add(historyEntry)
70-
return historyEntry
71-
}
72-
7367
fun updateIndex(project: Project) {
7468
this.name = project.name
7569
this.project = project

ambassador-storage/src/test/kotlin/com/roche/ambassador/storage/project/ProjectEntityTest.kt

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import com.roche.ambassador.model.Visibility
44
import com.roche.ambassador.model.project.Permissions
55
import com.roche.ambassador.model.project.Project
66
import com.roche.ambassador.model.stats.Statistics
7-
import org.assertj.core.api.Assertions.assertThat
8-
import org.junit.jupiter.api.Test
97
import java.time.LocalDate
10-
import java.time.LocalDateTime
118

129
class ProjectEntityTest {
1310

@@ -21,16 +18,16 @@ class ProjectEntityTest {
2118
Permissions(true, true)
2219
)
2320

24-
@Test
25-
fun `should create new stats history entry when recording stats`() {
26-
val project = ProjectEntity(project = createProject(), lastIndexedDate = LocalDateTime.now(),)
27-
28-
val history = project.recordStatistics()
29-
30-
assertThat(project.statsHistory).hasSize(1)
31-
.containsExactly(history)
32-
assertThat(history)
33-
.extracting(ProjectStatisticsHistory::date, ProjectStatisticsHistory::project)
34-
.containsExactly(project.lastIndexedDate, project)
35-
}
21+
// @Test
22+
// fun `should create new stats history entry when recording stats`() {
23+
// val project = ProjectEntity(project = createProject(), lastIndexedDate = LocalDateTime.now(),)
24+
//
25+
// val history = project.recordStatistics()
26+
//
27+
// assertThat(project.statsHistory).hasSize(1)
28+
// .containsExactly(history)
29+
// assertThat(history)
30+
// .extracting(ProjectStatisticsHistory::date, ProjectStatisticsHistory::project)
31+
// .containsExactly(project.lastIndexedDate, project)
32+
// }
3633
}

0 commit comments

Comments
 (0)