@luvio/environments 0.105.0 → 0.108.0
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/es/es2018/DurableStore.d.ts +4 -6
- package/dist/es/es2018/environments.js +75 -47
- package/dist/es/es2018/makeDurable.d.ts +1 -7
- package/dist/umd/es2018/DurableStore.d.ts +4 -6
- package/dist/umd/es2018/environments.js +74 -46
- package/dist/umd/es2018/makeDurable.d.ts +1 -7
- package/dist/umd/es5/DurableStore.d.ts +4 -6
- package/dist/umd/es5/environments.js +109 -51
- package/dist/umd/es5/makeDurable.d.ts +1 -7
- package/package.json +2 -2
|
@@ -27,19 +27,17 @@ export interface DeprecatedDurableStoreEntry1<T = unknown> {
|
|
|
27
27
|
export interface DurableStoreEntries<EntryTypes> {
|
|
28
28
|
[key: string]: DurableStoreEntry<Extract<EntryTypes, unknown>>;
|
|
29
29
|
}
|
|
30
|
-
export declare
|
|
31
|
-
SetEntries = "setEntries",
|
|
32
|
-
EvictEntries = "evictEntries"
|
|
33
|
-
}
|
|
30
|
+
export declare type DurableStoreOperationType = 'setEntries' | 'evictEntries';
|
|
34
31
|
export interface BaseOperation {
|
|
32
|
+
type: DurableStoreOperationType;
|
|
35
33
|
segment: string;
|
|
36
34
|
}
|
|
37
35
|
export interface DurableStoreSetOperation<T> extends BaseOperation {
|
|
38
|
-
type:
|
|
36
|
+
type: 'setEntries';
|
|
39
37
|
entries: DurableStoreEntries<T>;
|
|
40
38
|
}
|
|
41
39
|
export interface DurableStoreEvictOperation extends BaseOperation {
|
|
42
|
-
type:
|
|
40
|
+
type: 'evictEntries';
|
|
43
41
|
ids: string[];
|
|
44
42
|
}
|
|
45
43
|
export declare type DurableStoreOperation<T> = DurableStoreSetOperation<T> | DurableStoreEvictOperation;
|
|
@@ -7,11 +7,6 @@ function isDeprecatedDurableStoreEntry(durableRecord) {
|
|
|
7
7
|
// Add more deprecated shape checks here
|
|
8
8
|
return false;
|
|
9
9
|
}
|
|
10
|
-
var DurableStoreOperationType;
|
|
11
|
-
(function (DurableStoreOperationType) {
|
|
12
|
-
DurableStoreOperationType["SetEntries"] = "setEntries";
|
|
13
|
-
DurableStoreOperationType["EvictEntries"] = "evictEntries";
|
|
14
|
-
})(DurableStoreOperationType || (DurableStoreOperationType = {}));
|
|
15
10
|
const DefaultDurableSegment = 'DEFAULT';
|
|
16
11
|
|
|
17
12
|
const { keys, create, assign, freeze } = Object;
|
|
@@ -310,7 +305,7 @@ function flushInMemoryStoreValuesToDurableStore(store, durableStore, durableStor
|
|
|
310
305
|
const recordKeys = keys(durableRecords);
|
|
311
306
|
if (recordKeys.length > 0) {
|
|
312
307
|
durableStoreOperations.push({
|
|
313
|
-
type:
|
|
308
|
+
type: 'setEntries',
|
|
314
309
|
entries: durableRecords,
|
|
315
310
|
segment: DefaultDurableSegment,
|
|
316
311
|
});
|
|
@@ -319,7 +314,7 @@ function flushInMemoryStoreValuesToDurableStore(store, durableStore, durableStor
|
|
|
319
314
|
const evictedKeys = keys(evictedRecords);
|
|
320
315
|
if (evictedKeys.length > 0) {
|
|
321
316
|
durableStoreOperations.push({
|
|
322
|
-
type:
|
|
317
|
+
type: 'evictEntries',
|
|
323
318
|
ids: evictedKeys,
|
|
324
319
|
segment: DefaultDurableSegment,
|
|
325
320
|
});
|
|
@@ -424,6 +419,7 @@ function isUnfulfilledSnapshot(cachedSnapshotResult) {
|
|
|
424
419
|
function makeDurable(environment, { durableStore, instrumentation }) {
|
|
425
420
|
let ingestStagingStore = null;
|
|
426
421
|
const durableTTLStore = new DurableTTLStore(durableStore);
|
|
422
|
+
const mergeKeysPromiseMap = new Map();
|
|
427
423
|
let initializationPromise = new Promise((resolve) => {
|
|
428
424
|
const finish = () => {
|
|
429
425
|
resolve();
|
|
@@ -682,52 +678,84 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
682
678
|
}
|
|
683
679
|
return {};
|
|
684
680
|
};
|
|
685
|
-
const handleSuccessResponse = function (ingestAndBroadcastFunc, getResponseCacheKeysFunc
|
|
681
|
+
const handleSuccessResponse = async function (ingestAndBroadcastFunc, getResponseCacheKeysFunc) {
|
|
686
682
|
validateNotDisposed();
|
|
687
683
|
const cacheKeySet = getResponseCacheKeysFunc();
|
|
688
|
-
const
|
|
684
|
+
const cacheKeySetKeys = keys(cacheKeySet);
|
|
689
685
|
const keysToRevive = {};
|
|
690
|
-
|
|
691
|
-
const
|
|
692
|
-
if (
|
|
693
|
-
|
|
694
|
-
keysToRevive[cacheKey] = true;
|
|
686
|
+
for (const cacheKeySetKey of cacheKeySetKeys) {
|
|
687
|
+
const cacheKey = cacheKeySet[cacheKeySetKey];
|
|
688
|
+
if (cacheKey.mergeable === true) {
|
|
689
|
+
keysToRevive[cacheKeySetKey] = true;
|
|
695
690
|
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
691
|
+
}
|
|
692
|
+
let snapshotFromMemoryIngest = undefined;
|
|
693
|
+
const keysAsArray = keys(keysToRevive);
|
|
694
|
+
if (keysAsArray.length > 0) {
|
|
695
|
+
// if we need to do an L2 read then L2 write then we need to synchronize
|
|
696
|
+
// our read/merge/ingest/write Promise based on the keys so we don't
|
|
697
|
+
// stomp over any data
|
|
698
|
+
const readWritePromise = (async () => {
|
|
699
|
+
const pendingPromises = [];
|
|
700
|
+
for (const key of keysAsArray) {
|
|
701
|
+
const pendingPromise = mergeKeysPromiseMap.get(key);
|
|
702
|
+
if (pendingPromise !== undefined) {
|
|
703
|
+
// IMPORTANT: while on the synchronous code path we get a
|
|
704
|
+
// handle to pendingPromise and push it onto the array.
|
|
705
|
+
// This is important because later in this synchronous code
|
|
706
|
+
// path we will upsert readWritePromise into the
|
|
707
|
+
// mergeKeysPromiseMap (essentially overwriting pendingPromise
|
|
708
|
+
// in the map).
|
|
709
|
+
pendingPromises.push(pendingPromise);
|
|
710
|
+
}
|
|
707
711
|
}
|
|
708
|
-
|
|
709
|
-
|
|
712
|
+
await Promise.all(pendingPromises);
|
|
713
|
+
const entries = await durableStore.getEntries(keysAsArray, DefaultDurableSegment);
|
|
714
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
715
|
+
publishDurableStoreEntries(entries, ingestStagingStore.publish.bind(ingestStagingStore),
|
|
716
|
+
// we don't need to prime metadata
|
|
717
|
+
() => { });
|
|
718
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
719
|
+
await publishChangesToDurableStore();
|
|
720
|
+
})();
|
|
721
|
+
for (const key of keysAsArray) {
|
|
722
|
+
// we are overwriting the previous promise at this key, but that
|
|
723
|
+
// is ok because we got a handle to it earlier (see the IMPORTANT
|
|
724
|
+
// comment about 35 lines up)
|
|
725
|
+
mergeKeysPromiseMap.set(key, readWritePromise);
|
|
726
|
+
}
|
|
727
|
+
try {
|
|
728
|
+
await readWritePromise;
|
|
729
|
+
}
|
|
730
|
+
finally {
|
|
731
|
+
for (const key of keysAsArray) {
|
|
732
|
+
const pendingPromise = mergeKeysPromiseMap.get(key);
|
|
733
|
+
// cleanup the entry from the map if this is the last promise
|
|
734
|
+
// for that key
|
|
735
|
+
if (pendingPromise === readWritePromise) {
|
|
736
|
+
mergeKeysPromiseMap.delete(key);
|
|
737
|
+
}
|
|
710
738
|
}
|
|
711
|
-
|
|
712
|
-
return reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(snapshotFromMemoryIngest.select, environment.createSnapshot, snapshotFromMemoryIngest.refresh)).then((result) => {
|
|
713
|
-
return result.snapshot;
|
|
714
|
-
});
|
|
715
|
-
});
|
|
716
|
-
};
|
|
717
|
-
if (keys(keysToRevive).length === 0) {
|
|
718
|
-
return ingestAndPublish({});
|
|
739
|
+
}
|
|
719
740
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return
|
|
730
|
-
}
|
|
741
|
+
else {
|
|
742
|
+
// we aren't doing any merging so we don't have to synchronize, the
|
|
743
|
+
// underlying DurableStore implementation takes care of R/W sync
|
|
744
|
+
// so all we have to do is ingest then write to L2
|
|
745
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
746
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
747
|
+
await publishChangesToDurableStore();
|
|
748
|
+
}
|
|
749
|
+
if (snapshotFromMemoryIngest === undefined) {
|
|
750
|
+
return undefined;
|
|
751
|
+
}
|
|
752
|
+
if (snapshotFromMemoryIngest.state !== 'Unfulfilled') {
|
|
753
|
+
return snapshotFromMemoryIngest;
|
|
754
|
+
}
|
|
755
|
+
// if snapshot from staging store lookup is unfulfilled then do an L2 lookup
|
|
756
|
+
const { select, refresh } = snapshotFromMemoryIngest;
|
|
757
|
+
const result = await reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(select, environment.createSnapshot, refresh));
|
|
758
|
+
return result.snapshot;
|
|
731
759
|
};
|
|
732
760
|
const handleErrorResponse = function (ingestAndBroadcastFunc) {
|
|
733
761
|
validateNotDisposed();
|
|
@@ -778,4 +806,4 @@ function makeDurable(environment, { durableStore, instrumentation }) {
|
|
|
778
806
|
});
|
|
779
807
|
}
|
|
780
808
|
|
|
781
|
-
export { DefaultDurableSegment,
|
|
809
|
+
export { DefaultDurableSegment, isDurableEnvironmentEvent, makeDurable, publishDurableStoreEntries };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Environment, RecordSource, InMemoryStore } from '@luvio/engine';
|
|
2
2
|
import type { DurableStore } from './DurableStore';
|
|
3
3
|
import type { InstrumentationFunction } from './makeDurable/error';
|
|
4
4
|
import type { TTLOverridesMap } from './DurableTTLStore';
|
|
@@ -25,12 +25,6 @@ export interface DurableEnvironment extends Environment {
|
|
|
25
25
|
* flow, otherwise returns an empty object.
|
|
26
26
|
*/
|
|
27
27
|
getIngestStagingStoreMetadata(): InMemoryStore['metadata'];
|
|
28
|
-
/**
|
|
29
|
-
* Overload of Environment.handleSuccessResponse that takes in an optional
|
|
30
|
-
* RecordSource to "prime" the ingest staging store with before calling
|
|
31
|
-
* ingest. Useful for merge-able record types
|
|
32
|
-
*/
|
|
33
|
-
handleSuccessResponse<IngestionReturnType extends Snapshot<D, V> | undefined, D, V = unknown>(ingestAndBroadcastFunc: () => IngestionReturnType, getResponseCacheKeysFunc: () => CacheKeySet, existingRecords?: RecordSource): IngestionReturnType | Promise<IngestionReturnType>;
|
|
34
28
|
}
|
|
35
29
|
export declare const AdapterContextSegment = "ADAPTER-CONTEXT";
|
|
36
30
|
export declare const ADAPTER_CONTEXT_ID_SUFFIX = "__NAMED_CONTEXT";
|
|
@@ -27,19 +27,17 @@ export interface DeprecatedDurableStoreEntry1<T = unknown> {
|
|
|
27
27
|
export interface DurableStoreEntries<EntryTypes> {
|
|
28
28
|
[key: string]: DurableStoreEntry<Extract<EntryTypes, unknown>>;
|
|
29
29
|
}
|
|
30
|
-
export declare
|
|
31
|
-
SetEntries = "setEntries",
|
|
32
|
-
EvictEntries = "evictEntries"
|
|
33
|
-
}
|
|
30
|
+
export declare type DurableStoreOperationType = 'setEntries' | 'evictEntries';
|
|
34
31
|
export interface BaseOperation {
|
|
32
|
+
type: DurableStoreOperationType;
|
|
35
33
|
segment: string;
|
|
36
34
|
}
|
|
37
35
|
export interface DurableStoreSetOperation<T> extends BaseOperation {
|
|
38
|
-
type:
|
|
36
|
+
type: 'setEntries';
|
|
39
37
|
entries: DurableStoreEntries<T>;
|
|
40
38
|
}
|
|
41
39
|
export interface DurableStoreEvictOperation extends BaseOperation {
|
|
42
|
-
type:
|
|
40
|
+
type: 'evictEntries';
|
|
43
41
|
ids: string[];
|
|
44
42
|
}
|
|
45
43
|
export declare type DurableStoreOperation<T> = DurableStoreSetOperation<T> | DurableStoreEvictOperation;
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
// Add more deprecated shape checks here
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
|
-
exports.DurableStoreOperationType = void 0;
|
|
15
|
-
(function (DurableStoreOperationType) {
|
|
16
|
-
DurableStoreOperationType["SetEntries"] = "setEntries";
|
|
17
|
-
DurableStoreOperationType["EvictEntries"] = "evictEntries";
|
|
18
|
-
})(exports.DurableStoreOperationType || (exports.DurableStoreOperationType = {}));
|
|
19
14
|
const DefaultDurableSegment = 'DEFAULT';
|
|
20
15
|
|
|
21
16
|
const { keys, create, assign, freeze } = Object;
|
|
@@ -314,7 +309,7 @@
|
|
|
314
309
|
const recordKeys = keys(durableRecords);
|
|
315
310
|
if (recordKeys.length > 0) {
|
|
316
311
|
durableStoreOperations.push({
|
|
317
|
-
type:
|
|
312
|
+
type: 'setEntries',
|
|
318
313
|
entries: durableRecords,
|
|
319
314
|
segment: DefaultDurableSegment,
|
|
320
315
|
});
|
|
@@ -323,7 +318,7 @@
|
|
|
323
318
|
const evictedKeys = keys(evictedRecords);
|
|
324
319
|
if (evictedKeys.length > 0) {
|
|
325
320
|
durableStoreOperations.push({
|
|
326
|
-
type:
|
|
321
|
+
type: 'evictEntries',
|
|
327
322
|
ids: evictedKeys,
|
|
328
323
|
segment: DefaultDurableSegment,
|
|
329
324
|
});
|
|
@@ -428,6 +423,7 @@
|
|
|
428
423
|
function makeDurable(environment, { durableStore, instrumentation }) {
|
|
429
424
|
let ingestStagingStore = null;
|
|
430
425
|
const durableTTLStore = new DurableTTLStore(durableStore);
|
|
426
|
+
const mergeKeysPromiseMap = new Map();
|
|
431
427
|
let initializationPromise = new Promise((resolve) => {
|
|
432
428
|
const finish = () => {
|
|
433
429
|
resolve();
|
|
@@ -686,52 +682,84 @@
|
|
|
686
682
|
}
|
|
687
683
|
return {};
|
|
688
684
|
};
|
|
689
|
-
const handleSuccessResponse = function (ingestAndBroadcastFunc, getResponseCacheKeysFunc
|
|
685
|
+
const handleSuccessResponse = async function (ingestAndBroadcastFunc, getResponseCacheKeysFunc) {
|
|
690
686
|
validateNotDisposed();
|
|
691
687
|
const cacheKeySet = getResponseCacheKeysFunc();
|
|
692
|
-
const
|
|
688
|
+
const cacheKeySetKeys = keys(cacheKeySet);
|
|
693
689
|
const keysToRevive = {};
|
|
694
|
-
|
|
695
|
-
const
|
|
696
|
-
if (
|
|
697
|
-
|
|
698
|
-
keysToRevive[cacheKey] = true;
|
|
690
|
+
for (const cacheKeySetKey of cacheKeySetKeys) {
|
|
691
|
+
const cacheKey = cacheKeySet[cacheKeySetKey];
|
|
692
|
+
if (cacheKey.mergeable === true) {
|
|
693
|
+
keysToRevive[cacheKeySetKey] = true;
|
|
699
694
|
}
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
695
|
+
}
|
|
696
|
+
let snapshotFromMemoryIngest = undefined;
|
|
697
|
+
const keysAsArray = keys(keysToRevive);
|
|
698
|
+
if (keysAsArray.length > 0) {
|
|
699
|
+
// if we need to do an L2 read then L2 write then we need to synchronize
|
|
700
|
+
// our read/merge/ingest/write Promise based on the keys so we don't
|
|
701
|
+
// stomp over any data
|
|
702
|
+
const readWritePromise = (async () => {
|
|
703
|
+
const pendingPromises = [];
|
|
704
|
+
for (const key of keysAsArray) {
|
|
705
|
+
const pendingPromise = mergeKeysPromiseMap.get(key);
|
|
706
|
+
if (pendingPromise !== undefined) {
|
|
707
|
+
// IMPORTANT: while on the synchronous code path we get a
|
|
708
|
+
// handle to pendingPromise and push it onto the array.
|
|
709
|
+
// This is important because later in this synchronous code
|
|
710
|
+
// path we will upsert readWritePromise into the
|
|
711
|
+
// mergeKeysPromiseMap (essentially overwriting pendingPromise
|
|
712
|
+
// in the map).
|
|
713
|
+
pendingPromises.push(pendingPromise);
|
|
714
|
+
}
|
|
711
715
|
}
|
|
712
|
-
|
|
713
|
-
|
|
716
|
+
await Promise.all(pendingPromises);
|
|
717
|
+
const entries = await durableStore.getEntries(keysAsArray, DefaultDurableSegment);
|
|
718
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
719
|
+
publishDurableStoreEntries(entries, ingestStagingStore.publish.bind(ingestStagingStore),
|
|
720
|
+
// we don't need to prime metadata
|
|
721
|
+
() => { });
|
|
722
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
723
|
+
await publishChangesToDurableStore();
|
|
724
|
+
})();
|
|
725
|
+
for (const key of keysAsArray) {
|
|
726
|
+
// we are overwriting the previous promise at this key, but that
|
|
727
|
+
// is ok because we got a handle to it earlier (see the IMPORTANT
|
|
728
|
+
// comment about 35 lines up)
|
|
729
|
+
mergeKeysPromiseMap.set(key, readWritePromise);
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
await readWritePromise;
|
|
733
|
+
}
|
|
734
|
+
finally {
|
|
735
|
+
for (const key of keysAsArray) {
|
|
736
|
+
const pendingPromise = mergeKeysPromiseMap.get(key);
|
|
737
|
+
// cleanup the entry from the map if this is the last promise
|
|
738
|
+
// for that key
|
|
739
|
+
if (pendingPromise === readWritePromise) {
|
|
740
|
+
mergeKeysPromiseMap.delete(key);
|
|
741
|
+
}
|
|
714
742
|
}
|
|
715
|
-
|
|
716
|
-
return reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(snapshotFromMemoryIngest.select, environment.createSnapshot, snapshotFromMemoryIngest.refresh)).then((result) => {
|
|
717
|
-
return result.snapshot;
|
|
718
|
-
});
|
|
719
|
-
});
|
|
720
|
-
};
|
|
721
|
-
if (keys(keysToRevive).length === 0) {
|
|
722
|
-
return ingestAndPublish({});
|
|
743
|
+
}
|
|
723
744
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
return
|
|
734
|
-
}
|
|
745
|
+
else {
|
|
746
|
+
// we aren't doing any merging so we don't have to synchronize, the
|
|
747
|
+
// underlying DurableStore implementation takes care of R/W sync
|
|
748
|
+
// so all we have to do is ingest then write to L2
|
|
749
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
750
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
751
|
+
await publishChangesToDurableStore();
|
|
752
|
+
}
|
|
753
|
+
if (snapshotFromMemoryIngest === undefined) {
|
|
754
|
+
return undefined;
|
|
755
|
+
}
|
|
756
|
+
if (snapshotFromMemoryIngest.state !== 'Unfulfilled') {
|
|
757
|
+
return snapshotFromMemoryIngest;
|
|
758
|
+
}
|
|
759
|
+
// if snapshot from staging store lookup is unfulfilled then do an L2 lookup
|
|
760
|
+
const { select, refresh } = snapshotFromMemoryIngest;
|
|
761
|
+
const result = await reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, () => environment.storeLookup(select, environment.createSnapshot, refresh));
|
|
762
|
+
return result.snapshot;
|
|
735
763
|
};
|
|
736
764
|
const handleErrorResponse = function (ingestAndBroadcastFunc) {
|
|
737
765
|
validateNotDisposed();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Environment, RecordSource, InMemoryStore } from '@luvio/engine';
|
|
2
2
|
import type { DurableStore } from './DurableStore';
|
|
3
3
|
import type { InstrumentationFunction } from './makeDurable/error';
|
|
4
4
|
import type { TTLOverridesMap } from './DurableTTLStore';
|
|
@@ -25,12 +25,6 @@ export interface DurableEnvironment extends Environment {
|
|
|
25
25
|
* flow, otherwise returns an empty object.
|
|
26
26
|
*/
|
|
27
27
|
getIngestStagingStoreMetadata(): InMemoryStore['metadata'];
|
|
28
|
-
/**
|
|
29
|
-
* Overload of Environment.handleSuccessResponse that takes in an optional
|
|
30
|
-
* RecordSource to "prime" the ingest staging store with before calling
|
|
31
|
-
* ingest. Useful for merge-able record types
|
|
32
|
-
*/
|
|
33
|
-
handleSuccessResponse<IngestionReturnType extends Snapshot<D, V> | undefined, D, V = unknown>(ingestAndBroadcastFunc: () => IngestionReturnType, getResponseCacheKeysFunc: () => CacheKeySet, existingRecords?: RecordSource): IngestionReturnType | Promise<IngestionReturnType>;
|
|
34
28
|
}
|
|
35
29
|
export declare const AdapterContextSegment = "ADAPTER-CONTEXT";
|
|
36
30
|
export declare const ADAPTER_CONTEXT_ID_SUFFIX = "__NAMED_CONTEXT";
|
|
@@ -27,19 +27,17 @@ export interface DeprecatedDurableStoreEntry1<T = unknown> {
|
|
|
27
27
|
export interface DurableStoreEntries<EntryTypes> {
|
|
28
28
|
[key: string]: DurableStoreEntry<Extract<EntryTypes, unknown>>;
|
|
29
29
|
}
|
|
30
|
-
export declare
|
|
31
|
-
SetEntries = "setEntries",
|
|
32
|
-
EvictEntries = "evictEntries"
|
|
33
|
-
}
|
|
30
|
+
export declare type DurableStoreOperationType = 'setEntries' | 'evictEntries';
|
|
34
31
|
export interface BaseOperation {
|
|
32
|
+
type: DurableStoreOperationType;
|
|
35
33
|
segment: string;
|
|
36
34
|
}
|
|
37
35
|
export interface DurableStoreSetOperation<T> extends BaseOperation {
|
|
38
|
-
type:
|
|
36
|
+
type: 'setEntries';
|
|
39
37
|
entries: DurableStoreEntries<T>;
|
|
40
38
|
}
|
|
41
39
|
export interface DurableStoreEvictOperation extends BaseOperation {
|
|
42
|
-
type:
|
|
40
|
+
type: 'evictEntries';
|
|
43
41
|
ids: string[];
|
|
44
42
|
}
|
|
45
43
|
export declare type DurableStoreOperation<T> = DurableStoreSetOperation<T> | DurableStoreEvictOperation;
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
// Add more deprecated shape checks here
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
|
-
exports.DurableStoreOperationType = void 0;
|
|
15
|
-
(function (DurableStoreOperationType) {
|
|
16
|
-
DurableStoreOperationType["SetEntries"] = "setEntries";
|
|
17
|
-
DurableStoreOperationType["EvictEntries"] = "evictEntries";
|
|
18
|
-
})(exports.DurableStoreOperationType || (exports.DurableStoreOperationType = {}));
|
|
19
14
|
var DefaultDurableSegment = 'DEFAULT';
|
|
20
15
|
|
|
21
16
|
/*! *****************************************************************************
|
|
@@ -395,7 +390,7 @@
|
|
|
395
390
|
var recordKeys = keys(durableRecords);
|
|
396
391
|
if (recordKeys.length > 0) {
|
|
397
392
|
durableStoreOperations.push({
|
|
398
|
-
type:
|
|
393
|
+
type: 'setEntries',
|
|
399
394
|
entries: durableRecords,
|
|
400
395
|
segment: DefaultDurableSegment,
|
|
401
396
|
});
|
|
@@ -404,7 +399,7 @@
|
|
|
404
399
|
var evictedKeys = keys(evictedRecords);
|
|
405
400
|
if (evictedKeys.length > 0) {
|
|
406
401
|
durableStoreOperations.push({
|
|
407
|
-
type:
|
|
402
|
+
type: 'evictEntries',
|
|
408
403
|
ids: evictedKeys,
|
|
409
404
|
segment: DefaultDurableSegment,
|
|
410
405
|
});
|
|
@@ -521,6 +516,7 @@
|
|
|
521
516
|
var durableStore = _a.durableStore, instrumentation = _a.instrumentation;
|
|
522
517
|
var ingestStagingStore = null;
|
|
523
518
|
var durableTTLStore = new DurableTTLStore(durableStore);
|
|
519
|
+
var mergeKeysPromiseMap = new Map();
|
|
524
520
|
var initializationPromise = new Promise(function (resolve) {
|
|
525
521
|
var finish = function () {
|
|
526
522
|
resolve();
|
|
@@ -784,52 +780,114 @@
|
|
|
784
780
|
}
|
|
785
781
|
return {};
|
|
786
782
|
};
|
|
787
|
-
var handleSuccessResponse = function (ingestAndBroadcastFunc, getResponseCacheKeysFunc
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
783
|
+
var handleSuccessResponse = function (ingestAndBroadcastFunc, getResponseCacheKeysFunc) {
|
|
784
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
785
|
+
var cacheKeySet, cacheKeySetKeys, keysToRevive, _i, cacheKeySetKeys_1, cacheKeySetKey, cacheKey, snapshotFromMemoryIngest, keysAsArray, readWritePromise, _a, keysAsArray_1, key, _b, keysAsArray_2, key, pendingPromise, _c, select, refresh, result;
|
|
786
|
+
var _this = this;
|
|
787
|
+
return __generator(this, function (_d) {
|
|
788
|
+
switch (_d.label) {
|
|
789
|
+
case 0:
|
|
790
|
+
validateNotDisposed();
|
|
791
|
+
cacheKeySet = getResponseCacheKeysFunc();
|
|
792
|
+
cacheKeySetKeys = keys(cacheKeySet);
|
|
793
|
+
keysToRevive = {};
|
|
794
|
+
for (_i = 0, cacheKeySetKeys_1 = cacheKeySetKeys; _i < cacheKeySetKeys_1.length; _i++) {
|
|
795
|
+
cacheKeySetKey = cacheKeySetKeys_1[_i];
|
|
796
|
+
cacheKey = cacheKeySet[cacheKeySetKey];
|
|
797
|
+
if (cacheKey.mergeable === true) {
|
|
798
|
+
keysToRevive[cacheKeySetKey] = true;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
snapshotFromMemoryIngest = undefined;
|
|
802
|
+
keysAsArray = keys(keysToRevive);
|
|
803
|
+
if (!(keysAsArray.length > 0)) return [3 /*break*/, 5];
|
|
804
|
+
readWritePromise = (function () { return __awaiter(_this, void 0, void 0, function () {
|
|
805
|
+
var pendingPromises, _i, keysAsArray_3, key, pendingPromise, entries;
|
|
806
|
+
return __generator(this, function (_a) {
|
|
807
|
+
switch (_a.label) {
|
|
808
|
+
case 0:
|
|
809
|
+
pendingPromises = [];
|
|
810
|
+
for (_i = 0, keysAsArray_3 = keysAsArray; _i < keysAsArray_3.length; _i++) {
|
|
811
|
+
key = keysAsArray_3[_i];
|
|
812
|
+
pendingPromise = mergeKeysPromiseMap.get(key);
|
|
813
|
+
if (pendingPromise !== undefined) {
|
|
814
|
+
// IMPORTANT: while on the synchronous code path we get a
|
|
815
|
+
// handle to pendingPromise and push it onto the array.
|
|
816
|
+
// This is important because later in this synchronous code
|
|
817
|
+
// path we will upsert readWritePromise into the
|
|
818
|
+
// mergeKeysPromiseMap (essentially overwriting pendingPromise
|
|
819
|
+
// in the map).
|
|
820
|
+
pendingPromises.push(pendingPromise);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return [4 /*yield*/, Promise.all(pendingPromises)];
|
|
824
|
+
case 1:
|
|
825
|
+
_a.sent();
|
|
826
|
+
return [4 /*yield*/, durableStore.getEntries(keysAsArray, DefaultDurableSegment)];
|
|
827
|
+
case 2:
|
|
828
|
+
entries = _a.sent();
|
|
829
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
830
|
+
publishDurableStoreEntries(entries, ingestStagingStore.publish.bind(ingestStagingStore),
|
|
831
|
+
// we don't need to prime metadata
|
|
832
|
+
function () { });
|
|
833
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
834
|
+
return [4 /*yield*/, publishChangesToDurableStore()];
|
|
835
|
+
case 3:
|
|
836
|
+
_a.sent();
|
|
837
|
+
return [2 /*return*/];
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}); })();
|
|
841
|
+
for (_a = 0, keysAsArray_1 = keysAsArray; _a < keysAsArray_1.length; _a++) {
|
|
842
|
+
key = keysAsArray_1[_a];
|
|
843
|
+
// we are overwriting the previous promise at this key, but that
|
|
844
|
+
// is ok because we got a handle to it earlier (see the IMPORTANT
|
|
845
|
+
// comment about 35 lines up)
|
|
846
|
+
mergeKeysPromiseMap.set(key, readWritePromise);
|
|
847
|
+
}
|
|
848
|
+
_d.label = 1;
|
|
849
|
+
case 1:
|
|
850
|
+
_d.trys.push([1, , 3, 4]);
|
|
851
|
+
return [4 /*yield*/, readWritePromise];
|
|
852
|
+
case 2:
|
|
853
|
+
_d.sent();
|
|
854
|
+
return [3 /*break*/, 4];
|
|
855
|
+
case 3:
|
|
856
|
+
for (_b = 0, keysAsArray_2 = keysAsArray; _b < keysAsArray_2.length; _b++) {
|
|
857
|
+
key = keysAsArray_2[_b];
|
|
858
|
+
pendingPromise = mergeKeysPromiseMap.get(key);
|
|
859
|
+
// cleanup the entry from the map if this is the last promise
|
|
860
|
+
// for that key
|
|
861
|
+
if (pendingPromise === readWritePromise) {
|
|
862
|
+
mergeKeysPromiseMap.delete(key);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return [7 /*endfinally*/];
|
|
866
|
+
case 4: return [3 /*break*/, 7];
|
|
867
|
+
case 5:
|
|
868
|
+
// we aren't doing any merging so we don't have to synchronize, the
|
|
869
|
+
// underlying DurableStore implementation takes care of R/W sync
|
|
870
|
+
// so all we have to do is ingest then write to L2
|
|
871
|
+
ingestStagingStore = buildIngestStagingStore(environment);
|
|
872
|
+
snapshotFromMemoryIngest = ingestAndBroadcastFunc();
|
|
873
|
+
return [4 /*yield*/, publishChangesToDurableStore()];
|
|
874
|
+
case 6:
|
|
875
|
+
_d.sent();
|
|
876
|
+
_d.label = 7;
|
|
877
|
+
case 7:
|
|
878
|
+
if (snapshotFromMemoryIngest === undefined) {
|
|
879
|
+
return [2 /*return*/, undefined];
|
|
880
|
+
}
|
|
881
|
+
if (snapshotFromMemoryIngest.state !== 'Unfulfilled') {
|
|
882
|
+
return [2 /*return*/, snapshotFromMemoryIngest];
|
|
883
|
+
}
|
|
884
|
+
_c = snapshotFromMemoryIngest, select = _c.select, refresh = _c.refresh;
|
|
885
|
+
return [4 /*yield*/, reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, function () { return environment.storeLookup(select, environment.createSnapshot, refresh); })];
|
|
886
|
+
case 8:
|
|
887
|
+
result = _d.sent();
|
|
888
|
+
return [2 /*return*/, result.snapshot];
|
|
811
889
|
}
|
|
812
|
-
// if snapshot from staging store lookup is unfulfilled then do an L2 lookup
|
|
813
|
-
return reviveSnapshot(environment, durableStore, snapshotFromMemoryIngest, durableStoreErrorHandler, function () {
|
|
814
|
-
return environment.storeLookup(snapshotFromMemoryIngest.select, environment.createSnapshot, snapshotFromMemoryIngest.refresh);
|
|
815
|
-
}).then(function (result) {
|
|
816
|
-
return result.snapshot;
|
|
817
|
-
});
|
|
818
890
|
});
|
|
819
|
-
};
|
|
820
|
-
if (keys(keysToRevive).length === 0) {
|
|
821
|
-
return ingestAndPublish({});
|
|
822
|
-
}
|
|
823
|
-
return durableStore
|
|
824
|
-
.getEntries(keys(keysToRevive), DefaultDurableSegment)
|
|
825
|
-
.then(function (entries) {
|
|
826
|
-
var existingL2Records = create(null);
|
|
827
|
-
publishDurableStoreEntries(entries, function (key, record) {
|
|
828
|
-
existingL2Records[key] = record;
|
|
829
|
-
},
|
|
830
|
-
// we don't need to prime metadata
|
|
831
|
-
function () { });
|
|
832
|
-
return ingestAndPublish(existingL2Records);
|
|
833
891
|
});
|
|
834
892
|
};
|
|
835
893
|
var handleErrorResponse = function (ingestAndBroadcastFunc) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Environment, RecordSource, InMemoryStore } from '@luvio/engine';
|
|
2
2
|
import type { DurableStore } from './DurableStore';
|
|
3
3
|
import type { InstrumentationFunction } from './makeDurable/error';
|
|
4
4
|
import type { TTLOverridesMap } from './DurableTTLStore';
|
|
@@ -25,12 +25,6 @@ export interface DurableEnvironment extends Environment {
|
|
|
25
25
|
* flow, otherwise returns an empty object.
|
|
26
26
|
*/
|
|
27
27
|
getIngestStagingStoreMetadata(): InMemoryStore['metadata'];
|
|
28
|
-
/**
|
|
29
|
-
* Overload of Environment.handleSuccessResponse that takes in an optional
|
|
30
|
-
* RecordSource to "prime" the ingest staging store with before calling
|
|
31
|
-
* ingest. Useful for merge-able record types
|
|
32
|
-
*/
|
|
33
|
-
handleSuccessResponse<IngestionReturnType extends Snapshot<D, V> | undefined, D, V = unknown>(ingestAndBroadcastFunc: () => IngestionReturnType, getResponseCacheKeysFunc: () => CacheKeySet, existingRecords?: RecordSource): IngestionReturnType | Promise<IngestionReturnType>;
|
|
34
28
|
}
|
|
35
29
|
export declare const AdapterContextSegment = "ADAPTER-CONTEXT";
|
|
36
30
|
export declare const ADAPTER_CONTEXT_ID_SUFFIX = "__NAMED_CONTEXT";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/environments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.108.0",
|
|
4
4
|
"description": "Luvio Environments",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"watch": "yarn build --watch"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@luvio/engine": "0.
|
|
26
|
+
"@luvio/engine": "0.108.0"
|
|
27
27
|
},
|
|
28
28
|
"bundlesize": [
|
|
29
29
|
{
|