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

com.aliyun.datahub.clientlibrary.producer.Producer Maven / Gradle / Ivy

package com.aliyun.datahub.clientlibrary.producer;

import com.aliyun.datahub.client.exception.*;
import com.aliyun.datahub.client.model.RecordEntry;
import com.aliyun.datahub.client.util.FormatUtils;
import com.aliyun.datahub.clientlibrary.config.ProducerConfig;
import com.aliyun.datahub.clientlibrary.models.Assignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Not thread safe
 */
public class Producer {
    private static final Logger LOG = LoggerFactory.getLogger(Producer.class);

    private ShardGroupWriter shardGroupWriter;
    private ShardAssigner shardAssigner;
    private boolean autoAssigned;
    private final AtomicBoolean closed = new AtomicBoolean(false);

    /**
     * Producer perceiving shard change
     * @param projectName The name of project.
     * @param topicName The name of topic.
     * @param config The producer config.
     */
    public Producer(String projectName, String topicName, ProducerConfig config) {
        preCheck(projectName, topicName);
        shardGroupWriter = new ShardGroupWriter(projectName, topicName, config);
        shardAssigner = new ShardAssigner(projectName, topicName, config);
        autoAssigned = true;
    }

    /**
     * Producer with shards specified
     * @param projectName The name of project.
     * @param topicName The name of topic.
     * @param shardIds The shard ids.
     * @param config The producer config.
     */
    public Producer(String projectName, String topicName, List shardIds, ProducerConfig config) {
        preCheck(projectName, topicName, shardIds);
        shardAssigner = new ShardAssigner(projectName, topicName, config);
        if (!shardAssigner.checkAllActive(shardIds)) {
            shardAssigner.close();
            throw new InvalidParameterException("Shard must be valid and active");
        }

        shardGroupWriter = new ShardGroupWriter(projectName, topicName, config);
        shardGroupWriter.createShardWriter(shardIds);
        autoAssigned = false;
    }

    /**
     * Send record list
     * @param records The record list to send.
     * @param maxRetry The max retry times.
     */
    public void send(List records, int maxRetry) {
        if (closed.get()) {
            throw new DatahubClientException("This producer has already been closed");
        }
        if (maxRetry < 0) {
            throw new InvalidParameterException("Retry must not be negative");
        }

        for (int retry = 0; retry <= maxRetry && !closed.get(); ++retry) {
            try {
                syncAssignmentIfNeeded();
                shardGroupWriter.write(records);
                return;
            } catch (MalformedRecordException | InvalidParameterException e) {
                fail(e, true);
            } catch (ShardSealedException | ResourceNotFoundException e) {
                // split/merge sometimes lead to ResourceNotFoundException because of reloading shard
                fail(e, retry == maxRetry);
                shardAssigner.triggerUpdate();
            } catch (DatahubClientException e) {
                fail(e, retry == maxRetry);
            }
        }
        throw new DatahubClientException("Send records failed, retry limit exceeded");
    }

    /**
     * Close to release resource
     */
    public void close() {
        if (closed.compareAndSet(false, true)) {
            shardGroupWriter.close();
            if (shardAssigner != null) {
                shardAssigner.close();
            }
        }
    }

    private void preCheck(String projectName, String topicName) {
        if (!FormatUtils.checkProjectName(projectName)) {
            throw new InvalidParameterException("ProjectName format is invalid");
        }
        if (!FormatUtils.checkTopicName(topicName)) {
            throw new InvalidParameterException("TopicName format is invalid");
        }
    }

    private void preCheck(String projectName, String topicName, List shardIds) {
        preCheck(projectName, topicName);
        if (shardIds == null || shardIds.isEmpty()) {
            shardAssigner.close();
            throw new InvalidParameterException("ShardIds must not be empty");
        }
    }

    private void syncAssignmentIfNeeded() {
        if (!autoAssigned) {
            return;
        }

        Assignment newAssignment = shardAssigner.getNewAssignment();

        shardGroupWriter.createShardWriter(newAssignment.getNewShardList());
        shardGroupWriter.removeShardWriter(newAssignment.getReleaseShardList());
    }

    private void fail(DatahubClientException exception, boolean needThrow) {
        if (needThrow) {
            LOG.error("Send records failed, Exception: {}", exception.getMessage());
            throw exception;
        }
        LOG.warn("Send records failed, will retry, Exception: {}", exception.getMessage());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy