Offset operations

Updated at:

Perform offset operations such as initialization, retrieval, submission, and reset by using the DataHub Java SDK.

Initialization

Call openSubscriptionSession only once. Calling it again generates a new sessionId and invalidates the previous session, making it impossible to commit offsets.

Parameters

Parameter name

Parameter type

Description

projectName

String

The name of the project.

topicName

String

The name of the topic.

subId

String

The id of the subscription.

shardIds

List

The id list of the shards.

Exceptions

Exception class name

Error code

Description

DatahubClientException

-

The base class for all exceptions

InvalidParameterException

InvalidParameter

InvalidCursor

Invalid parameters.

AuthorizationFailureException

Unauthorized

Failed to parse the authorization signature. Verify that the AccessKey is correct.

ResourceNotFoundException

ResourceNotFound

NoSuchProject

NoSuchTopic

NoSuchShard

NoSuchSubscription

NoSuchConnector

NoSuchMeteringInfo

The specified resource does not exist.

Note

This exception may be thrown if you send other requests immediately after performing Split/Merge operations.

Code example

public static void openSubscriptionSession(String projectName, String topicName) {
    shardId = "4";
    shardIds = new ArrayList<String>();
    shardIds.add("0");
    shardIds.add("4");
    try {
        OpenSubscriptionSessionResult openSubscriptionSessionResult = datahubClient.openSubscriptionSession(projectName, topicName, subId, shardIds);
        SubscriptionOffset subscriptionOffset = openSubscriptionSessionResult.getOffsets().get(shardId);
        System.out.println(subscriptionOffset.getSessionId() + "\t"
                + subscriptionOffset.getVersionId() + "\t"
                + subscriptionOffset.getSequence());
    }  catch (DatahubClientException e) {
        System.out.println(e.getErrorMessage());      
    }
}

Get offset

getSubscriptionOffset returns a GetSubscriptionOffsetResult object similar to the result of openSubscriptionSession, but without a sessionId. Use it as a read-only query.

Parameters

Parameter name

Parameter type

Description

projectName

String

The name of the project.

topicName

String

The name of the topic.

subId

String

The id of the subscription.

shardIds

List

The id list of the shards.

Exceptions

Exception class name

Error code

Description

DatahubClientException

-

The base class for all exceptions

InvalidParameterException

InvalidParameter

InvalidCursor

Invalid parameters.

AuthorizationFailureException

Unauthorized

Failed to parse the authorization signature. Verify that the AccessKey is correct.

ResourceNotFoundException

ResourceNotFound

NoSuchProject

NoSuchTopic

NoSuchShard

NoSuchSubscription

NoSuchConnector

NoSuchMeteringInfo

The specified resource does not exist.

Note

This exception may be thrown if you send other requests immediately after performing Split/Merge operations.

Code example

//Get offset
public static void getSubscriptionOffset(String projectName, String topicName,String subId) {
    shardId = "4";
    shardIds = new ArrayList<String>();
    shardIds.add("0");
    shardIds.add("4");
    try {
        GetSubscriptionOffsetResult getSubscriptionOffsetResult = datahubClient.getSubscriptionOffset(projectName, topicName, subId, shardIds);
        SubscriptionOffset subscriptionOffset = getSubscriptionOffsetResult.getOffsets().get(shardId);
        System.out.println(subscriptionOffset.getVersionId() + "\t"
                + subscriptionOffset.getSequence());
    } catch (DatahubClientException e) {
        System.out.println(e.getErrorMessage());

    }
}

Submit offset

When you submit an offset, the system verifies that the versionId and sessionId match the current values. No strict restrictions apply to the offset content. We recommend that you populate the sequence and timestamp from the record.

Parameters

Parameter name

Parameter type

Description

projectName

String

The name of the project.

topicName

String

The name of the topic.

subId

String

The id of the subscription.

offsets

Map

The offset map of shards.

Exceptions

Exception class name

Error code

Description

DatahubClientException

-

The base class for all exceptions

InvalidParameterException

InvalidParameter

