This is an automated email from the ASF dual-hosted git repository.

dockerzhang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-inlong.git


The following commit(s) were added to refs/heads/master by this push:
     new 47f19b3  [INLONG-2077] sort-sdk change pulsar consume mode from 
listener to fetch (#2142)
47f19b3 is described below

commit 47f19b32cf85f8e360c0e870ece6fc4a8b47a47f
Author: wardli <[email protected]>
AuthorDate: Mon Jan 17 19:43:16 2022 +0800

    [INLONG-2077] sort-sdk change pulsar consume mode from listener to fetch 
(#2142)
---
 .../apache/inlong/sdk/sort/api/ClientContext.java  |   7 +
 .../inlong/sdk/sort/api/InLongTopicFetcher.java    |  11 +-
 .../apache/inlong/sdk/sort/api/ReadCallback.java   |   3 +
 .../inlong/sdk/sort/api/SortClientConfig.java      |  37 +++
 .../InLongMessage.java}                            |  26 +-
 .../inlong/sdk/sort/entity/MessageRecord.java      |  21 +-
 .../sdk/sort/impl/InLongPulsarFetcherImpl.java     | 224 --------------
 .../sdk/sort/impl/InLongTopicManagerImpl.java      |   1 +
 .../sdk/sort/impl/PulsarMessageListener.java       |  97 ------
 .../sort/impl/pulsar/InLongPulsarFetcherImpl.java  | 336 +++++++++++++++++++++
 .../sdk/sort/stat/SortClientStateCounter.java      | 103 +++++--
 .../apache/inlong/sdk/sort/stat/StatManager.java   |   9 +-
 .../sdk/sort/impl/InLongPulsarFetcherImplTest.java |  19 +-
 .../standalone/source/sortsdk/FetchCallback.java   |  44 ++-
 .../standalone/source/sortsdk/SortSdkSource.java   |  25 +-
 .../source/sortsdk/SubscribeFetchResult.java       |  49 ++-
 pom.xml                                            |   8 +-
 17 files changed, 580 insertions(+), 440 deletions(-)

diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ClientContext.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ClientContext.java
index 73a9d5f..060d8fe 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ClientContext.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ClientContext.java
@@ -44,4 +44,11 @@ public abstract class ClientContext implements Cleanable {
         return statManager;
     }
 
+    public void acquireRequestPermit() throws InterruptedException {
+        config.getGlobalInProgressRequest().acquireUninterruptibly();
+    }
+
+    public void releaseRequestPermit() {
+        config.getGlobalInProgressRequest().release();
+    }
 }
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/InLongTopicFetcher.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/InLongTopicFetcher.java
index dfcb725..e2ef03e 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/InLongTopicFetcher.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/InLongTopicFetcher.java
@@ -18,9 +18,6 @@
 package org.apache.inlong.sdk.sort.api;
 
 import org.apache.inlong.sdk.sort.entity.InLongTopic;
