Search in sources :

Example 1 with RawRecordsDto

use of org.folio.rest.jaxrs.model.RawRecordsDto in project mod-source-record-manager by folio-org.

the class EventDrivenChunkProcessingServiceImpl method processRawRecordsChunk.

@Override
protected Future<Boolean> processRawRecordsChunk(RawRecordsDto incomingChunk, JobExecutionSourceChunk sourceChunk, String jobExecutionId, OkapiConnectionParams params) {
    LOGGER.debug("Starting to process raw records chunk with id: {} for jobExecutionId: {}. Chunk size: {}.", sourceChunk.getId(), jobExecutionId, sourceChunk.getChunkSize());
    Promise<Boolean> promise = Promise.promise();
    initializeJobExecutionProgressIfNecessary(jobExecutionId, incomingChunk, params.getTenantId()).compose(ar -> checkAndUpdateJobExecutionStatusIfNecessary(jobExecutionId, new StatusDto().withStatus(StatusDto.Status.PARSING_IN_PROGRESS), params)).compose(jobExec -> changeEngineService.parseRawRecordsChunkForJobExecution(incomingChunk, jobExec, sourceChunk.getId(), params)).onComplete(sendEventsAr -> updateJobExecutionIfAllSourceChunksMarkedAsError(jobExecutionId, params).onComplete(updateAr -> promise.handle(sendEventsAr.map(true))));
    return promise.future();
}
Also used : StatusDto(org.folio.rest.jaxrs.model.StatusDto) StatusDto(org.folio.rest.jaxrs.model.StatusDto) Promise(io.vertx.core.Promise) Autowired(org.springframework.beans.factory.annotation.Autowired) JobExecutionSourceChunk(org.folio.rest.jaxrs.model.JobExecutionSourceChunk) Future(io.vertx.core.Future) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) NotFoundException(javax.ws.rs.NotFoundException) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) Logger(org.apache.logging.log4j.Logger) JobExecutionProgress(org.folio.rest.jaxrs.model.JobExecutionProgress) JobExecutionProgressService(org.folio.services.progress.JobExecutionProgressService) CollectionUtils.isNotEmpty(org.apache.commons.collections4.CollectionUtils.isNotEmpty) PARSING_IN_PROGRESS(org.folio.rest.jaxrs.model.StatusDto.Status.PARSING_IN_PROGRESS) Service(org.springframework.stereotype.Service) JobExecutionSourceChunkDao(org.folio.dao.JobExecutionSourceChunkDao) JobExecution(org.folio.rest.jaxrs.model.JobExecution) LogManager(org.apache.logging.log4j.LogManager)

Example 2 with RawRecordsDto

use of org.folio.rest.jaxrs.model.RawRecordsDto in project mod-source-record-manager by folio-org.

the class RawMarcChunksErrorHandler method handle.

