All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.camunda.exporter.store.ExporterBatchWriter Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha2
Show newest version
/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Camunda License 1.0. You may not use this file
 * except in compliance with the Camunda License 1.0.
 */
package io.camunda.exporter.store;

import io.camunda.exporter.exceptions.PersistenceException;
import io.camunda.exporter.handlers.ExportHandler;
import io.camunda.webapps.schema.entities.ExporterEntity;
import io.camunda.zeebe.protocol.record.Record;
import io.camunda.zeebe.protocol.record.RecordValue;
import io.camunda.zeebe.protocol.record.ValueType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/** Caches exporter entities of different types and provide the method to flush them in a batch. */
@SuppressWarnings({"rawtypes", "unchecked"})
public class ExporterBatchWriter {
  private final Map> handlers = new HashMap<>();
  private final Map cachedEntities = new HashMap<>();

  public void addRecord(final Record record) {
    final ValueType valueType = record.getValueType();

    handlers
        .getOrDefault(valueType, Collections.emptyList())
        .forEach(
            handler -> {
              if (handler.handlesRecord(record)) {
                final List entityIds = handler.generateIds(record);
                entityIds.forEach(id -> updateAndCacheEntity(record, handler, id));
              }
            });
  }

  private void updateAndCacheEntity(
      final Record record, final ExportHandler handler, final String id) {
    final var cacheKey = new EntityIdAndEntityType(id, handler.getEntityType());

    final EntityAndHandlers entityAndHandlers =
        cachedEntities.computeIfAbsent(
            cacheKey,
            (k) -> {
              final ExporterEntity entity = handler.createNewEntity(id);
              return new EntityAndHandlers(entity, new LinkedHashSet<>());
            });

    final var entity = entityAndHandlers.entity;
    handler.updateEntity(record, entity);

    // we store all handlers for an entity to make sure not to miss any flushes
    entityAndHandlers.handlers.add(handler);
  }

  public void flush(final BatchRequest batchRequest) throws PersistenceException {
    // some handlers modify the same entity (e.g. list view flow node instances are
    // updated from process instance and incident records)
    //
    // the handler that modified the entity last will also flush it
    if (cachedEntities.isEmpty()) {
      return;
    }

    for (final var entityAndHandler : cachedEntities.values()) {
      final ExporterEntity entity = entityAndHandler.entity();
      for (final var handler : entityAndHandler.handlers()) {
        handler.flush(entity, batchRequest);
      }
    }
    batchRequest.execute();
    reset();
  }

  public void reset() {
    cachedEntities.clear();
  }

  public int getBatchSize() {
    return cachedEntities.size();
  }

  public static class Builder {
    private ExporterBatchWriter writer;

    public static Builder begin() {
      final Builder builder = new Builder();
      builder.writer = new ExporterBatchWriter();
      return builder;
    }

    public , R extends RecordValue> Builder withHandler(
        final ExportHandler handler) {
      writer
          .handlers
          .computeIfAbsent(handler.getHandledValueType(), k -> new ArrayList<>())
          .add(handler);

      return this;
    }

    public ExporterBatchWriter build() {
      return writer;
    }
  }

  private record EntityIdAndEntityType(String entityId, Class entityType) {}

  private record EntityAndHandlers(ExporterEntity entity, Set handlers) {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy