Offset operations
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 |
|
Invalid parameters. |
|
AuthorizationFailureException |
|
Failed to parse the authorization signature. Verify that the AccessKey is correct. |
|
ResourceNotFoundException |
|
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 |
|
Invalid parameters. |
|
AuthorizationFailureException |
|
Failed to parse the authorization signature. Verify that the AccessKey is correct. |
|
ResourceNotFoundException |
|
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 |
|
Invalid parameters. |
|
AuthorizationFailureException |
|
Failed to parse the authorization signature. Verify that the AccessKey is correct. |
|
ResourceNotFoundException |
|
The specified resource does not exist. Note
This exception may be thrown if you send other requests immediately after performing Split/Merge operations. |
|
SubscriptionOffsetResetException |
|
The subscription offset has been reset. |
|
SubscriptionSessionInvalidException |
|
The subscription session is invalid. This exception is thrown when another client uses the same subscription, which invalidates the current session. |
|
SubscriptionOfflineException |
|
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 |
|
Invalid parameters. |
|
AuthorizationFailureException |
|
Failed to parse the authorization signature. Verify that the AccessKey is correct. |
|
ResourceNotFoundException |
|
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.
-
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;
}
}
}