@azure/eventhubs-checkpointstore-table 1.0.0-alpha.20250619.1 → 1.0.0-alpha.20250804.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/tableCheckpointStore.js +25 -51
- package/dist/browser/tableCheckpointStore.js.map +1 -1
- package/dist/commonjs/tableCheckpointStore.js +25 -51
- package/dist/commonjs/tableCheckpointStore.js.map +1 -1
- package/dist/commonjs/tsdoc-metadata.json +11 -11
- package/dist/esm/tableCheckpointStore.js +25 -51
- package/dist/esm/tableCheckpointStore.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
|
-
import { __asyncValues } from "tslib";
|
|
4
3
|
import { odata } from "@azure/data-tables";
|
|
5
4
|
import { logErrorStackTrace, logger } from "./log.js";
|
|
6
5
|
/**
|
|
@@ -14,6 +13,7 @@ function _hasTimestamp(value) {
|
|
|
14
13
|
* An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.
|
|
15
14
|
*/
|
|
16
15
|
export class TableCheckpointStore {
|
|
16
|
+
_tableClient;
|
|
17
17
|
constructor(tableClient) {
|
|
18
18
|
this._tableClient = tableClient;
|
|
19
19
|
}
|
|
@@ -32,46 +32,33 @@ export class TableCheckpointStore {
|
|
|
32
32
|
* @returns Partition ownership details of all the partitions that have had an owner.
|
|
33
33
|
*/
|
|
34
34
|
async listOwnership(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
35
|
-
var _a, e_1, _b, _c;
|
|
36
35
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;
|
|
37
36
|
const partitionOwnershipArray = [];
|
|
38
37
|
const entitiesIter = this._tableClient.listEntities({
|
|
39
38
|
queryOptions: { filter: odata `PartitionKey eq ${partitionKey}` },
|
|
40
39
|
});
|
|
41
40
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_d = false;
|
|
46
|
-
const entity = _c;
|
|
47
|
-
if (!entity.timestamp) {
|
|
48
|
-
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
49
|
-
}
|
|
50
|
-
const partitionOwnership = {
|
|
51
|
-
fullyQualifiedNamespace,
|
|
52
|
-
eventHubName,
|
|
53
|
-
consumerGroup,
|
|
54
|
-
ownerId: entity.ownerid,
|
|
55
|
-
partitionId: entity.rowKey,
|
|
56
|
-
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
57
|
-
etag: entity.etag,
|
|
58
|
-
};
|
|
59
|
-
partitionOwnershipArray.push(partitionOwnership);
|
|
41
|
+
for await (const entity of entitiesIter) {
|
|
42
|
+
if (!entity.timestamp) {
|
|
43
|
+
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
60
44
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
45
|
+
const partitionOwnership = {
|
|
46
|
+
fullyQualifiedNamespace,
|
|
47
|
+
eventHubName,
|
|
48
|
+
consumerGroup,
|
|
49
|
+
ownerId: entity.ownerid,
|
|
50
|
+
partitionId: entity.rowKey,
|
|
51
|
+
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
52
|
+
etag: entity.etag,
|
|
53
|
+
};
|
|
54
|
+
partitionOwnershipArray.push(partitionOwnership);
|
|
68
55
|
}
|
|
69
56
|
return partitionOwnershipArray;
|
|
70
57
|
}
|
|
71
58
|
catch (err) {
|
|
72
59
|
logger.warning(`Error occurred while fetching the list of entities`, err.message);
|
|
73
60
|
logErrorStackTrace(err);
|
|
74
|
-
if (
|
|
61
|
+
if (err?.name === "AbortError")
|
|
75
62
|
throw err;
|
|
76
63
|
throw new Error(`Error occurred while fetching the list of entities. \n${err}`);
|
|
77
64
|
}
|
|
@@ -89,7 +76,7 @@ export class TableCheckpointStore {
|
|
|
89
76
|
async claimOwnership(partitionOwnership) {
|
|
90
77
|
const partitionOwnershipArray = [];
|
|
91
78
|
for (const ownership of partitionOwnership) {
|
|
92
|
-
const updatedOwnership =
|
|
79
|
+
const updatedOwnership = { ...ownership };
|
|
93
80
|
const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;
|
|
94
81
|
const ownershipEntity = {
|
|
95
82
|
partitionKey: partitionKey,
|
|
@@ -154,33 +141,20 @@ export class TableCheckpointStore {
|
|
|
154
141
|
* - `tracingOptions`: Options for configuring tracing.
|
|
155
142
|
*/
|
|
156
143
|
async listCheckpoints(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
157
|
-
var _a, e_2, _b, _c;
|
|
158
144
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;
|
|
159
145
|
const checkpoints = [];
|
|
160
146
|
const entitiesIter = this._tableClient.listEntities({
|
|
161
147
|
queryOptions: { filter: odata `PartitionKey eq ${partitionKey}` },
|
|
162
148
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
partitionId: entity.rowKey,
|
|
173
|
-
offset: entity.offset,
|
|
174
|
-
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
179
|
-
finally {
|
|
180
|
-
try {
|
|
181
|
-
if (!_d && !_a && (_b = entitiesIter_2.return)) await _b.call(entitiesIter_2);
|
|
182
|
-
}
|
|
183
|
-
finally { if (e_2) throw e_2.error; }
|
|
149
|
+
for await (const entity of entitiesIter) {
|
|
150
|
+
checkpoints.push({
|
|
151
|
+
consumerGroup,
|
|
152
|
+
eventHubName,
|
|
153
|
+
fullyQualifiedNamespace,
|
|
154
|
+
partitionId: entity.rowKey,
|
|
155
|
+
offset: entity.offset,
|
|
156
|
+
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
157
|
+
});
|
|
184
158
|
}
|
|
185
159
|
return checkpoints;
|
|
186
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.TableCheckpointStore = void 0;
|
|
6
|
-
const tslib_1 = require("tslib");
|
|
7
6
|
const data_tables_1 = require("@azure/data-tables");
|
|
8
7
|
const log_js_1 = require("./log.js");
|
|
9
8
|
/**
|
|
@@ -17,6 +16,7 @@ function _hasTimestamp(value) {
|
|
|
17
16
|
* An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.
|
|
18
17
|
*/
|
|
19
18
|
class TableCheckpointStore {
|
|
19
|
+
_tableClient;
|
|
20
20
|
constructor(tableClient) {
|
|
21
21
|
this._tableClient = tableClient;
|
|
22
22
|
}
|
|
@@ -35,46 +35,33 @@ class TableCheckpointStore {
|
|
|
35
35
|
* @returns Partition ownership details of all the partitions that have had an owner.
|
|
36
36
|
*/
|
|
37
37
|
async listOwnership(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
38
|
-
var _a, e_1, _b, _c;
|
|
39
38
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;
|
|
40
39
|
const partitionOwnershipArray = [];
|
|
41
40
|
const entitiesIter = this._tableClient.listEntities({
|
|
42
41
|
queryOptions: { filter: (0, data_tables_1.odata) `PartitionKey eq ${partitionKey}` },
|
|
43
42
|
});
|
|
44
43
|
try {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
_d = false;
|
|
49
|
-
const entity = _c;
|
|
50
|
-
if (!entity.timestamp) {
|
|
51
|
-
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
52
|
-
}
|
|
53
|
-
const partitionOwnership = {
|
|
54
|
-
fullyQualifiedNamespace,
|
|
55
|
-
eventHubName,
|
|
56
|
-
consumerGroup,
|
|
57
|
-
ownerId: entity.ownerid,
|
|
58
|
-
partitionId: entity.rowKey,
|
|
59
|
-
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
60
|
-
etag: entity.etag,
|
|
61
|
-
};
|
|
62
|
-
partitionOwnershipArray.push(partitionOwnership);
|
|
44
|
+
for await (const entity of entitiesIter) {
|
|
45
|
+
if (!entity.timestamp) {
|
|
46
|
+
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
63
47
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
48
|
+
const partitionOwnership = {
|
|
49
|
+
fullyQualifiedNamespace,
|
|
50
|
+
eventHubName,
|
|
51
|
+
consumerGroup,
|
|
52
|
+
ownerId: entity.ownerid,
|
|
53
|
+
partitionId: entity.rowKey,
|
|
54
|
+
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
55
|
+
etag: entity.etag,
|
|
56
|
+
};
|
|
57
|
+
partitionOwnershipArray.push(partitionOwnership);
|
|
71
58
|
}
|
|
72
59
|
return partitionOwnershipArray;
|
|
73
60
|
}
|
|
74
61
|
catch (err) {
|
|
75
62
|
log_js_1.logger.warning(`Error occurred while fetching the list of entities`, err.message);
|
|
76
63
|
(0, log_js_1.logErrorStackTrace)(err);
|
|
77
|
-
if (
|
|
64
|
+
if (err?.name === "AbortError")
|
|
78
65
|
throw err;
|
|
79
66
|
throw new Error(`Error occurred while fetching the list of entities. \n${err}`);
|
|
80
67
|
}
|
|
@@ -92,7 +79,7 @@ class TableCheckpointStore {
|
|
|
92
79
|
async claimOwnership(partitionOwnership) {
|
|
93
80
|
const partitionOwnershipArray = [];
|
|
94
81
|
for (const ownership of partitionOwnership) {
|
|
95
|
-
const updatedOwnership =
|
|
82
|
+
const updatedOwnership = { ...ownership };
|
|
96
83
|
const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;
|
|
97
84
|
const ownershipEntity = {
|
|
98
85
|
partitionKey: partitionKey,
|
|
@@ -157,33 +144,20 @@ class TableCheckpointStore {
|
|
|
157
144
|
* - `tracingOptions`: Options for configuring tracing.
|
|
158
145
|
*/
|
|
159
146
|
async listCheckpoints(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
160
|
-
var _a, e_2, _b, _c;
|
|
161
147
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;
|
|
162
148
|
const checkpoints = [];
|
|
163
149
|
const entitiesIter = this._tableClient.listEntities({
|
|
164
150
|
queryOptions: { filter: (0, data_tables_1.odata) `PartitionKey eq ${partitionKey}` },
|
|
165
151
|
});
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
partitionId: entity.rowKey,
|
|
176
|
-
offset: entity.offset,
|
|
177
|
-
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
182
|
-
finally {
|
|
183
|
-
try {
|
|
184
|
-
if (!_d && !_a && (_b = entitiesIter_2.return)) await _b.call(entitiesIter_2);
|
|
185
|
-
}
|
|
186
|
-
finally { if (e_2) throw e_2.error; }
|
|
152
|
+
for await (const entity of entitiesIter) {
|
|
153
|
+
checkpoints.push({
|
|
154
|
+
consumerGroup,
|
|
155
|
+
eventHubName,
|
|
156
|
+
fullyQualifiedNamespace,
|
|
157
|
+
partitionId: entity.rowKey,
|
|
158
|
+
offset: entity.offset,
|
|
159
|
+
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
160
|
+
});
|
|
187
161
|
}
|
|
188
162
|
return checkpoints;
|
|
189
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
-
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
-
{
|
|
4
|
-
"tsdocVersion": "0.12",
|
|
5
|
-
"toolPackages": [
|
|
6
|
-
{
|
|
7
|
-
"packageName": "@microsoft/api-extractor",
|
|
8
|
-
"packageVersion": "7.52.
|
|
9
|
-
}
|
|
10
|
-
]
|
|
11
|
-
}
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
|
3
|
+
{
|
|
4
|
+
"tsdocVersion": "0.12",
|
|
5
|
+
"toolPackages": [
|
|
6
|
+
{
|
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
|
8
|
+
"packageVersion": "7.52.10"
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Copyright (c) Microsoft Corporation.
|
|
2
2
|
// Licensed under the MIT License.
|
|
3
|
-
import { __asyncValues } from "tslib";
|
|
4
3
|
import { odata } from "@azure/data-tables";
|
|
5
4
|
import { logErrorStackTrace, logger } from "./log.js";
|
|
6
5
|
/**
|
|
@@ -14,6 +13,7 @@ function _hasTimestamp(value) {
|
|
|
14
13
|
* An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.
|
|
15
14
|
*/
|
|
16
15
|
export class TableCheckpointStore {
|
|
16
|
+
_tableClient;
|
|
17
17
|
constructor(tableClient) {
|
|
18
18
|
this._tableClient = tableClient;
|
|
19
19
|
}
|
|
@@ -32,46 +32,33 @@ export class TableCheckpointStore {
|
|
|
32
32
|
* @returns Partition ownership details of all the partitions that have had an owner.
|
|
33
33
|
*/
|
|
34
34
|
async listOwnership(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
35
|
-
var _a, e_1, _b, _c;
|
|
36
35
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;
|
|
37
36
|
const partitionOwnershipArray = [];
|
|
38
37
|
const entitiesIter = this._tableClient.listEntities({
|
|
39
38
|
queryOptions: { filter: odata `PartitionKey eq ${partitionKey}` },
|
|
40
39
|
});
|
|
41
40
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_d = false;
|
|
46
|
-
const entity = _c;
|
|
47
|
-
if (!entity.timestamp) {
|
|
48
|
-
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
49
|
-
}
|
|
50
|
-
const partitionOwnership = {
|
|
51
|
-
fullyQualifiedNamespace,
|
|
52
|
-
eventHubName,
|
|
53
|
-
consumerGroup,
|
|
54
|
-
ownerId: entity.ownerid,
|
|
55
|
-
partitionId: entity.rowKey,
|
|
56
|
-
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
57
|
-
etag: entity.etag,
|
|
58
|
-
};
|
|
59
|
-
partitionOwnershipArray.push(partitionOwnership);
|
|
41
|
+
for await (const entity of entitiesIter) {
|
|
42
|
+
if (!entity.timestamp) {
|
|
43
|
+
throw new Error(`Unable to retrieve timestamp from partitionKey "${partitionKey}", rowKey "${entity.rowKey}"`);
|
|
60
44
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
45
|
+
const partitionOwnership = {
|
|
46
|
+
fullyQualifiedNamespace,
|
|
47
|
+
eventHubName,
|
|
48
|
+
consumerGroup,
|
|
49
|
+
ownerId: entity.ownerid,
|
|
50
|
+
partitionId: entity.rowKey,
|
|
51
|
+
lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),
|
|
52
|
+
etag: entity.etag,
|
|
53
|
+
};
|
|
54
|
+
partitionOwnershipArray.push(partitionOwnership);
|
|
68
55
|
}
|
|
69
56
|
return partitionOwnershipArray;
|
|
70
57
|
}
|
|
71
58
|
catch (err) {
|
|
72
59
|
logger.warning(`Error occurred while fetching the list of entities`, err.message);
|
|
73
60
|
logErrorStackTrace(err);
|
|
74
|
-
if (
|
|
61
|
+
if (err?.name === "AbortError")
|
|
75
62
|
throw err;
|
|
76
63
|
throw new Error(`Error occurred while fetching the list of entities. \n${err}`);
|
|
77
64
|
}
|
|
@@ -89,7 +76,7 @@ export class TableCheckpointStore {
|
|
|
89
76
|
async claimOwnership(partitionOwnership) {
|
|
90
77
|
const partitionOwnershipArray = [];
|
|
91
78
|
for (const ownership of partitionOwnership) {
|
|
92
|
-
const updatedOwnership =
|
|
79
|
+
const updatedOwnership = { ...ownership };
|
|
93
80
|
const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;
|
|
94
81
|
const ownershipEntity = {
|
|
95
82
|
partitionKey: partitionKey,
|
|
@@ -154,33 +141,20 @@ export class TableCheckpointStore {
|
|
|
154
141
|
* - `tracingOptions`: Options for configuring tracing.
|
|
155
142
|
*/
|
|
156
143
|
async listCheckpoints(fullyQualifiedNamespace, eventHubName, consumerGroup) {
|
|
157
|
-
var _a, e_2, _b, _c;
|
|
158
144
|
const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;
|
|
159
145
|
const checkpoints = [];
|
|
160
146
|
const entitiesIter = this._tableClient.listEntities({
|
|
161
147
|
queryOptions: { filter: odata `PartitionKey eq ${partitionKey}` },
|
|
162
148
|
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
partitionId: entity.rowKey,
|
|
173
|
-
offset: entity.offset,
|
|
174
|
-
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
179
|
-
finally {
|
|
180
|
-
try {
|
|
181
|
-
if (!_d && !_a && (_b = entitiesIter_2.return)) await _b.call(entitiesIter_2);
|
|
182
|
-
}
|
|
183
|
-
finally { if (e_2) throw e_2.error; }
|
|
149
|
+
for await (const entity of entitiesIter) {
|
|
150
|
+
checkpoints.push({
|
|
151
|
+
consumerGroup,
|
|
152
|
+
eventHubName,
|
|
153
|
+
fullyQualifiedNamespace,
|
|
154
|
+
partitionId: entity.rowKey,
|
|
155
|
+
offset: entity.offset,
|
|
156
|
+
sequenceNumber: parseInt(entity.sequencenumber, 10),
|
|
157
|
+
});
|
|
184
158
|
}
|
|
185
159
|
return checkpoints;
|
|
186
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tableCheckpointStore.js","sourceRoot":"","sources":["../../src/tableCheckpointStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport type { Checkpoint, CheckpointStore, PartitionOwnership } from \"@azure/event-hubs\";\nimport type { TableClient, TableInsertEntityHeaders } from \"@azure/data-tables\";\nimport { odata } from \"@azure/data-tables\";\nimport { logErrorStackTrace, logger } from \"./log.js\";\n\n/**\n *\n * Checks if the value contains a `Timestamp` field of type `string`.\n */\nfunction _hasTimestamp<T extends TableInsertEntityHeaders>(\n value: T,\n): value is T & { Timestamp: string } {\n return typeof (value as any).Timestamp === \"string\";\n}\n\n/**\n * A checkpoint entity of type CheckpointEntity to be stored in the table\n * @internal\n *\n */\nexport interface CheckpointEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n sequencenumber: string;\n offset: string;\n}\n\n/**\n * An ownership entity of type PartitionOwnership to be stored in the table\n * @internal\n */\nexport interface PartitionOwnershipEntity {\n /**\n * The partitionKey is a composite key assembled in the following format:\n * `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`\n */\n partitionKey: string;\n /**\n * The rowKey is the partitionId\n *\n */\n rowKey: string;\n ownerid: string;\n}\n\n/**\n * An implementation of CheckpointStore that uses Azure Table Storage to persist checkpoint data.\n */\nexport class TableCheckpointStore implements CheckpointStore {\n private _tableClient: TableClient;\n\n constructor(tableClient: TableClient) {\n this._tableClient = tableClient;\n }\n\n /**\n * Get the list of all existing partition ownership from the underlying data store. May return empty\n * results if there are is no existing ownership information.\n * Partition Ownership contains the information on which `EventHubConsumerClient` subscribe call is currently processing the partition.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns Partition ownership details of all the partitions that have had an owner.\n */\n async listOwnership(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<PartitionOwnership[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Ownership`;\n const partitionOwnershipArray: PartitionOwnership[] = [];\n const entitiesIter = this._tableClient.listEntities<PartitionOwnershipEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n try {\n for await (const entity of entitiesIter) {\n if (!entity.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entity.rowKey}\"`,\n );\n }\n\n const partitionOwnership: PartitionOwnership = {\n fullyQualifiedNamespace,\n eventHubName,\n consumerGroup,\n ownerId: entity.ownerid,\n partitionId: entity.rowKey,\n lastModifiedTimeInMs: new Date(entity.timestamp).getTime(),\n etag: entity.etag,\n };\n partitionOwnershipArray.push(partitionOwnership);\n }\n return partitionOwnershipArray;\n } catch (err: any) {\n logger.warning(`Error occurred while fetching the list of entities`, err.message);\n logErrorStackTrace(err);\n if (err?.name === \"AbortError\") throw err;\n\n throw new Error(`Error occurred while fetching the list of entities. \\n${err}`);\n }\n }\n\n /**\n * Claim ownership of a list of partitions. This will return the list of partitions that were\n * successfully claimed.\n *\n * @param partitionOwnership - The list of partition ownership this instance is claiming to own.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A list partitions this instance successfully claimed ownership.\n */\n async claimOwnership(partitionOwnership: PartitionOwnership[]): Promise<PartitionOwnership[]> {\n const partitionOwnershipArray: PartitionOwnership[] = [];\n\n for (const ownership of partitionOwnership) {\n const updatedOwnership = { ...ownership };\n const partitionKey = `${ownership.fullyQualifiedNamespace} ${ownership.eventHubName} ${ownership.consumerGroup} Ownership`;\n const ownershipEntity: PartitionOwnershipEntity = {\n partitionKey: partitionKey,\n rowKey: ownership.partitionId,\n ownerid: ownership.ownerId,\n };\n\n // When we have an etag, we know the entity existed.\n // If we encounter an error we should fail.\n try {\n if (ownership.etag) {\n const updatedMetadata = await this._tableClient.updateEntity(ownershipEntity, \"Replace\", {\n etag: ownership.etag,\n });\n const entityRetrieved = await this._tableClient.getEntity(\n ownershipEntity.partitionKey,\n ownershipEntity.rowKey,\n );\n if (!entityRetrieved.timestamp) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${entityRetrieved.rowKey}\"`,\n );\n }\n updatedOwnership.lastModifiedTimeInMs = new Date(entityRetrieved.timestamp).getTime();\n updatedOwnership.etag = updatedMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n logger.info(\n `[${ownership.ownerId}] Claimed ownership successfully for partition: ${ownership.partitionId}`,\n `LastModifiedTime: ${ownership.lastModifiedTimeInMs}, ETag: ${ownership.etag}`,\n );\n } else {\n const newOwnershipMetadata = await this._tableClient.createEntity(ownershipEntity, {\n requestOptions: {\n customHeaders: {\n Prefer: \"return-content\",\n },\n },\n });\n\n if (!_hasTimestamp(newOwnershipMetadata)) {\n throw new Error(\n `Unable to retrieve timestamp from partitionKey \"${partitionKey}\", rowKey \"${ownershipEntity.rowKey}\"`,\n );\n }\n\n updatedOwnership.lastModifiedTimeInMs = new Date(\n newOwnershipMetadata.Timestamp,\n ).getTime();\n updatedOwnership.etag = newOwnershipMetadata.etag;\n partitionOwnershipArray.push(updatedOwnership);\n }\n } catch (err: any) {\n if (err.statusCode === 412) {\n // etag failures (precondition not met) aren't fatal errors. They happen\n // as multiple consumers attempt to claim the same partition (first one wins)\n // and losers get this error.\n logger.verbose(\n `[${ownership.ownerId}] Did not claim partition ${ownership.partitionId}. Another processor has already claimed it.`,\n );\n continue;\n }\n logger.warning(\n `Error occurred while claiming ownership for partition: ${ownership.partitionId}`,\n err.message,\n );\n logErrorStackTrace(err);\n }\n }\n return partitionOwnershipArray;\n }\n\n /**\n * Lists all the checkpoints in a data store for a given namespace, eventhub and consumer group.\n *\n * @param fullyQualifiedNamespace - The fully qualified Event Hubs namespace. This is likely to be similar to\n * <yournamespace>.servicebus.windows.net.\n * @param eventHubName - The event hub name.\n * @param consumerGroup - The consumer group name.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n */\n async listCheckpoints(\n fullyQualifiedNamespace: string,\n eventHubName: string,\n consumerGroup: string,\n ): Promise<Checkpoint[]> {\n const partitionKey = `${fullyQualifiedNamespace} ${eventHubName} ${consumerGroup} Checkpoint`;\n const checkpoints: Checkpoint[] = [];\n const entitiesIter = this._tableClient.listEntities<CheckpointEntity>({\n queryOptions: { filter: odata`PartitionKey eq ${partitionKey}` },\n });\n for await (const entity of entitiesIter) {\n checkpoints.push({\n consumerGroup,\n eventHubName,\n fullyQualifiedNamespace,\n partitionId: entity.rowKey,\n offset: entity.offset,\n sequenceNumber: parseInt(entity.sequencenumber, 10),\n });\n }\n return checkpoints;\n }\n\n /**\n * Updates the checkpoint in the data store for a partition.\n *\n * @param checkpoint - The checkpoint.\n * @param options - A set of options that can be specified to influence the behavior of this method.\n * - `abortSignal`: A signal used to request operation cancellation.\n * - `tracingOptions`: Options for configuring tracing.\n * @returns A promise that resolves when the checkpoint has been updated.\n */\n async updateCheckpoint(checkpoint: Checkpoint): Promise<void> {\n const partitionKey = `${checkpoint.fullyQualifiedNamespace} ${checkpoint.eventHubName} ${checkpoint.consumerGroup} Checkpoint`;\n const checkpointEntity: CheckpointEntity = {\n partitionKey: partitionKey,\n rowKey: checkpoint.partitionId,\n sequencenumber: checkpoint.sequenceNumber.toString(),\n offset: checkpoint.offset.toString(),\n };\n try {\n await this._tableClient.upsertEntity(checkpointEntity);\n logger.verbose(`Updated checkpoint successfully for partition: ${checkpoint.partitionId}`);\n return;\n } catch (err: any) {\n logger.verbose(\n `Error occurred while updating the checkpoint for partition: ${checkpoint.partitionId}.`,\n err.message,\n );\n throw err;\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azure/eventhubs-checkpointstore-table",
|
|
3
3
|
"sdk-type": "client",
|
|
4
|
-
"version": "1.0.0-alpha.
|
|
4
|
+
"version": "1.0.0-alpha.20250804.1",
|
|
5
5
|
"description": "An Azure Storage Table solution to store checkpoints when using Event Hubs.",
|
|
6
6
|
"author": "Microsoft Corporation",
|
|
7
7
|
"license": "MIT",
|