Skip to content

Commit

Permalink
[MODCON-73] - Test simultaneous create tenant requests and apply impr…
Browse files Browse the repository at this point in the history
…ovements found after automated pipeline work (#64)

* [MODCON - 73] - Test simultaneous create tenant requests and apply improvements found after automated pipeline work

* [MODCON - 73] - Test simultaneous create tenant requests and apply improvements found after automated pipeline work

* [MODCON - 73] - Test simultaneous create tenant requests and apply improvements found after automated pipeline work

* [MODCON - 73] - Fixed unit tests

* [MODCON - 73] - Test simultaneous create tenant requests and apply improvements found after automated pipeline work

* [MODCON - 73] - Increased code coverage

* [MODCON - 73] - Minor improvements

* [MODCON - 73] - Minor improvements

* [MODCON - 73] - Minor improvements

* [MODCON - 73] - Minor improvements
  • Loading branch information
azizbekxm authored Jul 11, 2023
1 parent bf65437 commit acb05c9
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 85 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<publish_coordinator.yaml.file>${project.basedir}/src/main/resources/swagger.api/publications.yaml</publish_coordinator.yaml.file>
<sharing_instances.yaml.file>${project.basedir}/src/main/resources/swagger.api/sharing_instance.yaml</sharing_instances.yaml.file>
<!-- runtime dependencies -->
<folio-spring-base.version>7.1.0</folio-spring-base.version>
<folio-spring-base.version>7.1.2</folio-spring-base.version>
<openapi-generator.version>6.2.1</openapi-generator.version>
<mapstruct.version>1.5.3.Final</mapstruct.version>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
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 String consortiumId, @PathVariable String tenantId, @RequestParam 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 String consortiumId, @PathVariable String tenantId, @RequestParam String centralTenantId);

}
2 changes: 0 additions & 2 deletions src/main/java/org/folio/consortia/config/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.folio.consortia.domain.converter.ConsortiumConverter;
import org.folio.consortia.domain.converter.TenantConverter;
import org.folio.consortia.domain.converter.UserTenantConverter;
import org.folio.spring.scope.FolioExecutionScopeExecutionContextManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
Expand Down Expand Up @@ -37,7 +36,6 @@ public TaskExecutor asyncTaskExecutor() {
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("ConsortiaAsync-");
executor.setTaskDecorator(FolioExecutionScopeExecutionContextManager::getRunnableWithCurrentFolioContext);
executor.initialize();
return executor;
}
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/org/folio/consortia/controller/TenantController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.folio.consortia.controller;

import static org.folio.consortia.utils.TenantContextUtils.prepareContextForTenant;
import static org.folio.spring.scope.FolioExecutionScopeExecutionContextManager.getRunnableWithCurrentFolioContext;
import static org.folio.spring.scope.FolioExecutionScopeExecutionContextManager.getRunnableWithFolioContext;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NO_CONTENT;

