Add timestamps to cache entries and server events (#19976)
This commit is contained in:
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@umbraco-cms/backoffice/external/backend-api';
|
} from '@umbraco-cms/backoffice/external/backend-api';
|
||||||
import {
|
import {
|
||||||
UmbManagementApiDetailDataRequestManager,
|
UmbManagementApiDetailDataRequestManager,
|
||||||
UmbManagementApiInflightRequestCache,
|
UmbManagementApiInFlightRequestCache,
|
||||||
} from '@umbraco-cms/backoffice/management-api';
|
} from '@umbraco-cms/backoffice/management-api';
|
||||||
|
|
||||||
export class UmbManagementApiDataTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager<
|
export class UmbManagementApiDataTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager<
|
||||||
@@ -17,7 +17,7 @@ export class UmbManagementApiDataTypeDetailDataRequestManager extends UmbManagem
|
|||||||
UpdateDataTypeRequestModel,
|
UpdateDataTypeRequestModel,
|
||||||
CreateDataTypeRequestModel
|
CreateDataTypeRequestModel
|
||||||
> {
|
> {
|
||||||
static #inflightRequestCache = new UmbManagementApiInflightRequestCache<DataTypeResponseModel>();
|
static #inflightRequestCache = new UmbManagementApiInFlightRequestCache<DataTypeResponseModel>();
|
||||||
|
|
||||||
constructor(host: UmbControllerHost) {
|
constructor(host: UmbControllerHost) {
|
||||||
super(host, {
|
super(host, {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@umbraco-cms/backoffice/external/backend-api';
|
} from '@umbraco-cms/backoffice/external/backend-api';
|
||||||
import {
|
import {
|
||||||
UmbManagementApiDetailDataRequestManager,
|
UmbManagementApiDetailDataRequestManager,
|
||||||
UmbManagementApiInflightRequestCache,
|
UmbManagementApiInFlightRequestCache,
|
||||||
} from '@umbraco-cms/backoffice/management-api';
|
} from '@umbraco-cms/backoffice/management-api';
|
||||||
|
|
||||||
export class UmbManagementApiDocumentTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager<
|
export class UmbManagementApiDocumentTypeDetailDataRequestManager extends UmbManagementApiDetailDataRequestManager<
|
||||||
@@ -17,7 +17,7 @@ export class UmbManagementApiDocumentTypeDetailDataRequestManager extends UmbMan
|
|||||||
UpdateDocumentTypeRequestModel,
|
UpdateDocumentTypeRequestModel,
|
||||||
CreateDocumentTypeRequestModel
|
CreateDocumentTypeRequestModel
|
||||||
> {
|
> {
|
||||||
static #inflightRequestCache = new UmbManagementApiInflightRequestCache<DocumentTypeResponseModel>();
|
static #inflightRequestCache = new UmbManagementApiInFlightRequestCache<DocumentTypeResponseModel>();
|
||||||
|
|
||||||
constructor(host: UmbControllerHost) {
|
constructor(host: UmbControllerHost) {
|
||||||
super(host, {
|
super(host, {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// Keep internal
|
// Keep internal
|
||||||
interface UmbCacheEntryModel<DetailDataModelType> {
|
interface UmbDetailCacheEntryModel<DetailDataModelType> {
|
||||||
id: string;
|
id: string;
|
||||||
data: DetailDataModelType;
|
data: DetailDataModelType;
|
||||||
|
timestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,7 +11,7 @@ interface UmbCacheEntryModel<DetailDataModelType> {
|
|||||||
* @template DetailDataModelType
|
* @template DetailDataModelType
|
||||||
*/
|
*/
|
||||||
export class UmbManagementApiDetailDataCache<DetailDataModelType> {
|
export class UmbManagementApiDetailDataCache<DetailDataModelType> {
|
||||||
#entries: Map<string, UmbCacheEntryModel<DetailDataModelType>> = new Map();
|
#entries: Map<string, UmbDetailCacheEntryModel<DetailDataModelType>> = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if an entry exists in the cache
|
* Checks if an entry exists in the cache
|
||||||
@@ -29,9 +30,10 @@ export class UmbManagementApiDetailDataCache<DetailDataModelType> {
|
|||||||
* @memberof UmbManagementApiDetailDataCache
|
* @memberof UmbManagementApiDetailDataCache
|
||||||
*/
|
*/
|
||||||
set(id: string, data: DetailDataModelType): void {
|
set(id: string, data: DetailDataModelType): void {
|
||||||
const cacheEntry: UmbCacheEntryModel<DetailDataModelType> = {
|
const cacheEntry: UmbDetailCacheEntryModel<DetailDataModelType> = {
|
||||||
id: id,
|
id: id,
|
||||||
data,
|
data,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.#entries.set(id, cacheEntry);
|
this.#entries.set(id, cacheEntry);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { UMB_MANAGEMENT_API_SERVER_EVENT_CONTEXT } from '../server-event/constants.js';
|
import { UMB_MANAGEMENT_API_SERVER_EVENT_CONTEXT } from '../server-event/constants.js';
|
||||||
import type { UmbManagementApiInflightRequestCache } from '../inflight-request/cache.js';
|
import type { UmbManagementApiInFlightRequestCache } from '../inflight-request/cache.js';
|
||||||
import type { UmbManagementApiDetailDataCache } from './cache.js';
|
import type { UmbManagementApiDetailDataCache } from './cache.js';
|
||||||
import {
|
import {
|
||||||
tryExecute,
|
tryExecute,
|
||||||
@@ -21,7 +21,7 @@ export interface UmbManagementApiDetailDataRequestManagerArgs<
|
|||||||
update: (id: string, data: UpdateRequestModelType) => Promise<UmbApiResponse<{ data: unknown }>>;
|
update: (id: string, data: UpdateRequestModelType) => Promise<UmbApiResponse<{ data: unknown }>>;
|
||||||
delete: (id: string) => Promise<UmbApiResponse<{ data: unknown }>>;
|
delete: (id: string) => Promise<UmbApiResponse<{ data: unknown }>>;
|
||||||
dataCache: UmbManagementApiDetailDataCache<DetailResponseModelType>;
|
dataCache: UmbManagementApiDetailDataCache<DetailResponseModelType>;
|
||||||
inflightRequestCache: UmbManagementApiInflightRequestCache<DetailResponseModelType>;
|
inflightRequestCache: UmbManagementApiInFlightRequestCache<DetailResponseModelType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UmbManagementApiDetailDataRequestManager<
|
export class UmbManagementApiDetailDataRequestManager<
|
||||||
@@ -30,7 +30,7 @@ export class UmbManagementApiDetailDataRequestManager<
|
|||||||
UpdateRequestModelType,
|
UpdateRequestModelType,
|
||||||
> extends UmbControllerBase {
|
> extends UmbControllerBase {
|
||||||
#dataCache: UmbManagementApiDetailDataCache<DetailResponseModelType>;
|
#dataCache: UmbManagementApiDetailDataCache<DetailResponseModelType>;
|
||||||
#inflightRequestCache: UmbManagementApiInflightRequestCache<DetailResponseModelType>;
|
#inflightRequestCache: UmbManagementApiInFlightRequestCache<DetailResponseModelType>;
|
||||||
|
|
||||||
#create;
|
#create;
|
||||||
#read;
|
#read;
|
||||||
@@ -86,11 +86,13 @@ export class UmbManagementApiDetailDataRequestManager<
|
|||||||
const hasInflightRequest = this.#inflightRequestCache.has(inflightCacheKey);
|
const hasInflightRequest = this.#inflightRequestCache.has(inflightCacheKey);
|
||||||
|
|
||||||
const request = hasInflightRequest
|
const request = hasInflightRequest
|
||||||
? this.#inflightRequestCache.get(inflightCacheKey)
|
? this.#inflightRequestCache.get(inflightCacheKey)?.requestPromise
|
||||||
: tryExecute(this, this.#read(id));
|
: tryExecute(this, this.#read(id));
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
throw new Error(`Failed to create or retrieve 'read' request for ID: ${id} (cache key: ${inflightCacheKey}). Aborting read.`);
|
throw new Error(
|
||||||
|
`Failed to create or retrieve 'read' request for ID: ${id} (cache key: ${inflightCacheKey}). Aborting read.`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#inflightRequestCache.set(inflightCacheKey, request);
|
this.#inflightRequestCache.set(inflightCacheKey, request);
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import type { UmbApiResponse } from '@umbraco-cms/backoffice/resources';
|
import type { UmbApiResponse } from '@umbraco-cms/backoffice/resources';
|
||||||
|
|
||||||
|
interface UmbInFlightRequestCacheEntryModel<ResponseModelType> {
|
||||||
|
key: string;
|
||||||
|
requestPromise: Promise<RequestResolvedType<ResponseModelType>>;
|
||||||
|
timestamp: string;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep internal
|
// Keep internal
|
||||||
type RequestResolvedType<ResponseModelType> = UmbApiResponse<{ data?: ResponseModelType }>;
|
type RequestResolvedType<ResponseModelType> = UmbApiResponse<{ data?: ResponseModelType }>;
|
||||||
|
|
||||||
@@ -8,8 +14,8 @@ type RequestResolvedType<ResponseModelType> = UmbApiResponse<{ data?: ResponseMo
|
|||||||
* @class UmbManagementApiInflightRequestCache
|
* @class UmbManagementApiInflightRequestCache
|
||||||
* @template ResponseModelType
|
* @template ResponseModelType
|
||||||
*/
|
*/
|
||||||
export class UmbManagementApiInflightRequestCache<ResponseModelType> {
|
export class UmbManagementApiInFlightRequestCache<ResponseModelType> {
|
||||||
#entries = new Map<string, Promise<RequestResolvedType<ResponseModelType>>>();
|
#entries = new Map<string, UmbInFlightRequestCacheEntryModel<ResponseModelType>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if an entry exists in the cache
|
* Checks if an entry exists in the cache
|
||||||
@@ -28,7 +34,11 @@ export class UmbManagementApiInflightRequestCache<ResponseModelType> {
|
|||||||
* @memberof UmbManagementApiInflightRequestCache
|
* @memberof UmbManagementApiInflightRequestCache
|
||||||
*/
|
*/
|
||||||
set(key: string, promise: Promise<RequestResolvedType<ResponseModelType>>): void {
|
set(key: string, promise: Promise<RequestResolvedType<ResponseModelType>>): void {
|
||||||
this.#entries.set(key, promise);
|
this.#entries.set(key, {
|
||||||
|
key,
|
||||||
|
requestPromise: promise,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,7 +47,7 @@ export class UmbManagementApiInflightRequestCache<ResponseModelType> {
|
|||||||
* @returns {Promise<RequestResolvedType<ResponseModelType>> | undefined} - The cached promise or undefined if not found
|
* @returns {Promise<RequestResolvedType<ResponseModelType>> | undefined} - The cached promise or undefined if not found
|
||||||
* @memberof UmbManagementApiInflightRequestCache
|
* @memberof UmbManagementApiInflightRequestCache
|
||||||
*/
|
*/
|
||||||
get(key: string): Promise<RequestResolvedType<ResponseModelType>> | undefined {
|
get(key: string): UmbInFlightRequestCacheEntryModel<ResponseModelType> | undefined {
|
||||||
return this.#entries.get(key);
|
return this.#entries.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// Keep internal
|
// Keep internal
|
||||||
interface UmbCacheEntryModel<ItemDataModelType> {
|
interface UmbItemCacheEntryModel<ItemDataModelType> {
|
||||||
id: string;
|
id: string;
|
||||||
data: ItemDataModelType;
|
data: ItemDataModelType;
|
||||||
|
timestamp: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,7 +11,7 @@ interface UmbCacheEntryModel<ItemDataModelType> {
|
|||||||
* @template ItemDataModelType
|
* @template ItemDataModelType
|
||||||
*/
|
*/
|
||||||
export class UmbManagementApiItemDataCache<ItemDataModelType> {
|
export class UmbManagementApiItemDataCache<ItemDataModelType> {
|
||||||
#entries: Map<string, UmbCacheEntryModel<ItemDataModelType>> = new Map();
|
#entries: Map<string, UmbItemCacheEntryModel<ItemDataModelType>> = new Map();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if an entry exists in the cache
|
* Checks if an entry exists in the cache
|
||||||
@@ -29,9 +30,10 @@ export class UmbManagementApiItemDataCache<ItemDataModelType> {
|
|||||||
* @memberof UmbManagementApiItemDataCache
|
* @memberof UmbManagementApiItemDataCache
|
||||||
*/
|
*/
|
||||||
set(id: string, data: ItemDataModelType): void {
|
set(id: string, data: ItemDataModelType): void {
|
||||||
const cacheEntry: UmbCacheEntryModel<ItemDataModelType> = {
|
const cacheEntry: UmbItemCacheEntryModel<ItemDataModelType> = {
|
||||||
id: id,
|
id: id,
|
||||||
data,
|
data,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.#entries.set(id, cacheEntry);
|
this.#entries.set(id, cacheEntry);
|
||||||
|
|||||||
@@ -94,8 +94,13 @@ export class UmbManagementApiServerEventContext extends UmbContextBase {
|
|||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.#connection.on('notify', (payload: UmbManagementApiServerEventModel) => {
|
this.#connection.on('notify', (payload) => {
|
||||||
this.#events.next(payload);
|
const event: UmbManagementApiServerEventModel = {
|
||||||
|
...payload,
|
||||||
|
clientTimestamp: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#events.next(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#connection
|
this.#connection
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export interface UmbManagementApiServerEventModel {
|
|||||||
eventSource: string;
|
eventSource: string;
|
||||||
eventType: string;
|
eventType: string;
|
||||||
key: string;
|
key: string;
|
||||||
|
clientTimestamp: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user