InvalidCursor

Invalid parameters.

AuthorizationFailureException

Unauthorized

Failed to parse the authorization signature. Verify that the AccessKey is correct.

ResourceNotFoundException

ResourceNotFound

NoSuchProject

NoSuchTopic

NoSuchShard

NoSuchSubscription

NoSuchConnector

NoSuchMeteringInfo

The specified resource does not exist.

Note

This exception may be thrown if you send other requests immediately after performing Split/Merge operations.

SubscriptionOffsetResetException

OffsetReseted

The subscription offset has been reset.

SubscriptionSessionInvalidException

OffsetSessionChanged

OffsetSessionClosed

The subscription session is invalid. This exception is thrown when another client uses the same subscription, which invalidates the current session.

SubscriptionOfflineException

SubscriptionOffline

The subscription is offline and unavailable.

Code example

//Submit offset
public static void commitSubscriptionOffset(String projectName, String topicName,String subId) {
  while (true) {
      try {
          OpenSubscriptionSessionResult openSubscriptionSessionResult = datahubClient.openSubscriptionSession(projectName, topicName, subId, shardIds);
          SubscriptionOffset subscriptionOffset = openSubscriptionSessionResult.getOffsets().get(shardId);
          //This is just a test for submission, please refer to the offset consumption example for the complete process
          subscriptionOffset.setSequence(10);
          subscriptionOffset.setTimestamp(100);
          Map<String, SubscriptionOffset> offsets = new HashMap<String, SubscriptionOffset>();
          offsets.put(shardId, subscriptionOffset);
          // Submit offset
          datahubClient.commitSubscriptionOffset(Constant.projectName, Constant.topicName, subId, offsets);
      } catch (DatahubClientException e) {
        System.out.println(e.getErrorMessage());


      }
  }
}

Reset offset

Resetting an offset moves the consumption position to a specific point in time. If multiple records exist at that time point, the position is set to the first record. Resetting also updates the versionId. Running tasks that use the old versionId to submit offsets receive a SubscriptionOffsetResetException. You can obtain the new versionId by calling getSubscriptionOffset.

Parameters

Parameter name

Parameter type

Description

projectName

String

The name of the project.

topicName

String

The name of the topic.

subId

String

The id of the subscription.

offsets

Map

The offset map of shards.

Exceptions

Exception class name

Error code

Description

DatahubClientException

-

The base class for all exceptions

InvalidParameterException

InvalidParameter

InvalidCursor

Invalid parameters.

AuthorizationFailureException

Unauthorized

Failed to parse the authorization signature. Verify that the AccessKey is correct.

ResourceNotFoundException

ResourceNotFound

NoSuchProject

NoSuchTopic

NoSuchShard

NoSuchSubscription

NoSuchConnector

NoSuchMeteringInfo

The specified resource does not exist.

Note

This exception may be thrown if you send other requests immediately after performing Split/Merge operations.

Code example

//Reset offset
public static void resetSubscriptionOffset(String projectName, String topicName) throws ParseException {
    List<String> shardIds = Arrays.asList("0");
    //Choose the time you want to reset the offset to and convert it to a timestamp
    String time = "2019-07-09 10:00:00";
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    Date date = simpleDateFormat.parse(time);

    long timestamp = date.getTime();//Get the timestamp of the time
    long sequence = client.getCursor(projectName, topicName, subId, CursorType.SYSTEM_TIME, timestamp).getSequence();
    SubscriptionOffset offset = new SubscriptionOffset();
    offset.setTimestamp(timestamp);
    offset.setSequence(sequence);
    Map<String, SubscriptionOffset> offsets = new HashMap<String, SubscriptionOffset>();
    for (String shardId : shardIds) {
        offsets.put(shardId, offset);
    }

    try {
        datahubClient.resetSubscriptionOffset(projectName, topicName, subId, offsets);
        System.out.println("reset successful");
    } catch (DatahubClientException e) {
        System.out.println(e.getErrorMessage());
    }
}

Using subscription to consume DataHub data