@Override
public void handle(Throwable throwable, KafkaConsumerRecord<String, String> record) {
    Event event = Json.decodeValue(record.value(), Event.class);
    List<KafkaHeader> kafkaHeaders = record.headers();
    OkapiConnectionParams okapiParams = new OkapiConnectionParams(KafkaHeaderUtils.kafkaHeadersToMap(kafkaHeaders), vertx);
    String jobExecutionId = okapiParams.getHeaders().get(JOB_EXECUTION_ID_HEADER);
    String chunkId = okapiParams.getHeaders().get(CHUNK_ID_HEADER);
    String tenantId = okapiParams.getTenantId();
    String lastChunk = okapiParams.getHeaders().get(LAST_CHUNK_HEADER);
    if (StringUtils.isNotBlank(lastChunk)) {
        LOGGER.error("Source chunk with jobExecutionId: {} , tenantId: {}, chunkId: {} marked as last, prevent sending DI error", jobExecutionId, tenantId, chunkId, throwable);
    } else if (throwable instanceof RecordsPublishingException) {
        List<Record> failedRecords = ((RecordsPublishingException) throwable).getFailedRecords();
        for (Record failedRecord : failedRecords) {
            sendDiErrorEvent(throwable, okapiParams, jobExecutionId, tenantId, failedRecord);
        }
    } else if (throwable instanceof DuplicateEventException) {
        RawRecordsDto rawRecordsDto = Json.decodeValue(event.getEventPayload(), RawRecordsDto.class);
        LOGGER.info("Duplicate event received, skipping parsing for jobExecutionId: {} , tenantId: {}, chunkId:{}, totalRecords: {}, cause: {}", jobExecutionId, tenantId, chunkId, rawRecordsDto.getInitialRecords().size(), throwable.getMessage());
    } else if (throwable instanceof RawChunkRecordsParsingException) {
        RawChunkRecordsParsingException exception = (RawChunkRecordsParsingException) throwable;
        parsedRecordsErrorProvider.getParsedRecordsFromInitialRecords(okapiParams, jobExecutionId, exception.getRawRecordsDto()).onComplete(ar -> {
            List<Record> parsedRecords = ar.result();
            if (CollectionUtils.isNotEmpty(parsedRecords)) {
                for (Record rec : parsedRecords) {
                    sendDiError(throwable, jobExecutionId, okapiParams, rec);
                }
            } else {
                sendDiError(throwable, jobExecutionId, okapiParams, null);
            }
        });
    } else {
        sendDiErrorEvent(throwable, okapiParams, jobExecutionId, tenantId, null);
    }
}
Also used : DuplicateEventException(org.folio.kafka.exception.DuplicateEventException) Json(io.vertx.core.json.Json) ProcessRecordErrorHandler(org.folio.kafka.ProcessRecordErrorHandler) Autowired(org.springframework.beans.factory.annotation.Autowired) HashMap(java.util.HashMap) RecordsPublishingException(org.folio.services.exceptions.RecordsPublishingException) StringUtils(org.apache.commons.lang3.StringUtils) CollectionUtils(org.apache.commons.collections4.CollectionUtils) RawChunkRecordsParsingException(org.folio.services.exceptions.RawChunkRecordsParsingException) Qualifier(org.springframework.beans.factory.annotation.Qualifier) DI_ERROR(org.folio.rest.jaxrs.model.DataImportEventTypes.DI_ERROR) DiErrorPayloadBuilder(org.folio.verticle.consumers.errorhandlers.payloadbuilders.DiErrorPayloadBuilder) Event(org.folio.rest.jaxrs.model.Event) EventHandlingUtil(org.folio.services.util.EventHandlingUtil) DuplicateEventException(org.folio.kafka.exception.DuplicateEventException) Record(org.folio.rest.jaxrs.model.Record) RecordConversionUtil(org.folio.services.util.RecordConversionUtil) Vertx(io.vertx.core.Vertx) DataImportEventPayload(org.folio.DataImportEventPayload) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) Component(org.springframework.stereotype.Component) List(java.util.List) Logger(org.apache.logging.log4j.Logger) KafkaConsumerRecord(io.vertx.kafka.client.consumer.KafkaConsumerRecord) KafkaHeader(io.vertx.kafka.client.producer.KafkaHeader) LogManager(org.apache.logging.log4j.LogManager) KafkaHeaderUtils(org.folio.kafka.KafkaHeaderUtils) KafkaConfig(org.folio.kafka.KafkaConfig) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) RawChunkRecordsParsingException(org.folio.services.exceptions.RawChunkRecordsParsingException) RecordsPublishingException(org.folio.services.exceptions.RecordsPublishingException) Event(org.folio.rest.jaxrs.model.Event) List(java.util.List) Record(org.folio.rest.jaxrs.model.Record) KafkaConsumerRecord(io.vertx.kafka.client.consumer.KafkaConsumerRecord) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) KafkaHeader(io.vertx.kafka.client.producer.KafkaHeader)

Example 3 with RawRecordsDto

use of org.folio.rest.jaxrs.model.RawRecordsDto in project mod-source-record-manager by folio-org.

the class ChangeManagerAPITest method fillInRecordOrderIfAtLeastOneRecordHasNoOrder.

