Skip to content

Commit

Permalink
[MODCON - 73] - Test simultaneous create tenant requests and apply im…
Browse files Browse the repository at this point in the history
…provements found after automated pipeline work
  • Loading branch information
azizbekxm committed Jul 10, 2023
1 parent 7bd9bca commit d5adc8a
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "consortia", configuration = FeignClientConfiguration.class)
public interface SyncPrimaryAffiliationClient {
@PostMapping(value = "/{consortiumId}/tenants/{tenantId}/sync-primary-affiliations")
void syncPrimaryAffiliations(@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId);
void syncPrimaryAffiliations(@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId,
@RequestParam("centralTenantId") String centralTenantId);

@PostMapping(value = "/{consortiumId}/tenants/{tenantId}/create-primary-affiliations", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
SyncPrimaryAffiliationBody savePrimaryAffiliations(@RequestBody SyncPrimaryAffiliationBody syncPrimaryAffiliationBody,
@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId);
@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId,
@RequestParam("centralTenantId") String centralTenantId);

}
18 changes: 6 additions & 12 deletions src/main/java/org/folio/consortia/controller/TenantController.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
import org.folio.consortia.rest.resource.TenantsApi;
import org.folio.consortia.service.SyncPrimaryAffiliationService;
import org.folio.consortia.service.TenantService;
import org.folio.spring.DefaultFolioExecutionContext;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.scope.FolioExecutionContextSetter;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.task.TaskExecutor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -57,23 +56,18 @@ public ResponseEntity<Void> deleteTenantById(UUID consortiumId, String tenantId)
}

@Override
public ResponseEntity<Void> syncPrimaryAffiliations(UUID consortiumId, String tenantId) {
// var context = prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext);
public ResponseEntity<Void> syncPrimaryAffiliations(UUID consortiumId, String tenantId, @NotNull String centralTenantId) {
asyncTaskExecutor.execute(getRunnableWithCurrentFolioContext(
() -> syncPrimaryAffiliationService.syncPrimaryAffiliations(consortiumId, tenantId)));
() -> syncPrimaryAffiliationService.syncPrimaryAffiliations(consortiumId, tenantId, centralTenantId)));
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

@Override
public ResponseEntity<Void> createPrimaryAffiliations(UUID consortiumId, String tenantId,
public ResponseEntity<Void> createPrimaryAffiliations(UUID consortiumId, String tenantId, @NotNull String centralTenantId,
SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) {
// try (var comtext = new FolioExecutionContextSetter(prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext))) {
// syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, syncPrimaryAffiliationBody);
// }
var context = prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext);

var context = prepareContextForTenant(centralTenantId, folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext);
asyncTaskExecutor.execute(getRunnableWithFolioContext(context,
() -> syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, syncPrimaryAffiliationBody)));
() -> syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, syncPrimaryAffiliationBody)));
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@
import java.util.UUID;

public interface SyncPrimaryAffiliationService {
void syncPrimaryAffiliations(UUID consortiumId, String syncPrimaryAffiliationBody);

/**
* Sync primary affiliation for user
* @param consortiumId - consortium unique identifier
* @param centralTenantId - central tenant unique identifier
* @param syncPrimaryAffiliationBody - consortia tenant record
*/
void syncPrimaryAffiliations(UUID consortiumId, String centralTenantId, String syncPrimaryAffiliationBody);

/**
* Create primary affiliation for user
*
* Create affiliations between central tenant and user
* primary affiliation between local tenant and its user
* @param consortiumId - consortium unique identifier
* @param syncPrimaryAffiliationBody - consortia tenant record
*/
void createPrimaryUserAffiliations(UUID consortiumId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody);
void createPrimaryUserAffiliations(UUID consortiumId, String centralTenantId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.folio.consortia.service.impl;

import static org.folio.consortia.utils.TenantContextUtils.prepareContextForTenant;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
Expand All @@ -10,7 +8,6 @@
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.folio.consortia.client.SyncPrimaryAffiliationClient;
import org.folio.consortia.config.FolioExecutionContextHelper;
import org.folio.consortia.config.kafka.KafkaService;
import org.folio.consortia.domain.dto.PrimaryAffiliationEvent;
import org.folio.consortia.domain.dto.SyncPrimaryAffiliationBody;
Expand All @@ -20,17 +17,12 @@
import org.folio.consortia.domain.entity.TenantEntity;
import org.folio.consortia.domain.entity.UserTenantEntity;
import org.folio.consortia.repository.UserTenantRepository;
import org.folio.consortia.service.ConsortiaConfigurationService;
import org.folio.consortia.service.SyncPrimaryAffiliationService;
import org.folio.consortia.service.TenantService;
import org.folio.consortia.service.UserService;
import org.folio.consortia.service.UserTenantService;
import org.folio.spring.FolioExecutionContext;
import org.folio.spring.FolioModuleMetadata;
import org.folio.spring.scope.FolioExecutionContextSetter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -47,17 +39,12 @@ public class SyncPrimaryAffiliationServiceImpl implements SyncPrimaryAffiliation
private final UserTenantService userTenantService;
private final TenantService tenantService;
private final UserTenantRepository userTenantRepository;
private final ConsortiaConfigurationService consortiaConfigurationService;
private final FolioModuleMetadata folioModuleMetadata;
private final FolioExecutionContext folioExecutionContext;
private final FolioExecutionContextHelper contextHelper;
private final ObjectMapper objectMapper = new ObjectMapper();
private final KafkaService kafkaService;
private final SyncPrimaryAffiliationClient syncPrimaryAffiliationClient;

@Override
// @Async("asyncTaskExecutor")
public void syncPrimaryAffiliations(UUID consortiumId, String tenantId) {
public void syncPrimaryAffiliations(UUID consortiumId, String tenantId, String centralTenantId) {
log.info("Start syncing user primary affiliations for tenant {}", tenantId);
List<User> users = new ArrayList<>();
try {
Expand All @@ -67,7 +54,7 @@ public void syncPrimaryAffiliations(UUID consortiumId, String tenantId) {
}
if (CollectionUtils.isNotEmpty(users)) {
SyncPrimaryAffiliationBody spab = buildSyncPrimaryAffiliationBody(tenantId, users);
syncPrimaryAffiliationClient.savePrimaryAffiliations(spab, consortiumId.toString(), tenantId);
syncPrimaryAffiliationClient.savePrimaryAffiliations(spab, consortiumId.toString(), tenantId, centralTenantId);
}
}

Expand All @@ -81,44 +68,30 @@ private SyncPrimaryAffiliationBody buildSyncPrimaryAffiliationBody(String tenant
}

@Override
// @Async("asyncTaskExecutor")
public void createPrimaryUserAffiliations(UUID consortiumId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) {
// FolioExecutionContext currentTenantContext = (FolioExecutionContext) folioExecutionContext.getInstance();
public void createPrimaryUserAffiliations(UUID consortiumId, String centralTenantId,
SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) {
log.info("Start creating user primary affiliation for tenant {}", syncPrimaryAffiliationBody.getTenantId());
var tenantId = syncPrimaryAffiliationBody.getTenantId();
var userList = syncPrimaryAffiliationBody.getUsers();
var centralTenantId = consortiaConfigurationService.getCentralTenantId(tenantId);

// try (var context = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) {
TenantEntity tenantEntity = tenantService.getByTenantId(tenantId);
IntStream.range(0, userList.size())
.sequential()
.forEach(idx -> {
var user = userList.get(idx);
log.info("Processing users: {} of {}", idx + 1, userList.size());
TenantEntity tenantEntity = tenantService.getByTenantId(tenantId);
IntStream.range(0, userList.size()).sequential().forEach(idx -> {
var user = userList.get(idx);
log.info("Processing users: {} of {}", idx + 1, userList.size());
Page<UserTenantEntity> userTenantPage = userTenantRepository.findByUserId(UUID.fromString(user.getId()), PageRequest.of(0, 1));

// context changes in every iteration and folioExecutionContext become an empty, so we should set saved context again.
// try (var context2 = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) {
Page<UserTenantEntity> userTenantPage = userTenantRepository.findByUserId(UUID.fromString(user.getId()), PageRequest.of(0, 1));
if (userTenantPage.getTotalElements() > 0) {
log.info("Primary affiliation already exists for tenant/user: {}/{}", tenantId, user.getUsername());
} else {
userTenantService.createPrimaryUserTenantAffiliation(consortiumId, tenantEntity, user.getId(), user.getUsername());
if (ObjectUtils.notEqual(centralTenantId, tenantEntity.getId())) {
userTenantService.save(consortiumId, createUserTenant(centralTenantId, user), true);
}
// context changes in userTenantService.save(), so we should set saved context again.
// try (var context3 = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) {
sendCreatePrimaryAffiliationEvent(tenantEntity, user);
// }
}
// }
if (userTenantPage.getTotalElements() > 0) {
log.info("Primary affiliation already exists for tenant/user: {}/{}", tenantId, user.getUsername());
} else {
userTenantService.createPrimaryUserTenantAffiliation(consortiumId, tenantEntity, user.getId(), user.getUsername());
if (ObjectUtils.notEqual(centralTenantId, tenantEntity.getId())) {
userTenantService.save(consortiumId, createUserTenant(centralTenantId, user), true);
}
sendCreatePrimaryAffiliationEvent(tenantEntity, user);
}

});
log.info("Successfully created primary affiliations for tenant {}", tenantId);
// } catch (Exception e) {
// log.error("Failed to create primary affiliations for tenant {}", tenantId, e);
// }
});
log.info("Successfully created primary affiliations for tenant {}", tenantId);
}

@SneakyThrows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public Tenant save(UUID consortiumId, UUID adminUserId, Tenant tenantDto) {
createUserTenantWithDummyUser(tenantDto.getId());
createShadowAdminUserWithPermissions(shadowAdminUser); //NOSONAR
}
syncPrimaryAffiliationClient.syncPrimaryAffiliations(consortiumId.toString(), tenantDto.getId());
syncPrimaryAffiliationClient.syncPrimaryAffiliations(consortiumId.toString(), tenantDto.getId(), centralTenantId);
}
log.info("save:: saved consortia configuration with centralTenantId={} by tenantId={} context", centralTenantId, tenantDto.getId());
return savedTenant;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public void deleteById(String userId) {

public User prepareShadowUser(UUID userId, String tenantId) {
try (var context = new FolioExecutionContextSetter(prepareContextForTenant(tenantId, folioModuleMetadata, (FolioExecutionContext) folioExecutionContext.getInstance()))) {
log.debug("prepareShadowUser:: Try to get user of tenant={} ", folioExecutionContext.getTenantId());
User user = new User();
User userOptional = usersClient.getUsersByUserId(userId.toString());

Expand Down
9 changes: 9 additions & 0 deletions src/main/resources/swagger.api/tenants.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ paths:
parameters:
- $ref: "#/components/parameters/consortiumId"
- $ref: "#/components/parameters/tenantId"
- $ref: "#/components/parameters/centralTenantId"
responses:
"201":
$ref: "#/components/responses/NoContent"
Expand All @@ -104,6 +105,7 @@ paths:
parameters:
- $ref: "#/components/parameters/consortiumId"
- $ref: "#/components/parameters/tenantId"
- $ref: "#/components/parameters/centralTenantId"
requestBody:
$ref: "#/components/requestBodies/SyncPrimaryAffiliationsRequest"
responses:
Expand Down Expand Up @@ -206,6 +208,13 @@ components:
type: string
required: true
description: The ID of the tenant
centralTenantId:
in: query
name: centralTenantId
schema:
type: string
required: true
description: The ID of the central tenant
trait_pageable_offset:
name: offset
in: query
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void shouldSaveTenant(String contentString) throws Exception {
when(tenantRepository.existsById(any())).thenReturn(false);
when(tenantRepository.save(any(TenantEntity.class))).thenReturn(tenantEntity);
when(tenantRepository.findCentralTenant()).thenReturn(Optional.of(centralTenant));
doNothing().when(syncPrimaryAffiliationClient).syncPrimaryAffiliations(anyString(), anyString());//.thenReturn(new SyncPrimaryAffiliationBody());
doNothing().when(syncPrimaryAffiliationClient).syncPrimaryAffiliations(anyString(), anyString(), anyString());//.thenReturn(new SyncPrimaryAffiliationBody());
doNothing().when(configurationClient).saveConfiguration(createConsortiaConfiguration(CENTRAL_TENANT_ID));

this.mockMvc.perform(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class SyncPrimaryAffiliationServiceImplTest {
void createPrimaryUserAffiliationsWhenCentralTenantSaving() throws JsonProcessingException {
var consortiumId = UUID.randomUUID();
var tenantId = "ABC1";
var centralTenantId = "diku";
TenantEntity tenantEntity1 = createTenantEntity(tenantId, "TestName1");
tenantEntity1.setConsortiumId(consortiumId);

Expand All @@ -106,7 +107,7 @@ void createPrimaryUserAffiliationsWhenCentralTenantSaving() throws JsonProcessin
okapiHeaders.put(XOkapiHeaders.TENANT, List.of(tenantId));
when(folioExecutionContext.getOkapiHeaders()).thenReturn(okapiHeaders);

syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, spab);
syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, spab);

verify(kafkaService, timeout(2000)).send(any(), anyString(), anyString());
}
Expand Down Expand Up @@ -142,7 +143,7 @@ void createPrimaryUserAffiliationsWhenLocalTenantSaving() throws JsonProcessingE
okapiHeaders.put(XOkapiHeaders.TENANT, List.of(centralTenantId));
when(folioExecutionContext.getOkapiHeaders()).thenReturn(okapiHeaders);

syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, spab);
syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, spab);

verify(kafkaService, timeout(2000)).send(any(), anyString(), anyString());
}
Expand Down

0 comments on commit d5adc8a

Please sign in to comment.