Consuming DataHub data with a subscription is similar to reading data directly, except that the subscription persists the consumption offset so you can resume from any position.

Note
  • Call openSubscriptionSession once to initialize the offset and obtain the version and session information. Calling this method again invalidates the original session, making it impossible to submit offsets.

  • Call getCursor to obtain the current consumption offset. After consuming a record, call getNextCursor to get the offset for the next record.

  • Call commitSubscriptionOffset to submit the offset. The version and session information must match the current values for the submission to succeed.

//Offset consumption example with offset submission during consumption
public static void example(String projectName, String topicName,String subId) {
  String shardId = "0";
  List<String> shardIds = Arrays.asList("0", "1");
  OpenSubscriptionSessionResult openSubscriptionSessionResult = datahubClient.openSubscriptionSession(projectName, topicName, subId, shardIds);
  SubscriptionOffset subscriptionOffset = openSubscriptionSessionResult.getOffsets().get(shardId);
  // 1. Get the cursor for the current offset. If the current offset has expired, get the cursor for the first record within the lifecycle. If not consumed, also get the cursor for the first record within the lifecycle
  String cursor = null;
  //sequence < 0 means not consumed
  if (subscriptionOffset.getSequence() < 0) {
      // Get the cursor for the first record within the lifecycle
      cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.OLDEST).getCursor();
  } else {
      // Get the cursor for the next record
      long nextSequence = subscriptionOffset.getSequence() + 1;
      try {
          //Getting a cursor by SEQUENCE may report a SeekOutOfRange error, indicating that the data for the current cursor has expired
          cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.SEQUENCE, nextSequence).getCursor();
      } catch (SeekOutOfRangeException e) {
          // Get the cursor for the first record within the lifecycle
          cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.OLDEST).getCursor();
      }
  }
  // 2. Read and save the offset. This example reads Tuple data and saves the offset every 1000 records
  long recordCount = 0L;
  // Read 10 records each time
  int fetchNum = 10;
  while (true) {
      try {
          GetRecordsResult getRecordsResult = datahubClient.getRecords(projectName, topicName, shardId, schema, cursor, fetchNum);
          if (getRecordsResult.getRecordCount() <= 0) {
              // No data, sleep and then read
              Thread.sleep(1000);
              continue;
          }
          for (RecordEntry recordEntry : getRecordsResult.getRecords()) {
              //Consume data
              TupleRecordData data = (TupleRecordData) recordEntry.getRecordData();
              System.out.println("field1:" + data.getField("field1") + "\t"
                      + "field2:" + data.getField("field2"));
              // After processing the data, set the offset
              ++recordCount;
              subscriptionOffset.setSequence(recordEntry.getSequence());
              subscriptionOffset.setTimestamp(recordEntry.getSystemTime());
              if (recordCount % 1000 == 0) {
    //Submit offset
                  Map<String, SubscriptionOffset> offsetMap = new HashMap<>();
                  offsetMap.put(shardId, subscriptionOffset);
                  datahubClient.commitSubscriptionOffset(projectName, topicName, subId, offsetMap);
                  System.out.println("commit offset successful");
              }
          }
          cursor = getRecordsResult.getNextCursor();
      } catch (SubscriptionOfflineException | OffsetSessionChangedException e) {
          // Exit. Offline: subscription is offline; SessionChange: indicates the subscription is being consumed by another client simultaneously
          break;
      } catch (OffsetResetedException e) {
          // Indicates that the offset has been reset. Re-obtain the SubscriptionOffset information. This example uses Sequence reset
          // If reset by Timestamp, you need to obtain the cursor through CursorType.SYSTEM_TIME
          subscriptionOffset = datahubClient.getSubscriptionOffset(projectName, topicName, subId, shardIds).getOffsets().get(shardId);
          long nextSequence = subscriptionOffset.getSequence() + 1;
          cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.SEQUENCE, nextSequence).getCursor();
      } catch (DatahubClientException e) {
          // TODO: Decide whether to exit based on different exceptions
      } catch (Exception e) {
          break;
      }
  }
}