@boostercloud/framework-provider-azure 1.6.2 → 1.7.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/index.js
CHANGED
|
@@ -32,6 +32,7 @@ const Provider = (rockets) => ({
|
|
|
32
32
|
events: {
|
|
33
33
|
rawToEnvelopes: events_adapter_1.rawEventsToEnvelopes,
|
|
34
34
|
store: events_adapter_1.storeEvents.bind(null, cosmosClient),
|
|
35
|
+
storeSnapshot: events_adapter_1.storeSnapshot.bind(null, cosmosClient),
|
|
35
36
|
forEntitySince: events_adapter_1.readEntityEventsSince.bind(null, cosmosClient),
|
|
36
37
|
latestEntitySnapshot: events_adapter_1.readEntityLatestSnapshot.bind(null, cosmosClient),
|
|
37
38
|
search: events_searcher_adapter_1.searchEvents.bind(null, cosmosClient),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CosmosClient } from '@azure/cosmos';
|
|
2
|
-
import { EventEnvelope, BoosterConfig, UUID } from '@boostercloud/framework-types';
|
|
2
|
+
import { EventEnvelope, BoosterConfig, UUID, EntitySnapshotEnvelope, NonPersistedEventEnvelope, NonPersistedEntitySnapshotEnvelope } from '@boostercloud/framework-types';
|
|
3
3
|
import { Context } from '@azure/functions';
|
|
4
4
|
export declare function rawEventsToEnvelopes(context: Context): Array<EventEnvelope>;
|
|
5
5
|
export declare function readEntityEventsSince(cosmosDb: CosmosClient, config: BoosterConfig, entityTypeName: string, entityID: UUID, since?: string): Promise<Array<EventEnvelope>>;
|
|
6
|
-
export declare function readEntityLatestSnapshot(cosmosDb: CosmosClient, config: BoosterConfig, entityTypeName: string, entityID: UUID): Promise<
|
|
7
|
-
export declare function storeEvents(cosmosDb: CosmosClient, eventEnvelopes: Array<
|
|
6
|
+
export declare function readEntityLatestSnapshot(cosmosDb: CosmosClient, config: BoosterConfig, entityTypeName: string, entityID: UUID): Promise<EntitySnapshotEnvelope | undefined>;
|
|
7
|
+
export declare function storeEvents(cosmosDb: CosmosClient, eventEnvelopes: Array<NonPersistedEventEnvelope>, config: BoosterConfig): Promise<Array<EventEnvelope>>;
|
|
8
|
+
export declare function storeSnapshot(cosmosDb: CosmosClient, snapshotEnvelope: NonPersistedEntitySnapshotEnvelope, config: BoosterConfig): Promise<EntitySnapshotEnvelope>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.storeEvents = exports.readEntityLatestSnapshot = exports.readEntityEventsSince = exports.rawEventsToEnvelopes = void 0;
|
|
3
|
+
exports.storeSnapshot = exports.storeEvents = exports.readEntityLatestSnapshot = exports.readEntityEventsSince = exports.rawEventsToEnvelopes = void 0;
|
|
4
4
|
const framework_common_helpers_1 = require("@boostercloud/framework-common-helpers");
|
|
5
5
|
const constants_1 = require("../constants");
|
|
6
6
|
const partition_keys_1 = require("./partition-keys");
|
|
@@ -45,7 +45,7 @@ async function readEntityLatestSnapshot(cosmosDb, config, entityTypeName, entity
|
|
|
45
45
|
parameters: [
|
|
46
46
|
{
|
|
47
47
|
name: '@partitionKey',
|
|
48
|
-
value: (0, partition_keys_1.
|
|
48
|
+
value: (0, partition_keys_1.partitionKeyForSnapshot)(entityTypeName, entityID),
|
|
49
49
|
},
|
|
50
50
|
],
|
|
51
51
|
})
|
|
@@ -57,23 +57,84 @@ async function readEntityLatestSnapshot(cosmosDb, config, entityTypeName, entity
|
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
59
|
logger.debug(`[EventsAdapter#readEntityLatestSnapshot] No snapshot found for entity ${entityTypeName} with ID ${entityID}.`);
|
|
60
|
-
return
|
|
60
|
+
return undefined;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
exports.readEntityLatestSnapshot = readEntityLatestSnapshot;
|
|
64
64
|
async function storeEvents(cosmosDb, eventEnvelopes, config) {
|
|
65
65
|
const logger = (0, framework_common_helpers_1.getLogger)(config, 'events-adapter#storeEvents');
|
|
66
66
|
logger.debug('[EventsAdapter#storeEvents] Storing EventEnvelopes with eventEnvelopes:', eventEnvelopes);
|
|
67
|
+
const persistableEvents = [];
|
|
67
68
|
for (const eventEnvelope of eventEnvelopes) {
|
|
69
|
+
const persistableEvent = {
|
|
70
|
+
...eventEnvelope,
|
|
71
|
+
createdAt: new Date().toISOString(),
|
|
72
|
+
};
|
|
68
73
|
await cosmosDb
|
|
69
74
|
.database(config.resourceNames.applicationStack)
|
|
70
75
|
.container(config.resourceNames.eventsStore)
|
|
71
76
|
.items.create({
|
|
72
|
-
...
|
|
73
|
-
[constants_1.eventsStoreAttributes.partitionKey]: (0, partition_keys_1.partitionKeyForEvent)(eventEnvelope.entityTypeName, eventEnvelope.entityID
|
|
74
|
-
[constants_1.eventsStoreAttributes.sortKey]:
|
|
77
|
+
...persistableEvent,
|
|
78
|
+
[constants_1.eventsStoreAttributes.partitionKey]: (0, partition_keys_1.partitionKeyForEvent)(eventEnvelope.entityTypeName, eventEnvelope.entityID),
|
|
79
|
+
[constants_1.eventsStoreAttributes.sortKey]: persistableEvent.createdAt,
|
|
75
80
|
});
|
|
81
|
+
persistableEvents.push(persistableEvent);
|
|
76
82
|
}
|
|
77
83
|
logger.debug('[EventsAdapter#storeEvents] EventEnvelope stored');
|
|
84
|
+
return persistableEvents;
|
|
78
85
|
}
|
|
79
86
|
exports.storeEvents = storeEvents;
|
|
87
|
+
async function storeSnapshot(cosmosDb, snapshotEnvelope, config) {
|
|
88
|
+
const logger = (0, framework_common_helpers_1.getLogger)(config, 'events-adapter#storeSnapshot');
|
|
89
|
+
logger.debug('[EventsAdapter#storeSnapshot] Storing snapshot with snapshotEnvelope:', snapshotEnvelope);
|
|
90
|
+
const partitionKey = (0, partition_keys_1.partitionKeyForSnapshot)(snapshotEnvelope.entityTypeName, snapshotEnvelope.entityID);
|
|
91
|
+
/**
|
|
92
|
+
* The sort key of the snapshot matches the sort key of the last event that generated it.
|
|
93
|
+
* Entity snapshots can be potentially created by competing processes, and this way
|
|
94
|
+
* of storing the data makes snapshot creation an idempotent operation, allowing us to
|
|
95
|
+
* aggressively cache snapshots. If the snapshot already exists, it will be silently overwritten.
|
|
96
|
+
*/
|
|
97
|
+
const sortKey = snapshotEnvelope.snapshottedEventCreatedAt;
|
|
98
|
+
const container = cosmosDb.database(config.resourceNames.applicationStack).container(config.resourceNames.eventsStore);
|
|
99
|
+
/* TODO: As the sortKey is not part of an unique key in the table by default, there's no easy way to
|
|
100
|
+
* ensure that a snapshot is created only once, so we need to check if it exists first.
|
|
101
|
+
* This is not ideal, but conditional writes doesn't seem to have a simple solution in CosmosDB at
|
|
102
|
+
* the moment. We should revisit this in the future.
|
|
103
|
+
*
|
|
104
|
+
* Notice that while this implementation can potentially fail to prevent an extra snapshot to be created,
|
|
105
|
+
* the existence of such extra snapshot has no impact on the way Booster works. This check is here
|
|
106
|
+
* because we want to avoid snapshots to be created out of control in scenarios where a big number
|
|
107
|
+
* of event handlers are requesting the latest state of the same entity.
|
|
108
|
+
*/
|
|
109
|
+
const { resources } = await container.items
|
|
110
|
+
.query({
|
|
111
|
+
query: 'SELECT * FROM c WHERE c.partitionKey = @partitionKey AND c.sortKey = @sortKey',
|
|
112
|
+
parameters: [
|
|
113
|
+
{
|
|
114
|
+
name: '@partitionKey',
|
|
115
|
+
value: partitionKey,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: '@sortKey',
|
|
119
|
+
value: sortKey,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
})
|
|
123
|
+
.fetchAll();
|
|
124
|
+
if (resources.length > 0) {
|
|
125
|
+
throw new Error('Snapshot already exists. skipping...');
|
|
126
|
+
}
|
|
127
|
+
const persistableEntitySnapshot = {
|
|
128
|
+
...snapshotEnvelope,
|
|
129
|
+
createdAt: snapshotEnvelope.snapshottedEventCreatedAt,
|
|
130
|
+
persistedAt: new Date().toISOString(),
|
|
131
|
+
};
|
|
132
|
+
await container.items.create({
|
|
133
|
+
...persistableEntitySnapshot,
|
|
134
|
+
[constants_1.eventsStoreAttributes.partitionKey]: partitionKey,
|
|
135
|
+
[constants_1.eventsStoreAttributes.sortKey]: sortKey,
|
|
136
|
+
});
|
|
137
|
+
logger.debug('Snapshot stored', snapshotEnvelope);
|
|
138
|
+
return persistableEntitySnapshot;
|
|
139
|
+
}
|
|
140
|
+
exports.storeSnapshot = storeSnapshot;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function partitionKeyForEvent(entityTypeName: string, entityID: UUID
|
|
3
|
-
export declare function
|
|
1
|
+
import { UUID } from '@boostercloud/framework-types';
|
|
2
|
+
export declare function partitionKeyForEvent(entityTypeName: string, entityID: UUID): string;
|
|
3
|
+
export declare function partitionKeyForSnapshot(entityTypeName: string, entityID: UUID): string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
function partitionKeyForEvent(entityTypeName, entityID
|
|
5
|
-
return `${entityTypeName}-${entityID}
|
|
3
|
+
exports.partitionKeyForSnapshot = exports.partitionKeyForEvent = void 0;
|
|
4
|
+
function partitionKeyForEvent(entityTypeName, entityID) {
|
|
5
|
+
return `${entityTypeName}-${entityID}-event`;
|
|
6
6
|
}
|
|
7
7
|
exports.partitionKeyForEvent = partitionKeyForEvent;
|
|
8
|
-
function
|
|
9
|
-
return `${entityTypeName}-${
|
|
8
|
+
function partitionKeyForSnapshot(entityTypeName, entityID) {
|
|
9
|
+
return `${entityTypeName}-${entityID}-snapshot`;
|
|
10
10
|
}
|
|
11
|
-
exports.
|
|
11
|
+
exports.partitionKeyForSnapshot = partitionKeyForSnapshot;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boostercloud/framework-provider-azure",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "Handle Booster's integration with Azure",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework-provider-azure"
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"@azure/cosmos": "^3.17.0",
|
|
24
24
|
"@azure/functions": "^1.2.2",
|
|
25
25
|
"@azure/identity": "~2.1.0",
|
|
26
|
-
"@boostercloud/framework-common-helpers": "^1.
|
|
27
|
-
"@boostercloud/framework-types": "^1.
|
|
26
|
+
"@boostercloud/framework-common-helpers": "^1.7.1",
|
|
27
|
+
"@boostercloud/framework-types": "^1.7.1",
|
|
28
28
|
"tslib": "^2.4.0",
|
|
29
29
|
"@effect-ts/core": "^0.60.4"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@boostercloud/eslint-config": "^1.
|
|
32
|
+
"@boostercloud/eslint-config": "^1.7.1",
|
|
33
33
|
"@types/chai": "4.2.18",
|
|
34
34
|
"@types/chai-as-promised": "7.1.4",
|
|
35
35
|
"@types/faker": "5.1.5",
|