Expand All @@ -11,6 +14,9 @@
import org.folio.consortia.rest.resource.TenantsApi;
import org.folio.consortia.service.SyncPrimaryAffiliationService;
import org.folio.consortia.service.TenantService;
import org.folio.spring.FolioExecutionContext;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.task.TaskExecutor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
Expand All @@ -25,7 +31,9 @@
public class TenantController implements TenantsApi {

private final TenantService service;
private final TaskExecutor asyncTaskExecutor;
private final SyncPrimaryAffiliationService syncPrimaryAffiliationService;
private final FolioExecutionContext folioExecutionContext;
@Override
public ResponseEntity<TenantCollection> getTenants(UUID consortiumId, Integer offset, Integer limit) {
return ResponseEntity.ok(service.get(consortiumId, offset, limit));
Expand All @@ -48,15 +56,18 @@ public ResponseEntity<Void> deleteTenantById(UUID consortiumId, String tenantId)
}

@Override
public ResponseEntity<Void> syncPrimaryAffiliations(UUID consortiumId, String tenantId) {
syncPrimaryAffiliationService.syncPrimaryAffiliations(consortiumId, tenantId);
public ResponseEntity<Void> syncPrimaryAffiliations(UUID consortiumId, String tenantId, @NotNull String centralTenantId) {
asyncTaskExecutor.execute(getRunnableWithCurrentFolioContext(
() -> 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) {
syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, syncPrimaryAffiliationBody);
var context = prepareContextForTenant(centralTenantId, folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext);
asyncTaskExecutor.execute(getRunnableWithFolioContext(context,
() -> syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, syncPrimaryAffiliationBody)));
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class ResourceNotFoundException extends RuntimeException {

public static final String NOT_FOUND_MSG_TEMPLATE = "Objects with %s [%s] not found";
public static final String NOT_FOUND_MSG_TEMPLATE = "Object with %s [%s] was not found";

public ResourceNotFoundException(String attribute, String value) {
super(String.format(NOT_FOUND_MSG_TEMPLATE, attribute, value));
Expand Down
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
Expand Up @@ -3,6 +3,7 @@
import static org.folio.consortia.exception.PublicationException.PRIMARY_AFFILIATION_NOT_EXISTS;
import static org.folio.consortia.exception.PublicationException.TENANT_LIST_EMPTY;
import static org.folio.consortia.utils.TenantContextUtils.prepareContextForTenant;
import static org.folio.spring.scope.FolioExecutionScopeExecutionContextManager.getRunnableWithCurrentFolioContext;

import java.time.LocalDateTime;
import java.util.ArrayList;
Expand Down Expand Up @@ -74,7 +75,8 @@ public PublicationResponse publishRequest(UUID consortiumId, PublicationRequest

PublicationStatusEntity createdPublicationEntity = savePublicationStatusRecord(publicationRequest.getTenants().size());

asyncTaskExecutor.execute(() -> processTenantRequests(publicationRequest, createdPublicationEntity));
asyncTaskExecutor.execute(getRunnableWithCurrentFolioContext(
() -> processTenantRequests(publicationRequest, createdPublicationEntity)));

return buildPublicationResponse(createdPublicationEntity.getId());
}
Expand Down
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,38 +68,28 @@ 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))) {
try {
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());
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);
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.info("prepareShadowUser:: Try to get user of tenant={} ", folioExecutionContext.getTenantId());
User user = new User();
User userOptional = usersClient.getUsersByUserId(userId.toString());

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ spring:
folio:
environment: ${ENV:folio}
okapi:
url: ${OKAPI_URL:http://localhost:9130}
url: ${OKAPI_URL:http://okapi:9130}
kafka:
numberOfPartitions: ${NUMBER_OF_PARTITIONS:1}
replicationFactor: ${REPLICATION_FACTOR:1}
Expand Down
33 changes: 33 additions & 0 deletions src/main/resources/log4j2-json.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
status = error
name = PropertiesConfig
packages = org.folio.spring.logging

appenders = console

appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = JSONLayout
appender.console.layout.compact = true
appender.console.layout.eventEol = true
appender.console.layout.stacktraceAsString = true
appender.console.layout.includeTimeMillis = true

appender.console.layout.requestId.type = KeyValuePair
appender.console.layout.requestId.key = requestId
appender.console.layout.requestId.value = $${folio:requestid:-}

appender.console.layout.tenantId.type = KeyValuePair
appender.console.layout.tenantId.key = tenantId
appender.console.layout.tenantId.value = $${folio:tenantid:-}

appender.console.layout.userId.type = KeyValuePair
appender.console.layout.userId.key = userId
appender.console.layout.userId.value = $${folio:userid:-}

appender.console.layout.moduleId.type = KeyValuePair
appender.console.layout.moduleId.key = moduleId
appender.console.layout.moduleId.value = $${folio:moduleid:-}

rootLogger.level = info
rootLogger.appenderRefs = info
rootLogger.appenderRef.stdout.ref = STDOUT
15 changes: 15 additions & 0 deletions src/main/resources/log4j2.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
status = error
name = PropertiesConfig
packages = org.folio.spring.logging

appenders = console

appender.console.type = Console
appender.console.name = STDOUT

appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d{HH:mm:ss} %t [$${folio:requestid:-}] [$${folio:tenantid:-}] [$${folio:userid:-}] [$${folio:moduleid:-}] %-5p %-20.20C{1} %m%n

rootLogger.level = info
rootLogger.appenderRefs = info
rootLogger.appenderRef.stdout.ref = STDOUT
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
Loading

0 comments on commit acb05c9

Please sign in to comment.