-import org.apache.pulsar.client.api.MessageId;
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.client.api.PulsarClientException;
 
 public abstract class InLongTopicFetcher {
 
@@ -32,7 +29,7 @@ public abstract class InLongTopicFetcher {
         this.context = context;
     }
 
-    public abstract boolean init(PulsarClient pulsarClient);
+    public abstract boolean init(Object client);
 
     public abstract void ack(String msgOffset) throws Exception;
 
@@ -53,10 +50,4 @@ public abstract class InLongTopicFetcher {
     public abstract long getConsumedDataSize();
 
     public abstract long getAckedOffset();
-
-    public abstract void seek(long offset) throws Exception;
-
-    public abstract void seek(MessageId messageId) throws 
PulsarClientException;
-
-    public abstract String getFetcherType();
 }
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
index 5f7f810..9306e5c 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
@@ -17,9 +17,12 @@
 
 package org.apache.inlong.sdk.sort.api;
 
+import java.util.List;
 import org.apache.inlong.sdk.sort.entity.MessageRecord;
 
 public interface ReadCallback {
 
     void onFinished(MessageRecord messageRecord);
+
+    void onFinishedBatch(List<MessageRecord> messageRecord);
 }
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/SortClientConfig.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/SortClientConfig.java
index b50eace..116e7e5 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/SortClientConfig.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/SortClientConfig.java
@@ -18,6 +18,7 @@
 package org.apache.inlong.sdk.sort.api;
 
 import java.io.Serializable;
+import java.util.concurrent.Semaphore;
 
 public class SortClientConfig implements Serializable {
 
@@ -31,6 +32,7 @@ public class SortClientConfig implements Serializable {
     private ReadCallback callback;
     private int callbackQueueSize = 100;
     private int pulsarReceiveQueueSize = 2000;
+    private Semaphore globalInProgressRequest = new Semaphore(Short.MAX_VALUE, 
true);
     private String localIp;
     private String appName;
     private String serverName;
@@ -45,6 +47,9 @@ public class SortClientConfig implements Serializable {
     private int ackTimeoutSec = 10;
     private volatile boolean stopConsume = false;
     private boolean isPrometheusEnabled = true;
+    private int emptyPollSleepStepMs = 50;
+    private int maxEmptyPollSleepMs = 500;
+    private int emptyPollTimes = 10;
 
     public SortClientConfig(String sortTaskId, String sortClusterName, 
InLongTopicChangeListener assignmentsListener,
             ConsumeStrategy consumeStrategy, String localIp) {
@@ -155,6 +160,14 @@ public class SortClientConfig implements Serializable {
         this.pulsarReceiveQueueSize = pulsarReceiveQueueSize;
     }
 
+    public Semaphore getGlobalInProgressRequest() {
+        return globalInProgressRequest;
+    }
+
+    public void setGlobalInProgressRequest(Semaphore globalInProgressRequest) {
+        this.globalInProgressRequest = globalInProgressRequest;
+    }
+
     /**
      * get localIp
      *
@@ -237,6 +250,30 @@ public class SortClientConfig implements Serializable {
         isPrometheusEnabled = prometheusEnabled;
     }
 
+    public int getEmptyPollSleepStepMs() {
+        return emptyPollSleepStepMs;
+    }
+
+    public void setEmptyPollSleepStepMs(int emptyPollSleepStepMs) {
+        this.emptyPollSleepStepMs = emptyPollSleepStepMs;
+    }
+
+    public int getMaxEmptyPollSleepMs() {
+        return maxEmptyPollSleepMs;
+    }
+
+    public void setMaxEmptyPollSleepMs(int maxEmptyPollSleepMs) {
+        this.maxEmptyPollSleepMs = maxEmptyPollSleepMs;
+    }
+
+    public int getEmptyPollTimes() {
+        return emptyPollTimes;
+    }
+
+    public void setEmptyPollTimes(int emptyPollTimes) {
+        this.emptyPollTimes = emptyPollTimes;
+    }
+
     /**
      * ConsumeStrategy
      */
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/InLongMessage.java
similarity index 60%
copy from 
inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
copy to 
inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/InLongMessage.java
index 5f7f810..f332812 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/api/ReadCallback.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/InLongMessage.java
@@ -15,11 +15,29 @@
  * limitations under the License.
  */
 
-package org.apache.inlong.sdk.sort.api;
+package org.apache.inlong.sdk.sort.entity;
 
-import org.apache.inlong.sdk.sort.entity.MessageRecord;
+import java.util.Map;
 
-public interface ReadCallback {
+public class InLongMessage {
 
-    void onFinished(MessageRecord messageRecord);
+    private final Map<String, String> msgHeader;
+    private byte[] data;
+
+    public InLongMessage(byte[] data, Map<String, String> msgHeader) {
+        this.data = data;
+        this.msgHeader = msgHeader;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    public Map<String, String> getMsgHeader() {
+        return msgHeader;
+    }
 }
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/MessageRecord.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/MessageRecord.java
index 0abf1f0..6917426 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/MessageRecord.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/entity/MessageRecord.java
@@ -17,22 +17,20 @@
 
 package org.apache.inlong.sdk.sort.entity;
 
-import java.util.Map;
+import java.util.List;
 
 public class MessageRecord {
 
     private final String msgKey;
 
-    private final byte[] message;
-    private final Map<String, String> msgHeader;
+    private final List<InLongMessage> msgs;
 
     private final String offset;
     private final long recTime;
 
-    public MessageRecord(String msgKey, byte[] message, Map<String, String> 
msgHeader, String offset, long recTime) {
+    public MessageRecord(String msgKey, List<InLongMessage> msgs, String 
offset, long recTime) {
         this.msgKey = msgKey;
-        this.message = message;
-        this.msgHeader = msgHeader;
+        this.msgs = msgs;
         this.offset = offset;
         this.recTime = recTime;
     }
@@ -41,12 +39,8 @@ public class MessageRecord {
         return msgKey;
     }
 
-    public byte[] getMessage() {
-        return message;
-    }
-
-    public Map<String, String> getMsgHeader() {
-        return msgHeader;
+    public List<InLongMessage> getMsgs() {
+        return msgs;
     }
 
     public String getOffset() {
@@ -61,8 +55,7 @@ public class MessageRecord {
     public String toString() {
         return "MessageRecord{"
                 + "msgKey='" + msgKey
-                + ", message=" + new String(message)
-                + ", msgHeader=" + msgHeader
+                + ", message=" + String.valueOf(msgs)
                 + ", offset='" + offset
                 + ", recTime=" + recTime
                 + '}';
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImpl.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImpl.java
deleted file mode 100644
index 85c9047..0000000
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImpl.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.inlong.sdk.sort.impl;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import org.apache.inlong.sdk.sort.api.ClientContext;
-import org.apache.inlong.sdk.sort.api.InLongTopicFetcher;
-import org.apache.inlong.sdk.sort.entity.InLongTopic;
-import org.apache.pulsar.client.api.Consumer;
-import org.apache.pulsar.client.api.MessageId;
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.client.api.PulsarClientException;
-import org.apache.pulsar.client.api.Schema;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.shade.org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class InLongPulsarFetcherImpl extends InLongTopicFetcher {
-
-    private final Logger logger = 
LoggerFactory.getLogger(InLongPulsarFetcherImpl.class);
-    private final ReentrantReadWriteLock mainLock = new 
ReentrantReadWriteLock(true);
-    private final ConcurrentHashMap<String, MessageId> offsetCache = new 
ConcurrentHashMap<>();
-    private volatile boolean closed = false;
-    private Consumer<byte[]> consumer;
-    private volatile boolean stopConsume = false;
-
-    public InLongPulsarFetcherImpl(InLongTopic inLongTopic,
-            ClientContext context) {
-        super(inLongTopic, context);
-    }
-
-    @Override
-    public void stopConsume(boolean stopConsume) {
-        this.stopConsume = stopConsume;
-    }
-
-    @Override
-    public boolean isConsumeStop() {
-        return stopConsume;
-    }
-
-    @Override
-    public InLongTopic getInLongTopic() {
-        return inLongTopic;
-    }
-
-    @Override
-    public long getConsumedDataSize() {
-        return 0;
-    }
-
-    @Override
-    public long getAckedOffset() {
-        return 0;
-    }
-
-    @Override
-    public void seek(long offset) throws Exception {
-
-    }
-
-    @Override
-    public void seek(MessageId messageId) throws PulsarClientException {
-        if (consumer != null) {
-            consumer.seek(messageId);
-        }
-    }
-
-    @Override
-    public String getFetcherType() {
-        return inLongTopic.getTopicType();
-    }
-
-    private void ackSucc(String offset) {
-        logger.info("ack succ:{}", offset);
-        offsetCache.remove(offset);
-        
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
-                inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic()).addAckSuccTimes(1);
-    }
-
-    /**
-     * ack Offset
-     *
-     * @param msgOffset String
-     */
-    @Override
-    public void ack(String msgOffset) throws Exception {
-        if (!StringUtils.isEmpty(msgOffset)) {
-            logger.debug("## ack {}", msgOffset);
-            try {
-                if (consumer == null) {
-                    
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
-                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
-                            .addAckFailTimes(1);
-                    logger.error("consumer == null {}", msgOffset);
-                    return;
-                }
-                MessageId messageId = offsetCache.get(msgOffset);
-                if (messageId == null) {
-                    
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
-                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
-                            .addAckFailTimes(1);
-                    logger.error("messageId == null {}", msgOffset);
-                    return;
-                }
-                consumer.acknowledgeAsync(messageId)
-                        .thenAccept(consumer -> ackSucc(msgOffset))
-                        .exceptionally(exception -> {
-                            logger.error("ack fail:{}", msgOffset);
-                            
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
-                                    
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
-                                    .addAckFailTimes(1);
-                            return null;
-                        });
-            } catch (Exception e) {
-                
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
-                        inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic()).addAckFailTimes(1);
-                logger.error(e.getMessage(), e);
-                throw e;
-            }
-        }
-    }
-
-    /**
-     * create and init Consumer
-     *
-     * @return boolean
-     */
-    @Override
-    public boolean init(PulsarClient pulsarClient) {
-        return createConsumer(pulsarClient);
-    }
-
-    private boolean createConsumer(PulsarClient client) {
-        try {
-            consumer = client.newConsumer(Schema.BYTES)
-                    .topic(inLongTopic.getTopic())
-                    .subscriptionName(context.getConfig().getSortTaskId())
-                    .subscriptionType(SubscriptionType.Shared)
-                    .startMessageIdInclusive()
-                    .ackTimeout(context.getConfig().getAckTimeoutSec(), 
TimeUnit.SECONDS)
-                    
.receiverQueueSize(context.getConfig().getPulsarReceiveQueueSize())
-                    .messageListener(new PulsarMessageListener(this, context, 
inLongTopic, offsetCache))
-                    .subscribe();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * current fetcher is closed
-     */
-    public void isValidState() {
-        if (closed) {
-            throw new IllegalStateException(inLongTopic + " closed.");
-        }
-    }
-
-    /**
-     * pause
-     */
-    @Override
-    public void pause() {
-        if (consumer != null) {
-            consumer.pause();
-        }
-    }
-
-    /**
-     * resume
-     */
-    @Override
-    public void resume() {
-        if (consumer != null) {
-            consumer.resume();
-        }
-    }
-
-    @Override
-    public boolean close() {
-        mainLock.writeLock().lock();
-        try {
-            this.closed = true;
-            try {
-                if (consumer != null) {
-                    consumer.close();
-                }
-            } catch (PulsarClientException e) {
-                e.printStackTrace();
-            }
-
-            logger.info("{} closed.", inLongTopic);
-            return true;
-        } finally {
-            mainLock.writeLock().unlock();
-        }
-    }
-
-    @Override
-    public boolean isClosed() {
-        return closed;
-    }
-
-}
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongTopicManagerImpl.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongTopicManagerImpl.java
index 012d6b1..cfbd56c 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongTopicManagerImpl.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/InLongTopicManagerImpl.java
@@ -34,6 +34,7 @@ import org.apache.inlong.sdk.sort.api.InlongTopicTypeEnum;
 import org.apache.inlong.sdk.sort.api.QueryConsumeConfig;
 import org.apache.inlong.sdk.sort.entity.ConsumeConfig;
 import org.apache.inlong.sdk.sort.entity.InLongTopic;
+import org.apache.inlong.sdk.sort.impl.pulsar.InLongPulsarFetcherImpl;
 import org.apache.inlong.sdk.sort.util.PeriodicTask;
 import org.apache.inlong.sdk.sort.util.StringUtil;
 import org.apache.pulsar.client.api.AuthenticationFactory;
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/PulsarMessageListener.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/PulsarMessageListener.java
deleted file mode 100644
index f4afe82..0000000
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/PulsarMessageListener.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.inlong.sdk.sort.impl;
-
-import java.util.Base64;
-import java.util.concurrent.ConcurrentHashMap;
-import org.apache.inlong.sdk.sort.api.ClientContext;
-import org.apache.inlong.sdk.sort.entity.InLongTopic;
-import org.apache.inlong.sdk.sort.entity.MessageRecord;
-import org.apache.pulsar.client.api.Consumer;
-import org.apache.pulsar.client.api.Message;
-import org.apache.pulsar.client.api.MessageId;
-import org.apache.pulsar.client.api.MessageListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class PulsarMessageListener implements MessageListener<byte[]> {
-
-    private final Logger logger = 
LoggerFactory.getLogger(PulsarMessageListener.class);
-
-    private final ClientContext clientContext;
-    private final InLongTopic inLongTopic;
-    private final InLongPulsarFetcherImpl inLongTopicInFetcher;
-    private final ConcurrentHashMap<String, MessageId> offsetCache;
-
-    public PulsarMessageListener(InLongPulsarFetcherImpl inLongTopicInFetcher, 
ClientContext clientContext,
-            InLongTopic inLongTopic, ConcurrentHashMap<String, MessageId> 
offsetCache) {
-        this.inLongTopicInFetcher = inLongTopicInFetcher;
-        this.clientContext = clientContext;
-        this.inLongTopic = inLongTopic;
-        this.offsetCache = offsetCache;
-    }
-
-    /**
-     * put the received msg to onFinished method
-     *
-     * @param messageRecord MessageRecord
-     */
-    public void handleMsg(MessageRecord messageRecord) {
-        long start = System.currentTimeMillis();
-        try {
-            clientContext.getConfig().getCallback().onFinished(messageRecord);
-            clientContext.getStatManager()
-                    .getStatistics(clientContext.getConfig().getSortTaskId(),
-                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
-                    .addCallbackTimeCost(System.currentTimeMillis() - 
start).addCallbackDoneTimes(1);
-        } catch (Exception e) {
-            clientContext.getStatManager()
-                    .getStatistics(clientContext.getConfig().getSortTaskId(),
-                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
-                    .addCallbackErrorTimes(1);
-            throw e;
-        }
-    }
-
-    @Override
-    public void received(Consumer<byte[]> consumer, Message<byte[]> msg) {
-        String offsetKey;
-        try {
-            inLongTopicInFetcher.isValidState();
-            clientContext.getStatManager()
-                    .getStatistics(clientContext.getConfig().getSortTaskId(),
-                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
-                    
.addConsumeSize(msg.getData().length).addCallbackTimes(1).addMsgCount(1);
-
-            offsetKey = getOffset(msg.getMessageId());
-            offsetCache.put(offsetKey, msg.getMessageId());
-            callbackMessageRecord(msg, offsetKey);
-        } catch (Exception e) {
-            logger.error(e.getMessage(), e);
-        }
-    }
-
-    private void callbackMessageRecord(Message<byte[]> msg, String offsetKey) {
-        handleMsg(new MessageRecord(inLongTopic.getTopicKey(), msg.getData(), 
msg.getProperties(),
-                offsetKey, System.currentTimeMillis()));
-    }
-
-    private String getOffset(MessageId msgId) {
-        return Base64.getEncoder().encodeToString(msgId.toByteArray());
-    }
-}
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/pulsar/InLongPulsarFetcherImpl.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/pulsar/InLongPulsarFetcherImpl.java
new file mode 100644
index 0000000..ad463e5
--- /dev/null
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/impl/pulsar/InLongPulsarFetcherImpl.java
@@ -0,0 +1,336 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.inlong.sdk.sort.impl.pulsar;
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.inlong.sdk.sort.api.ClientContext;
+import org.apache.inlong.sdk.sort.api.InLongTopicFetcher;
+import org.apache.inlong.sdk.sort.entity.InLongMessage;
+import org.apache.inlong.sdk.sort.entity.InLongTopic;
+import org.apache.inlong.sdk.sort.entity.MessageRecord;
+import org.apache.inlong.sdk.sort.util.StringUtil;
+import org.apache.pulsar.client.api.Consumer;
+import org.apache.pulsar.client.api.Message;
+import org.apache.pulsar.client.api.MessageId;
+import org.apache.pulsar.client.api.Messages;
+import org.apache.pulsar.client.api.PulsarClient;
+import org.apache.pulsar.client.api.PulsarClientException;
+import org.apache.pulsar.client.api.Schema;
+import org.apache.pulsar.client.api.SubscriptionType;
+import org.apache.pulsar.shade.org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InLongPulsarFetcherImpl extends InLongTopicFetcher {
+
+    private final Logger logger = 
LoggerFactory.getLogger(InLongPulsarFetcherImpl.class);
+    private final ReentrantReadWriteLock mainLock = new 
ReentrantReadWriteLock(true);
+    private final ConcurrentHashMap<String, MessageId> offsetCache = new 
ConcurrentHashMap<>();
+    private volatile boolean closed = false;
+    private Consumer<byte[]> consumer;
+    private volatile boolean stopConsume = false;
+    private volatile Thread fetchThread;
+    private long sleepTime = 0L;
+    private int emptyPollTimes = 0;
+
+    public InLongPulsarFetcherImpl(InLongTopic inLongTopic,
+            ClientContext context) {
+        super(inLongTopic, context);
+    }
+
+    @Override
+    public void stopConsume(boolean stopConsume) {
+        this.stopConsume = stopConsume;
+    }
+
+    @Override
+    public boolean isConsumeStop() {
+        return stopConsume;
+    }
+
+    @Override
+    public InLongTopic getInLongTopic() {
+        return inLongTopic;
+    }
+
+    @Override
+    public long getConsumedDataSize() {
+        return 0;
+    }
+
+    @Override
+    public long getAckedOffset() {
+        return 0;
+    }
+
+    private void ackSucc(String offset) {
+        offsetCache.remove(offset);
+        
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
+                inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic()).addAckSuccTimes(1);
+    }
+
+    /**
+     * ack Offset
+     *
+     * @param msgOffset String
+     */
+    @Override
+    public void ack(String msgOffset) throws Exception {
+        if (!StringUtils.isEmpty(msgOffset)) {
+            try {
+                if (consumer == null) {
+                    
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
+                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
+                            .addAckFailTimes(1);
+                    logger.error("consumer == null");
+                    return;
+                }
+                MessageId messageId = offsetCache.get(msgOffset);
+                if (messageId == null) {
+                    
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
+                            inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
+                            .addAckFailTimes(1);
+                    logger.error("messageId == null");
+                    return;
+                }
+                consumer.acknowledgeAsync(messageId)
+                        .thenAccept(consumer -> ackSucc(msgOffset))
+                        .exceptionally(exception -> {
+                            logger.error("ack fail:{}", msgOffset);
+                            
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
+                                    
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                                    .addAckFailTimes(1);
+                            return null;
+                        });
+            } catch (Exception e) {
+                
context.getStatManager().getStatistics(context.getConfig().getSortTaskId(),
+                        inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic()).addAckFailTimes(1);
+                logger.error(e.getMessage(), e);
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * create Consumer and fetch thread
+     *
+     * @return boolean
+     */
+    @Override
+    public boolean init(Object object) {
+        PulsarClient pulsarClient = (PulsarClient) object;
+        return createConsumer(pulsarClient);
+    }
+
+    private boolean createConsumer(PulsarClient client) {
+        try {
+            consumer = client.newConsumer(Schema.BYTES)
+                    .topic(inLongTopic.getTopic())
+                    .subscriptionName(context.getConfig().getSortTaskId())
+                    .subscriptionType(SubscriptionType.Shared)
+                    .startMessageIdInclusive()
+                    .ackTimeout(10, TimeUnit.SECONDS)
+                    
.receiverQueueSize(context.getConfig().getPulsarReceiveQueueSize())
+                    .subscribe();
+
+            String threadName = "sort_sdk_fetch_thread_" + 
StringUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
+            this.fetchThread = new Thread(new Fetcher(), threadName);
+            this.fetchThread.start();
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * isValidState
+     */
+    public void isValidState() {
+        if (closed) {
+            throw new IllegalStateException(inLongTopic + " closed.");
+        }
+    }
+
+    /**
+     * pause
+     */
+    @Override
+    public void pause() {
+        if (consumer != null) {
+            consumer.pause();
+        }
+    }
+
+    /**
+     * resume
+     */
+    @Override
+    public void resume() {
+        if (consumer != null) {
+            consumer.resume();
+        }
+    }
+
+    /**
+     * close
+     *
+     * @return true/false
+     */
+    @Override
+    public boolean close() {
+        mainLock.writeLock().lock();
+        try {
+            this.closed = true;
+            try {
+                if (consumer != null) {
+                    consumer.close();
+                }
+                if (fetchThread != null) {
+                    fetchThread.interrupt();
+                }
+            } catch (PulsarClientException e) {
+                e.printStackTrace();
+            }
+
+            logger.info("closed {}", inLongTopic);
+            return true;
+        } finally {
+            mainLock.writeLock().unlock();
+        }
+    }
+
+    @Override
+    public boolean isClosed() {
+        return closed;
+    }
+
+    public class Fetcher implements Runnable {
+
+        /**
+         * put the received msg to onFinished method
+         *
+         * @param messageRecords {@link List<MessageRecord>}
+         */
+        private void handleAndCallbackMsg(List<MessageRecord> messageRecords) {
+            long start = System.currentTimeMillis();
+            try {
+                context.getStatManager()
+                        .getStatistics(context.getConfig().getSortTaskId(),
+                                inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
+                        .addCallbackTimes(1);
+                
context.getConfig().getCallback().onFinishedBatch(messageRecords);
+                context.getStatManager()
+                        .getStatistics(context.getConfig().getSortTaskId(),
+                                inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
+                        .addCallbackTimeCost(System.currentTimeMillis() - 
start).addCallbackDoneTimes(1);
+            } catch (Exception e) {
+                context.getStatManager()
+                        .getStatistics(context.getConfig().getSortTaskId(),
+                                inLongTopic.getInLongCluster().getClusterId(), 
inLongTopic.getTopic())
+                        .addCallbackErrorTimes(1);
+                e.printStackTrace();
+            }
+        }
+
+        private String getOffset(MessageId msgId) {
+            return Base64.getEncoder().encodeToString(msgId.toByteArray());
+        }
+
+        @Override
+        public void run() {
+            boolean hasPermit;
+            while (true) {
+                hasPermit = false;
+                try {
+                    if (context.getConfig().isStopConsume() || stopConsume) {
+                        TimeUnit.MILLISECONDS.sleep(50);
+                        continue;
+                    }
+
+                    if (sleepTime > 0) {
+                        TimeUnit.MILLISECONDS.sleep(sleepTime);
+                    }
+
+                    context.acquireRequestPermit();
+                    hasPermit = true;
+                    context.getStatManager()
+                            .getStatistics(context.getConfig().getSortTaskId(),
+                                    
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                            .addMsgCount(1).addFetchTimes(1);
+
+                    long startFetchTime = System.currentTimeMillis();
+                    Messages<byte[]> messages = consumer.batchReceive();
+                    context.getStatManager()
+                            .getStatistics(context.getConfig().getSortTaskId(),
+                                    
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                            .addFetchTimeCost(System.currentTimeMillis() - 
startFetchTime);
+                    if (null != messages && messages.size() != 0) {
+                        List<MessageRecord> msgs = new ArrayList<>();
+                        for (Message<byte[]> msg : messages) {
+                            String offsetKey = getOffset(msg.getMessageId());
+                            offsetCache.put(offsetKey, msg.getMessageId());
+
+                            msgs.add(new 
MessageRecord(inLongTopic.getTopicKey(),
+                                    Collections.singletonList(new 
InLongMessage(msg.getData(), msg.getProperties())),
+                                    offsetKey, System.currentTimeMillis()));
+                            context.getStatManager()
+                                    
.getStatistics(context.getConfig().getSortTaskId(),
+                                            
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                                    .addConsumeSize(msg.getData().length);
+                        }
+                        context.getStatManager()
+                                
.getStatistics(context.getConfig().getSortTaskId(),
+                                        
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                                .addMsgCount(msgs.size());
+                        handleAndCallbackMsg(msgs);
+                        sleepTime = 0L;
+                    } else {
+                        context.getStatManager()
+                                
.getStatistics(context.getConfig().getSortTaskId(),
+                                        
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                                .addEmptyFetchTimes(1);
+                        emptyPollTimes++;
+                        if (emptyPollTimes >= 
context.getConfig().getEmptyPollTimes()) {
+                            sleepTime = Math.min((sleepTime += 
context.getConfig().getEmptyPollSleepStepMs()),
+                                    
context.getConfig().getMaxEmptyPollSleepMs());
+                            emptyPollTimes = 0;
+                        }
+                    }
+                } catch (Exception e) {
+                    context.getStatManager()
+                            .getStatistics(context.getConfig().getSortTaskId(),
+                                    
inLongTopic.getInLongCluster().getClusterId(), inLongTopic.getTopic())
+                            .addFetchErrorTimes(1);
+                    logger.error(e.getMessage(), e);
+                } finally {
+                    if (hasPermit) {
+                        context.releaseRequestPermit();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/SortClientStateCounter.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/SortClientStateCounter.java
index 5fe1c75..e9352b6 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/SortClientStateCounter.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/SortClientStateCounter.java
@@ -45,7 +45,7 @@ public class SortClientStateCounter {
     /**
      * reset Counter
      *
-     * @return SortClientStateCounter
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter reset() {
         SortClientStateCounter counter = new 
SortClientStateCounter(sortTaskId, cacheClusterId, topic, partitionId);
@@ -72,7 +72,7 @@ public class SortClientStateCounter {
      * consume byte size
      *
      * @param num long byte
-     * @return SortClientStateCounter
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addConsumeSize(long num) {
         count.getAndAdd(0, num);
@@ -82,8 +82,8 @@ public class SortClientStateCounter {
     /**
      * count receive event num
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addMsgCount(long num) {
         count.getAndAdd(1, num);
@@ -93,8 +93,8 @@ public class SortClientStateCounter {
     /**
      * count callbak times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addCallbackTimes(long num) {
         count.getAndAdd(2, num);
@@ -104,8 +104,8 @@ public class SortClientStateCounter {
     /**
      * count callbak done times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addCallbackDoneTimes(long num) {
         count.getAndAdd(3, num);
@@ -116,7 +116,7 @@ public class SortClientStateCounter {
      * count callbak time cost
      *
      * @param num long
-     * @return SortClientStateCounter
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addCallbackTimeCost(long num) {
         count.getAndAdd(4, num);
@@ -126,8 +126,8 @@ public class SortClientStateCounter {
     /**
      * count callbak error times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addCallbackErrorTimes(long num) {
         count.getAndAdd(5, num);
@@ -137,8 +137,8 @@ public class SortClientStateCounter {
     /**
      * count topic online times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addTopicOnlineTimes(long num) {
         count.getAndAdd(6, num);
@@ -148,8 +148,8 @@ public class SortClientStateCounter {
     /**
      * count topic offline times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addTopicOfflineTimes(long num) {
         count.getAndAdd(7, num);
@@ -159,8 +159,8 @@ public class SortClientStateCounter {
     /**
      * count ack fail times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addAckFailTimes(long num) {
         count.getAndAdd(8, num);
@@ -170,8 +170,8 @@ public class SortClientStateCounter {
     /**
      * count ack succ times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addAckSuccTimes(long num) {
         count.getAndAdd(9, num);
@@ -181,8 +181,8 @@ public class SortClientStateCounter {
     /**
      * count request manager times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addRequestManagerTimes(long num) {
         count.getAndAdd(10, num);
@@ -193,7 +193,7 @@ public class SortClientStateCounter {
      * count request manager time cost
      *
      * @param num long
-     * @return SortClientStateCounter
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addRequestManagerTimeCost(long num) {
         count.getAndAdd(11, num);
@@ -203,8 +203,8 @@ public class SortClientStateCounter {
     /**
      * count request manager fail times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addRequestManagerFailTimes(long num) {
         count.getAndAdd(12, num);
@@ -214,8 +214,8 @@ public class SortClientStateCounter {
     /**
      * count manager conf changed times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addManagerConfChangedTimes(long num) {
         count.getAndAdd(13, num);
@@ -225,8 +225,8 @@ public class SortClientStateCounter {
     /**
      * count manager result code common error times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addRequestManagerCommonErrorTimes(long num) {
         count.getAndAdd(14, num);
@@ -236,12 +236,55 @@ public class SortClientStateCounter {
     /**
      * count manager result param error times
      *
-     * @param num int
-     * @return SortClientStateCounter
+     * @param num long
+     * @return {@link SortClientStateCounter}
      */
     public SortClientStateCounter addRequestManagerParamErrorTimes(long num) {
         count.getAndAdd(15, num);
         return this;
     }
 
+    /**
+     * count thread fetch times
+     *
+     * @param num long
+     * @return {@link SortClientStateCounter}
+     */
+    public SortClientStateCounter addFetchTimes(long num) {
+        count.getAndAdd(16, num);
+        return this;
+    }
+
+    /**
+     * count fetch error times
+     *
+     * @param num long
+     * @return {@link SortClientStateCounter}
+     */
+    public SortClientStateCounter addFetchErrorTimes(long num) {
+        count.getAndAdd(17, num);
+        return this;
+    }
+
+    /**
+     * count empty fetch times
+     *
+     * @param num long
+     * @return {@link SortClientStateCounter}
+     */
+    public SortClientStateCounter addEmptyFetchTimes(long num) {
+        count.getAndAdd(18, num);
+        return this;
+    }
+
+    /**
+     * count fetch time cost
+     *
+     * @param num long
+     * @return {@link SortClientStateCounter}
+     */
+    public SortClientStateCounter addFetchTimeCost(long num) {
+        count.getAndAdd(19, num);
+        return this;
+    }
 }
diff --git 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/StatManager.java
 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/StatManager.java
index b4ca542..cfa9ad6 100644
--- 
a/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/StatManager.java
+++ 
b/inlong-sdk/sort-sdk/src/main/java/org/apache/inlong/sdk/sort/stat/StatManager.java
@@ -41,8 +41,8 @@ public class StatManager implements Cleanable {
     /**
      * StatManager Constructor
      *
-     * @param context ClientContext
-     * @param reporter MetricReporter
+     * @param context {@link ClientContext}
+     * @param reporter {@link MetricReporter}
      */
     public StatManager(ClientContext context, MetricReporter reporter) {
         this.config = context.getConfig();
@@ -105,7 +105,7 @@ public class StatManager implements Cleanable {
     }
 
     /**
-     * use for
+     * use for common SortClientStateCounter
      *
      * @param sortTaskId String
      * @param clusterId String
@@ -142,9 +142,8 @@ public class StatManager implements Cleanable {
                     }
                 }
             } catch (Exception e) {
-                logger.error("StatManager doWork error" + e.getMessage(), e);
+                logger.error("StatManager doWork error " + e.getMessage(), e);
             }
         }
     }
-
 }
diff --git 
a/inlong-sdk/sort-sdk/src/test/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImplTest.java
 
b/inlong-sdk/sort-sdk/src/test/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImplTest.java
index 19078cd..ca17f58 100644
--- 
a/inlong-sdk/sort-sdk/src/test/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImplTest.java
+++ 
b/inlong-sdk/sort-sdk/src/test/java/org/apache/inlong/sdk/sort/impl/InLongPulsarFetcherImplTest.java
@@ -29,6 +29,7 @@ import org.apache.inlong.sdk.sort.api.InLongTopicFetcher;
 import org.apache.inlong.sdk.sort.api.SortClientConfig;
 import org.apache.inlong.sdk.sort.entity.CacheZoneCluster;
 import org.apache.inlong.sdk.sort.entity.InLongTopic;
+import org.apache.inlong.sdk.sort.impl.pulsar.InLongPulsarFetcherImpl;
 import org.apache.inlong.sdk.sort.stat.SortClientStateCounter;
 import org.apache.inlong.sdk.sort.stat.StatManager;
 import org.apache.pulsar.client.api.Consumer;
@@ -109,17 +110,6 @@ public class InLongPulsarFetcherImplTest {
     }
 
     @Test
-    public void seek() {
-        InLongTopicFetcher inLongTopicFetcher = new 
InLongPulsarFetcherImpl(inLongTopic, clientContext);
-        MessageId messageId = PowerMockito.mock(MessageId.class);
-        try {
-            inLongTopicFetcher.seek(messageId);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    @Test
     public void ack() {
         InLongTopicFetcher inLongTopicFetcher = new 
InLongPulsarFetcherImpl(inLongTopic, clientContext);
         MessageId messageId = PowerMockito.mock(MessageId.class);
@@ -188,11 +178,4 @@ public class InLongPulsarFetcherImplTest {
         boolean closed = inLongTopicFetcher.isClosed();
         Assert.assertTrue(closed);
     }
-
-    @Test
-    public void getFetcherType() {
-        InLongTopicFetcher inLongTopicFetcher = new 
InLongPulsarFetcherImpl(inLongTopic, clientContext);
-        String fetcherType = inLongTopicFetcher.getFetcherType();
-        Assert.assertEquals(inLongTopic.getTopicType(), fetcherType);
-    }
 }
\ No newline at end of file
diff --git 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/FetchCallback.java
 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/FetchCallback.java
index 87ac897..53e96dd 100644
--- 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/FetchCallback.java
+++ 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/FetchCallback.java
@@ -18,28 +18,29 @@
 package org.apache.inlong.sort.standalone.source.sortsdk;
 
 import com.google.common.base.Preconditions;
+import java.util.List;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import org.apache.flume.channel.ChannelProcessor;
 import org.apache.inlong.sdk.sort.api.ReadCallback;
 import org.apache.inlong.sdk.sort.api.SortClient;
+import org.apache.inlong.sdk.sort.entity.InLongMessage;
 import org.apache.inlong.sdk.sort.entity.MessageRecord;
 import org.apache.inlong.sort.standalone.channel.ProfileEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-
 /**
  * Implementation of {@link ReadCallback}.
  *
  * TODO: Sort sdk should deliver one object which is held by {@link 
ProfileEvent} and used to ack upstream data store
  * The code should be like :
  *
- *        public void onFinished(final MessageRecord messageRecord, ACKer 
acker) {
- *            doSomething();
- *            final ProfileEvent profileEvent = new 
ProfileEvent(result.getBody(), result.getHeaders(), acker);
- *             channelProcessor.processEvent(profileEvent);
- *        }
+ * public void onFinished(final MessageRecord messageRecord, ACKer acker) {
+ * doSomething();
+ * final ProfileEvent profileEvent = new ProfileEvent(result.getBody(), 
result.getHeaders(), acker);
+ * channelProcessor.processEvent(profileEvent);
+ * }
  *
  * The ACKer will be used to <b>ACK</b> upstream after that the downstream 
<b>ACKed</b> sort-standalone.
  * This process seems like <b>transaction</b> of the whole sort-standalone, 
and which
@@ -81,6 +82,7 @@ public class FetchCallback implements ReadCallback {
 
     /**
      * Set client for ack.
+     *
      * @param client client for ack.
      */
     public void setClient(@NotNull SortClient client) {
@@ -100,10 +102,17 @@ public class FetchCallback implements ReadCallback {
     public void onFinished(final MessageRecord messageRecord) {
         try {
             Preconditions.checkState(messageRecord != null, "Fetched msg is 
null.");
-            final SubscribeFetchResult result = 
SubscribeFetchResult.Factory.create(sortId, messageRecord);
-            final ProfileEvent profileEvent = new 
ProfileEvent(result.getBody(), result.getHeaders());
-            channelProcessor.processEvent(profileEvent);
-            context.reportToMetric(profileEvent, sortId, "-", 
SortSdkSourceContext.FetchResult.SUCCESS);
+            for (InLongMessage inLongMessage : messageRecord.getMsgs()) {
+                //TODO fix here
+                final SubscribeFetchResult result = 
SubscribeFetchResult.Factory
+                        .create(sortId, messageRecord.getMsgKey(), 
messageRecord.getOffset(),
+                                inLongMessage.getMsgHeader(), 
messageRecord.getRecTime(),
+                                inLongMessage.getData());
+                final ProfileEvent profileEvent = new 
ProfileEvent(result.getBody(), result.getHeaders());
+                channelProcessor.processEvent(profileEvent);
+                context.reportToMetric(profileEvent, sortId, "-", 
SortSdkSourceContext.FetchResult.SUCCESS);
+            }
+
             client.ack(messageRecord.getMsgKey(), messageRecord.getMsgKey());
         } catch (NullPointerException npe) {
             LOG.error("Got a null pointer exception for sortId " + sortId, 
npe);
@@ -114,6 +123,16 @@ public class FetchCallback implements ReadCallback {
     }
 
     /**
+     * The callback function that SortSDK invoke when fetch messages batch
+     *
+     * @param messageRecord {@link List<MessageRecord>}
+     */
+    @Override
+    public void onFinishedBatch(List<MessageRecord> messageRecord) {
+        //TODO
+    }
+
+    /**
      * Factory of {@link FetchCallback}
      */
     public static class Factory {
@@ -125,7 +144,6 @@ public class FetchCallback implements ReadCallback {
          * @param sortId The sortId of fetched message.
          * @param channelProcessor The channelProcessor that put message in 
specific channel.
          * @param context The context to report fetch results.
-         *
          * @return One FetchCallback.
          */
         public static FetchCallback create(
diff --git 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SortSdkSource.java
 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SortSdkSource.java
index abad948..e9a7837 100644
--- 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SortSdkSource.java
+++ 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SortSdkSource.java
@@ -18,6 +18,14 @@
 package org.apache.inlong.sort.standalone.source.sortsdk;
 
 import com.google.common.base.Preconditions;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import org.apache.flume.Context;
 import org.apache.flume.EventDrivenSource;
 import org.apache.flume.conf.Configurable;
@@ -25,21 +33,11 @@ import org.apache.flume.source.AbstractSource;
 import org.apache.inlong.sdk.sort.api.SortClient;
 import org.apache.inlong.sdk.sort.api.SortClientConfig;
 import org.apache.inlong.sdk.sort.api.SortClientFactory;
-import org.apache.inlong.sdk.sort.entity.MessageRecord;
 import org.apache.inlong.sort.standalone.config.holder.SortClusterConfigHolder;
 import org.apache.inlong.sort.standalone.config.pojo.SortTaskConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
 /**
  * Default Source implementation of InLong.
  *
@@ -62,7 +60,7 @@ public final class SortSdkSource extends AbstractSource 
implements Configurable,
     private static final int CORE_POOL_SIZE = 1;
 
     // Default consume strategy of {@link SortClient}.
-    private static final  SortClientConfig.ConsumeStrategy defaultStrategy = 
SortClientConfig.ConsumeStrategy.lastest;
+    private static final SortClientConfig.ConsumeStrategy defaultStrategy = 
SortClientConfig.ConsumeStrategy.lastest;
 
     // Map of {@link SortClient}.
     private Map<String, SortClient> clients;
@@ -133,8 +131,8 @@ public final class SortSdkSource extends AbstractSource 
implements Configurable,
      * <p> Create new clients with new sort task id, and remove the finished 
or scheduled ones. </p>
      *
      * <p> Current version of SortSdk <b>DO NOT</b> support to get the 
corresponding sort id of {@link SortClient}.
-     *  Hence, the maintenance of mapping of <SortId, SortClient> should be 
done by Source itself. Which is not elegant,
-     *  the <b>REMOVE</b> of expire clients will <b>NOT</b> be supported right 
now. </p>
+     * Hence, the maintenance of mapping of <SortId, SortClient> should be 
done by Source itself. Which is not elegant,
+     * the <b>REMOVE</b> of expire clients will <b>NOT</b> be supported right 
now. </p>
      */
     private void reload() {
 
@@ -166,7 +164,6 @@ public final class SortSdkSource extends AbstractSource 
implements Configurable,
      * For more details see {@link FetchCallback#onFinished(MessageRecord)}</p>
      *
      * @param sortId Sort in of new client.
-     *
      * @return New sort client.
      */
     private SortClient newClient(final String sortId) {
diff --git 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SubscribeFetchResult.java
 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SubscribeFetchResult.java
index 638fb07..0c6bc21 100644
--- 
a/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SubscribeFetchResult.java
+++ 
b/inlong-sort-standalone/sort-standalone-source/src/main/java/org/apache/inlong/sort/standalone/source/sortsdk/SubscribeFetchResult.java
@@ -17,13 +17,12 @@
 
 package org.apache.inlong.sort.standalone.source.sortsdk;
 
-import org.apache.inlong.sdk.sort.entity.MessageRecord;
-import org.apache.inlong.sort.standalone.utils.Constants;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import org.apache.inlong.sdk.sort.entity.MessageRecord;
+import org.apache.inlong.sort.standalone.utils.Constants;
 
 /**
  * SubscribeFetchResult is the wrapper of {@link MessageRecord}.
@@ -47,6 +46,7 @@ public class SubscribeFetchResult {
      * @param sortId The sortId of fetched message.
      * @param message Message that fetched from upstream data storage.
      */
+
     private SubscribeFetchResult(
             final String sortId,
             final MessageRecord message) {
@@ -54,12 +54,37 @@ public class SubscribeFetchResult {
         this.headers.put(Constants.HEADER_KEY_MESSAGE_KEY, 
message.getMsgKey());
         this.headers.put(Constants.HEADER_KEY_MSG_OFFSET, message.getOffset());
         this.headers.put(Constants.HEADER_KEY_MSG_TIME, 
String.valueOf(message.getRecTime()));
-        this.headers.putAll(message.getMsgHeader());
-        this.body = message.getMessage();
+        //TODO to fix here
+        this.headers.putAll(null);
+        this.body = null;
+    }
+
+    /**
+     * Private constructor of SubscribeFetchResult.
+     * <p> The construction of SubscribeFetchResult should be initiated by 
{@link SubscribeFetchResult.Factory}.</p>
+     *
+     * @param sortId String
+     * @param msgKey String
+     * @param offset String
+     * @param headers {@link Map<String,String>}
+     * @param recTime long
+     * @param body byte[]
+     */
+    private SubscribeFetchResult(
+            final String sortId,
+            final String msgKey, final String offset, final Map<String, 
String> headers, final long recTime,
+            final byte[] body) {
+        this.sortId = sortId;
+        this.headers.put(Constants.HEADER_KEY_MESSAGE_KEY, msgKey);
+        this.headers.put(Constants.HEADER_KEY_MSG_OFFSET, offset);
+        this.headers.put(Constants.HEADER_KEY_MSG_TIME, 
String.valueOf(recTime));
+        this.headers.putAll(headers);
+        this.body = body;
     }
 
     /**
      * Get row data that in binary format.
+     *
      * @return Row data.
      */
     public byte[] getBody() {
@@ -68,6 +93,7 @@ public class SubscribeFetchResult {
 
     /**
      * Get important metrics in Map format called headers.
+     *
      * @return headers.
      */
     public Map<String, String> getHeaders() {
@@ -76,6 +102,7 @@ public class SubscribeFetchResult {
 
     /**
      * Get sortId of fetched message.
+     *
      * @return SortId of message.
      */
     public String getSortId() {
@@ -93,7 +120,6 @@ public class SubscribeFetchResult {
          *
          * @param sortId The sortId of fetched message.
          * @param messageRecord Message that fetched from upstream data 
storage.
-         *
          * @return One SubscribeFetchResult.
          */
         public static SubscribeFetchResult create(
@@ -101,5 +127,12 @@ public class SubscribeFetchResult {
                 @NotNull(message = "MessageRecord should not be null.") final 
MessageRecord messageRecord) {
             return new SubscribeFetchResult(sortId, messageRecord);
         }
+
+        public static SubscribeFetchResult create(
+                final String sortId,
+                final String msgKey, final String offset, final Map<String, 
String> headers, final long recTime,
+                final byte[] body) {
+            return new SubscribeFetchResult(sortId, msgKey, offset, headers, 
recTime, body);
+        }
     }
 }
diff --git a/pom.xml b/pom.xml
index e8e5112..bf552bb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,8 +33,10 @@
     <version>0.13.0-incubating-SNAPSHOT</version>
     <name>Apache InLong</name>
 
-    <description>InLong is a one-stop data integration framework donated by 
Tencent to the Apache community.
-        It provides automatic, safe, reliable, and high-performance data 
transmission capabilities to
+    <description>InLong is a one-stop data integration framework donated by 
Tencent to the Apache
+        community.
+        It provides automatic, safe, reliable, and high-performance data 
transmission capabilities
+        to
         facilitate the construction of streaming-based data analysis, 
modeling, and applications.
     </description>
     <url>https://github.com/apache/incubator-inlong</url>
@@ -95,10 +97,10 @@
         <module>inlong-agent</module>
         <module>inlong-manager</module>
         <module>inlong-sort</module>
+        <module>inlong-sdk</module>
         <module>inlong-sort-standalone</module>
         <module>inlong-website</module>
         <module>inlong-distribution</module>
-        <module>inlong-sdk</module>
     </modules>
 
 

Reply via email to