private void fillInRecordOrderIfAtLeastOneRecordHasNoOrder(String rawRecord) throws InterruptedException {
    RawRecordsDto rawRecordsDto = new RawRecordsDto().withId(UUID.randomUUID().toString()).withRecordsMetadata(new RecordsMetadata().withLast(true).withCounter(7).withContentType(RecordsMetadata.ContentType.MARC_RAW)).withInitialRecords(asList(new InitialRecord().withRecord(CORRECT_RAW_RECORD_1), new InitialRecord().withRecord(CORRECT_RAW_RECORD_2).withOrder(5), new InitialRecord().withRecord(rawRecord).withOrder(6)));
    InitJobExecutionsRsDto response = constructAndPostInitJobExecutionRqDto(1);
    List<JobExecution> createdJobExecutions = response.getJobExecutions();
    assertThat(createdJobExecutions.size(), is(1));
    JobExecution jobExec = createdJobExecutions.get(0);
    RestAssured.given().spec(spec).body(new JobProfileInfo().withName("MARC records").withId(DEFAULT_JOB_PROFILE_ID).withDataType(DataType.MARC)).when().put(JOB_EXECUTION_PATH + jobExec.getId() + JOB_PROFILE_PATH).then().statusCode(HttpStatus.SC_OK);
    RestAssured.given().spec(spec).body(rawRecordsDto).when().post(JOB_EXECUTION_PATH + jobExec.getId() + RECORDS_PATH).then().statusCode(HttpStatus.SC_NO_CONTENT);
    String topicToObserve = formatToKafkaTopicName(DI_RAW_RECORDS_CHUNK_PARSED.value());
    List<String> observedValues = kafkaCluster.observeValues(ObserveKeyValues.on(topicToObserve, 1).observeFor(30, TimeUnit.SECONDS).build());
    Event obtainedEvent = Json.decodeValue(observedValues.get(0), Event.class);
    assertEquals(DI_RAW_RECORDS_CHUNK_PARSED.value(), obtainedEvent.getEventType());
    RecordCollection processedRecords = Json.decodeValue(obtainedEvent.getEventPayload(), RecordCollection.class);
    assertEquals(3, processedRecords.getRecords().size());
    assertEquals(4, processedRecords.getRecords().get(0).getOrder().intValue());
    assertEquals(5, processedRecords.getRecords().get(1).getOrder().intValue());
    assertEquals(6, processedRecords.getRecords().get(2).getOrder().intValue());
}
Also used : JobExecution(org.folio.rest.jaxrs.model.JobExecution) InitialRecord(org.folio.rest.jaxrs.model.InitialRecord) JobProfileInfo(org.folio.rest.jaxrs.model.JobProfileInfo) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) RecordCollection(org.folio.rest.jaxrs.model.RecordCollection) RecordsMetadata(org.folio.rest.jaxrs.model.RecordsMetadata) Event(org.folio.rest.jaxrs.model.Event) InitJobExecutionsRsDto(org.folio.rest.jaxrs.model.InitJobExecutionsRsDto) Matchers.containsString(org.hamcrest.Matchers.containsString)

Example 4 with RawRecordsDto

use of org.folio.rest.jaxrs.model.RawRecordsDto in project mod-source-record-manager by folio-org.

the class ChangeManagerImpl method postChangeManagerJobExecutionsRecordsById.

@Override
public void postChangeManagerJobExecutionsRecordsById(String id, RawRecordsDto entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
    vertxContext.runOnContext(v -> {
        try {
            okapiHeaders.put(CHUNK_ID_HEADER, entity.getId());
            OkapiConnectionParams params = new OkapiConnectionParams(okapiHeaders, vertxContext.owner());
            eventDrivenChunkProcessingService.processChunk(entity, id, params).map(processed -> PostChangeManagerJobExecutionsRecordsByIdResponse.respond204()).map(Response.class::cast).otherwise(ExceptionHelper::mapExceptionToResponse).onComplete(asyncResultHandler);
        } catch (Exception e) {
            LOGGER.error(getMessage("Failed to process chunk of RawRecords with JobExecution id {}", e, id));
            asyncResultHandler.handle(Future.succeededFuture(ExceptionHelper.mapExceptionToResponse(e)));
        }
    });
}
Also used : Autowired(org.springframework.beans.factory.annotation.Autowired) Context(io.vertx.core.Context) ParameterizedMessage(org.apache.logging.log4j.message.ParameterizedMessage) DeleteJobExecutionsReq(org.folio.rest.jaxrs.model.DeleteJobExecutionsReq) SpringContextUtil(org.folio.spring.SpringContextUtil) ExceptionHelper(org.folio.dataimport.util.ExceptionHelper) JobExecution(org.folio.rest.jaxrs.model.JobExecution) JobProfileInfo(org.folio.rest.jaxrs.model.JobProfileInfo) Map(java.util.Map) Qualifier(org.springframework.beans.factory.annotation.Qualifier) AsyncResult(io.vertx.core.AsyncResult) InitJobExecutionsRqDto(org.folio.rest.jaxrs.model.InitJobExecutionsRqDto) StatusDto(org.folio.rest.jaxrs.model.StatusDto) ChangeManager(org.folio.rest.jaxrs.resource.ChangeManager) Vertx(io.vertx.core.Vertx) Future(io.vertx.core.Future) ParsedRecordDto(org.folio.rest.jaxrs.model.ParsedRecordDto) TenantTool(org.folio.rest.tools.utils.TenantTool) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) NotFoundException(javax.ws.rs.NotFoundException) String.format(java.lang.String.format) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) JobExecutionService(org.folio.services.JobExecutionService) Logger(org.apache.logging.log4j.Logger) ChunkProcessingService(org.folio.services.ChunkProcessingService) Response(javax.ws.rs.core.Response) JobExecutionsCache(org.folio.services.JobExecutionsCache) ParsedRecordService(org.folio.services.ParsedRecordService) Handler(io.vertx.core.Handler) LogManager(org.apache.logging.log4j.LogManager) Response(javax.ws.rs.core.Response) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) NotFoundException(javax.ws.rs.NotFoundException)

Example 5 with RawRecordsDto

use of org.folio.rest.jaxrs.model.RawRecordsDto in project mod-source-record-manager by folio-org.

the class ChangeEngineServiceImpl method parseRawRecordsChunkForJobExecution.

