fix: make tenant provisioning truly async via self-proxy
@Async on provisionAsync() was bypassed because all call sites were internal (this.provisionAsync), skipping the Spring proxy. Inject self via @Lazy to route through the proxy so provisioning runs in a background thread and the API returns immediately. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import net.siegeln.cameleer.saas.tenant.TenantStatus;
|
|||||||
import net.siegeln.cameleer.saas.tenant.dto.CreateTenantRequest;
|
import net.siegeln.cameleer.saas.tenant.dto.CreateTenantRequest;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -49,6 +50,7 @@ public class VendorTenantService {
|
|||||||
private final ProvisioningProperties provisioningProps;
|
private final ProvisioningProperties provisioningProps;
|
||||||
private final TenantDataCleanupService dataCleanupService;
|
private final TenantDataCleanupService dataCleanupService;
|
||||||
private final TenantDatabaseService tenantDatabaseService;
|
private final TenantDatabaseService tenantDatabaseService;
|
||||||
|
private final VendorTenantService self;
|
||||||
|
|
||||||
public VendorTenantService(TenantService tenantService,
|
public VendorTenantService(TenantService tenantService,
|
||||||
TenantRepository tenantRepository,
|
TenantRepository tenantRepository,
|
||||||
@@ -60,7 +62,8 @@ public class VendorTenantService {
|
|||||||
AuditService auditService,
|
AuditService auditService,
|
||||||
ProvisioningProperties provisioningProps,
|
ProvisioningProperties provisioningProps,
|
||||||
TenantDataCleanupService dataCleanupService,
|
TenantDataCleanupService dataCleanupService,
|
||||||
TenantDatabaseService tenantDatabaseService) {
|
TenantDatabaseService tenantDatabaseService,
|
||||||
|
@Lazy VendorTenantService self) {
|
||||||
this.tenantService = tenantService;
|
this.tenantService = tenantService;
|
||||||
this.tenantRepository = tenantRepository;
|
this.tenantRepository = tenantRepository;
|
||||||
this.licenseService = licenseService;
|
this.licenseService = licenseService;
|
||||||
@@ -72,6 +75,7 @@ public class VendorTenantService {
|
|||||||
this.provisioningProps = provisioningProps;
|
this.provisioningProps = provisioningProps;
|
||||||
this.dataCleanupService = dataCleanupService;
|
this.dataCleanupService = dataCleanupService;
|
||||||
this.tenantDatabaseService = tenantDatabaseService;
|
this.tenantDatabaseService = tenantDatabaseService;
|
||||||
|
this.self = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -114,7 +118,7 @@ public class VendorTenantService {
|
|||||||
|
|
||||||
// 4. Provision server asynchronously (Docker containers, health check, config push)
|
// 4. Provision server asynchronously (Docker containers, health check, config push)
|
||||||
if (tenantProvisioner.isAvailable()) {
|
if (tenantProvisioner.isAvailable()) {
|
||||||
provisionAsync(tenant.getId(), tenant.getSlug(), tenant.getTier().name(), license.getToken(), actorId);
|
self.provisionAsync(tenant.getId(), tenant.getSlug(), tenant.getTier().name(), license.getToken(), actorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tenant;
|
return tenant;
|
||||||
@@ -251,7 +255,7 @@ public class VendorTenantService {
|
|||||||
tenantProvisioner.remove(tenant.getSlug());
|
tenantProvisioner.remove(tenant.getSlug());
|
||||||
var license = licenseService.getActiveLicense(tenantId).orElse(null);
|
var license = licenseService.getActiveLicense(tenantId).orElse(null);
|
||||||
String token = license != null ? license.getToken() : "";
|
String token = license != null ? license.getToken() : "";
|
||||||
provisionAsync(tenantId, tenant.getSlug(), tenant.getTier().name(), token, null);
|
self.provisionAsync(tenantId, tenant.getSlug(), tenant.getTier().name(), token, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
@@ -268,7 +272,7 @@ public class VendorTenantService {
|
|||||||
// Re-provision with freshly pulled images
|
// Re-provision with freshly pulled images
|
||||||
var license = licenseService.getActiveLicense(tenantId).orElse(null);
|
var license = licenseService.getActiveLicense(tenantId).orElse(null);
|
||||||
String token = license != null ? license.getToken() : "";
|
String token = license != null ? license.getToken() : "";
|
||||||
provisionAsync(tenantId, tenant.getSlug(), tenant.getTier().name(), token, null);
|
self.provisionAsync(tenantId, tenant.getSlug(), tenant.getTier().name(), token, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|||||||
Reference in New Issue
Block a user