Skip to content

Commit e0ae72e

Browse files
fix(server): run initial workspace sync synchronously on installation (#1012)
1 parent eee4954 commit e0ae72e

1 file changed

Lines changed: 42 additions & 26 deletions

File tree

server/application-server/src/main/java/de/tum/in/www1/hephaestus/workspace/adapter/WorkspaceProvisioningAdapter.java

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import org.springframework.beans.factory.annotation.Qualifier;
1616
import org.springframework.core.task.AsyncTaskExecutor;
1717
import org.springframework.stereotype.Component;
18+
import org.springframework.transaction.support.TransactionSynchronization;
19+
import org.springframework.transaction.support.TransactionSynchronizationManager;
1820

1921
@Component
2022
public class WorkspaceProvisioningAdapter implements ProvisioningListener {
@@ -238,36 +240,24 @@ public void onInstallationActivated(Long installationId) {
238240
// Update status first
239241
workspaceInstallationService.updateWorkspaceStatus(installationId, Workspace.WorkspaceStatus.ACTIVE);
240242

241-
// Trigger initial sync asynchronously before starting NATS consumer
242-
// This ensures all entities exist before NATS starts processing webhook events
243+
// Sync after the outer transaction commits so RepositoryToMonitor rows are visible.
243244
workspaceRepository
244245
.findByInstallationId(installationId)
245246
.ifPresent(workspace -> {
246-
log.info(
247-
"Triggering initial sync for activated installation: installationId={}, workspaceId={}",
248-
installationId,
249-
workspace.getId()
250-
);
251-
252-
// Run sync asynchronously to avoid blocking webhook processing
253247
Long workspaceId = workspace.getId();
254-
monitoringExecutor.execute(() -> {
255-
try {
256-
getGitHubDataSyncService().syncAllRepositories(workspaceId);
257-
log.info(
258-
"Completed initial sync for activated installation: installationId={}, workspaceId={}",
259-
installationId,
260-
workspaceId
261-
);
262-
} catch (Exception e) {
263-
log.error(
264-
"Failed initial sync for activated installation: installationId={}, workspaceId={}",
265-
installationId,
266-
workspaceId,
267-
e
268-
);
269-
}
270-
});
248+
249+
if (TransactionSynchronizationManager.isSynchronizationActive()) {
250+
TransactionSynchronizationManager.registerSynchronization(
251+
new TransactionSynchronization() {
252+
@Override
253+
public void afterCommit() {
254+
triggerInitialSync(installationId, workspaceId);
255+
}
256+
}
257+
);
258+
} else {
259+
triggerInitialSync(installationId, workspaceId);
260+
}
271261
});
272262

273263
// Start NATS consumer to resume webhook processing
@@ -287,6 +277,32 @@ public void onRepositorySelectionChanged(Long installationId, String selection)
287277
log.debug("Updated repository selection: installationId={}, selection={}", installationId, repoSelection);
288278
}
289279

280+
private void triggerInitialSync(Long installationId, Long workspaceId) {
281+
log.info(
282+
"Starting initial sync for activated installation: installationId={}, workspaceId={}",
283+
installationId,
284+
workspaceId
285+
);
286+
287+
monitoringExecutor.execute(() -> {
288+
try {
289+
getGitHubDataSyncService().syncAllRepositories(workspaceId);
290+
log.info(
291+
"Completed initial sync for activated installation: installationId={}, workspaceId={}",
292+
installationId,
293+
workspaceId
294+
);
295+
} catch (Exception e) {
296+
log.error(
297+
"Failed initial sync for activated installation: installationId={}, workspaceId={}",
298+
installationId,
299+
workspaceId,
300+
e
301+
);
302+
}
303+
});
304+
}
305+
290306
private RepositorySelection parseRepositorySelection(String selection) {
291307
if ("all".equalsIgnoreCase(selection)) {
292308
return RepositorySelection.ALL;

0 commit comments

Comments
 (0)