@Override
public Future<List<Record>> parseRawRecordsChunkForJobExecution(RawRecordsDto chunk, JobExecution jobExecution, String sourceChunkId, OkapiConnectionParams params) {
    Promise<List<Record>> promise = Promise.promise();
    Future<List<Record>> futureParsedRecords = parseRecords(chunk.getInitialRecords(), chunk.getRecordsMetadata().getContentType(), jobExecution, sourceChunkId, params.getTenantId(), params);
    futureParsedRecords.compose(parsedRecords -> ensureMappingMetaDataSnapshot(jobExecution.getId(), parsedRecords, params).map(parsedRecords)).onSuccess(parsedRecords -> {
        fillParsedRecordsWithAdditionalFields(parsedRecords);
        if (updateMarcActionExists(jobExecution)) {
            updateRecords(parsedRecords, jobExecution, params).onSuccess(ar -> promise.complete(parsedRecords)).onFailure(promise::fail);
        } else if (deleteMarcActionExists(jobExecution)) {
            deleteRecords(parsedRecords, jobExecution, params).onSuccess(ar -> promise.complete(parsedRecords)).onFailure(promise::fail);
        } else {
            saveRecords(params, jobExecution, parsedRecords).onComplete(postAr -> {
                if (postAr.failed()) {
                    StatusDto statusDto = new StatusDto().withStatus(StatusDto.Status.ERROR).withErrorStatus(StatusDto.ErrorStatus.RECORD_UPDATE_ERROR);
                    jobExecutionService.updateJobExecutionStatus(jobExecution.getId(), statusDto, params).onComplete(r -> {
                        if (r.failed()) {
                            LOGGER.error("Error during update jobExecution and snapshot status", r.cause());
                        }
                    });
                    jobExecutionSourceChunkDao.getById(sourceChunkId, params.getTenantId()).compose(optional -> optional.map(sourceChunk -> jobExecutionSourceChunkDao.update(sourceChunk.withState(JobExecutionSourceChunk.State.ERROR), params.getTenantId())).orElseThrow(() -> new NotFoundException(String.format("Couldn't update failed jobExecutionSourceChunk status to ERROR, jobExecutionSourceChunk with id %s was not found", sourceChunkId)))).onComplete(ar -> promise.fail(postAr.cause()));
                } else {
                    promise.complete(parsedRecords);
                }
            });
        }
    }).onFailure(th -> {
        LOGGER.error("Error parsing records: {}", th.getMessage());
        promise.fail(th);
    });
    return promise.future();
}
Also used : StringUtils(org.apache.commons.lang.StringUtils) MutableInt(org.apache.commons.lang3.mutable.MutableInt) TAG_999(org.folio.services.afterprocessing.AdditionalFieldsUtil.TAG_999) Autowired(org.springframework.beans.factory.annotation.Autowired) RecordAnalyzer(org.folio.dataimport.util.marc.RecordAnalyzer) MARC_HOLDING(org.folio.rest.jaxrs.model.Record.RecordType.MARC_HOLDING) RecordType(org.folio.rest.jaxrs.model.Record.RecordType) ProfileSnapshotWrapper(org.folio.rest.jaxrs.model.ProfileSnapshotWrapper) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MarcRecordAnalyzer(org.folio.dataimport.util.marc.MarcRecordAnalyzer) Map(java.util.Map) JobExecutionSourceChunkDao(org.folio.dao.JobExecutionSourceChunkDao) JobExecution(org.folio.rest.jaxrs.model.JobExecution) RecordParserBuilder(org.folio.services.parsers.RecordParserBuilder) JsonObject(io.vertx.core.json.JsonObject) DI_ERROR(org.folio.rest.jaxrs.model.DataImportEventTypes.DI_ERROR) AdditionalFieldsUtil.getValue(org.folio.services.afterprocessing.AdditionalFieldsUtil.getValue) InitialRecord(org.folio.rest.jaxrs.model.InitialRecord) StatusDto(org.folio.rest.jaxrs.model.StatusDto) MODULE_SPECIFIC_ARGS(org.folio.rest.RestVerticle.MODULE_SPECIFIC_ARGS) AdditionalFieldsUtil.getControlFieldValue(org.folio.services.afterprocessing.AdditionalFieldsUtil.getControlFieldValue) Collection(java.util.Collection) EventHandlingUtil.sendEventToKafka(org.folio.services.util.EventHandlingUtil.sendEventToKafka) UUID(java.util.UUID) JobExecutionSourceChunk(org.folio.rest.jaxrs.model.JobExecutionSourceChunk) RecordCollection(org.folio.rest.jaxrs.model.RecordCollection) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) String.format(java.lang.String.format) NotFoundException(javax.ws.rs.NotFoundException) OkapiConnectionParams(org.folio.dataimport.util.OkapiConnectionParams) KafkaHeaderImpl(io.vertx.kafka.client.producer.impl.KafkaHeaderImpl) FolioRecord(org.folio.rest.jaxrs.model.ActionProfile.FolioRecord) Objects(java.util.Objects) List(java.util.List) StringUtils.isNotBlank(org.apache.commons.lang3.StringUtils.isNotBlank) Logger(org.apache.logging.log4j.Logger) DI_MARC_FOR_UPDATE_RECEIVED(org.folio.rest.jaxrs.model.DataImportEventTypes.DI_MARC_FOR_UPDATE_RECEIVED) KafkaHeaderUtils(org.folio.kafka.KafkaHeaderUtils) ParsedRecord(org.folio.rest.jaxrs.model.ParsedRecord) HrIdFieldService(org.folio.services.afterprocessing.HrIdFieldService) Json(io.vertx.core.json.Json) DI_RAW_RECORDS_CHUNK_PARSED(org.folio.rest.jaxrs.model.DataImportEventTypes.DI_RAW_RECORDS_CHUNK_PARSED) DataImportEventPayload(org.folio.rest.jaxrs.model.DataImportEventPayload) RawRecord(org.folio.rest.jaxrs.model.RawRecord) HashMap(java.util.HashMap) RecordsMetadata(org.folio.rest.jaxrs.model.RecordsMetadata) Function(java.util.function.Function) CollectionUtils(org.apache.commons.collections4.CollectionUtils) ArrayList(java.util.ArrayList) DI_MARC_FOR_DELETE_RECEIVED(org.folio.rest.jaxrs.model.DataImportEventTypes.DI_MARC_FOR_DELETE_RECEIVED) Value(org.springframework.beans.factory.annotation.Value) MARC_AUTHORITY(org.folio.rest.jaxrs.model.Record.RecordType.MARC_AUTHORITY) CompositeFuture(io.vertx.core.CompositeFuture) IterableUtils(org.apache.commons.collections4.IterableUtils) DataType(org.folio.rest.jaxrs.model.JobProfileInfo.DataType) Lists(com.google.common.collect.Lists) Action(org.folio.rest.jaxrs.model.ActionProfile.Action) ExternalIdsHolder(org.folio.rest.jaxrs.model.ExternalIdsHolder) Service(org.springframework.stereotype.Service) AdditionalFieldsUtil.addFieldToMarcRecord(org.folio.services.afterprocessing.AdditionalFieldsUtil.addFieldToMarcRecord) SourceStorageBatchClient(org.folio.rest.client.SourceStorageBatchClient) ActionProfile(org.folio.rest.jaxrs.model.ActionProfile) EntityType(org.folio.rest.jaxrs.model.EntityType) Record(org.folio.rest.jaxrs.model.Record) ParsedResult(org.folio.services.parsers.ParsedResult) RecordConversionUtil(org.folio.services.util.RecordConversionUtil) Promise(io.vertx.core.Promise) AdditionalFieldsUtil.hasIndicator(org.folio.services.afterprocessing.AdditionalFieldsUtil.hasIndicator) RawRecordsDto(org.folio.rest.jaxrs.model.RawRecordsDto) MARC_BIB(org.folio.rest.jaxrs.model.Record.RecordType.MARC_BIB) SUBFIELD_S(org.folio.services.afterprocessing.AdditionalFieldsUtil.SUBFIELD_S) StringUtils.isBlank(org.apache.commons.lang3.StringUtils.isBlank) ErrorRecord(org.folio.rest.jaxrs.model.ErrorRecord) SUBFIELD_I(org.folio.services.afterprocessing.AdditionalFieldsUtil.SUBFIELD_I) MarcRecordType(org.folio.dataimport.util.marc.MarcRecordType) Collections(java.util.Collections) KafkaHeader(io.vertx.kafka.client.producer.KafkaHeader) LogManager(org.apache.logging.log4j.LogManager) KafkaConfig(org.folio.kafka.KafkaConfig) StatusDto(org.folio.rest.jaxrs.model.StatusDto) NotFoundException(javax.ws.rs.NotFoundException) List(java.util.List) ArrayList(java.util.ArrayList)

Aggregations

RawRecordsDto (org.folio.rest.jaxrs.model.RawRecordsDto)31 JobExecution (org.folio.rest.jaxrs.model.JobExecution)25 Test (org.junit.Test)25 OkapiConnectionParams (org.folio.dataimport.util.OkapiConnectionParams)15 JsonObject (io.vertx.core.json.JsonObject)14 InitialRecord (org.folio.rest.jaxrs.model.InitialRecord)14 RecordsMetadata (org.folio.rest.jaxrs.model.RecordsMetadata)14 Future (io.vertx.core.Future)13 AbstractRestTest (org.folio.rest.impl.AbstractRestTest)13 JobProfileInfo (org.folio.rest.jaxrs.model.JobProfileInfo)13 Vertx (io.vertx.core.Vertx)12 HashMap (java.util.HashMap)12 List (java.util.List)12 Async (io.vertx.ext.unit.Async)11 Collections (java.util.Collections)11 UUID (java.util.UUID)11 MarcRecordAnalyzer (org.folio.dataimport.util.marc.MarcRecordAnalyzer)11 JobExecutionSourceChunk (org.folio.rest.jaxrs.model.JobExecutionSourceChunk)11 Optional (java.util.Optional)10 WireMock (com.github.tomakehurst.wiremock.client.WireMock)9