commit 5885cc498cf4effb4774305383e24eddb2910019
parent 48764f27bc67764112665b792668099c9d175eb5
Author: Iván Ávalos <avalos@disroot.org>
Date: Wed, 11 Mar 2026 16:12:32 +0100
wallet-core: improved performance stats
Diffstat:
5 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/packages/taler-util/src/notifications.ts b/packages/taler-util/src/notifications.ts
@@ -248,6 +248,7 @@ export type ObservabilityEvent =
when: AbsoluteTime;
type: ObservabilityEventType.HttpFetchStart;
url: string;
+ longPolling: boolean;
}
| {
id: string;
@@ -256,6 +257,7 @@ export type ObservabilityEvent =
url: string;
status: number;
durationMs: number;
+ longPolling: boolean;
}
| {
id: string;
@@ -264,6 +266,7 @@ export type ObservabilityEvent =
url: string;
error: TalerErrorDetail;
durationMs: number;
+ longPolling: boolean;
}
| {
type: ObservabilityEventType.DbQueryStart;
diff --git a/packages/taler-util/src/observability.ts b/packages/taler-util/src/observability.ts
@@ -66,6 +66,7 @@ export class ObservableHttpClientLibrary implements HttpRequestLibrary {
when: AbsoluteTime.now(),
type: ObservabilityEventType.HttpFetchStart,
url: url,
+ longPolling: !opt?.cancellationToken,
});
const optsWithCancel = opt ?? {};
@@ -81,6 +82,7 @@ export class ObservableHttpClientLibrary implements HttpRequestLibrary {
url,
status: res.status,
durationMs: performanceDelta(start, end),
+ longPolling: !opt?.cancellationToken,
};
this.oc.observe(event);
return res;
@@ -93,6 +95,7 @@ export class ObservableHttpClientLibrary implements HttpRequestLibrary {
url,
error: getErrorDetailFromException(e),
durationMs: performanceDelta(start, end),
+ longPolling: !opt?.cancellationToken,
});
throw e;
} finally {
diff --git a/packages/taler-util/src/performance.ts b/packages/taler-util/src/performance.ts
@@ -37,32 +37,47 @@ export type PerformanceStat =
| {
type: PerformanceStatType.HttpFetch;
url: string;
+ avgDurationMs: number;
maxDurationMs: number;
+ minDurationMs: number;
+ totalDurationMs: number;
count: number;
}
| {
type: PerformanceStatType.DbQuery;
name: string;
location: string;
+ avgDurationMs: number;
maxDurationMs: number;
+ minDurationMs: number;
+ totalDurationMs: number;
count: number;
}
| {
type: PerformanceStatType.Crypto;
operation: string;
+ avgDurationMs: number;
maxDurationMs: number;
+ minDurationMs: number;
+ totalDurationMs: number;
count: number;
}
| {
type: PerformanceStatType.WalletRequest;
operation: string;
+ avgDurationMs: number;
maxDurationMs: number;
+ minDurationMs: number;
+ totalDurationMs: number;
count: number;
}
| {
type: PerformanceStatType.WalletTask;
taskId: string;
+ avgDurationMs: number;
maxDurationMs: number;
+ minDurationMs: number;
+ totalDurationMs: number;
count: number;
};
@@ -71,13 +86,17 @@ export namespace PerformanceStat {
evt: ObservabilityEvent & { durationMs: number },
): PerformanceStat | undefined {
if (
- evt.type === ObservabilityEventType.HttpFetchFinishSuccess ||
- evt.type === ObservabilityEventType.HttpFetchFinishError
+ (evt.type === ObservabilityEventType.HttpFetchFinishSuccess ||
+ evt.type === ObservabilityEventType.HttpFetchFinishError
+ ) && !evt.longPolling
) {
return {
type: PerformanceStatType.HttpFetch,
url: evt.url,
+ avgDurationMs: evt.durationMs,
maxDurationMs: evt.durationMs,
+ minDurationMs: evt.durationMs,
+ totalDurationMs: evt.durationMs,
count: 1,
};
} else if (
@@ -88,7 +107,10 @@ export namespace PerformanceStat {
type: PerformanceStatType.DbQuery,
name: evt.name,
location: evt.location,
+ avgDurationMs: evt.durationMs,
maxDurationMs: evt.durationMs,
+ minDurationMs: evt.durationMs,
+ totalDurationMs: evt.durationMs,
count: 1,
};
} else if (
@@ -98,7 +120,10 @@ export namespace PerformanceStat {
return {
type: PerformanceStatType.Crypto,
operation: evt.operation,
+ avgDurationMs: evt.durationMs,
maxDurationMs: evt.durationMs,
+ minDurationMs: evt.durationMs,
+ totalDurationMs: evt.durationMs,
count: 1,
};
} else if (
@@ -108,14 +133,20 @@ export namespace PerformanceStat {
return {
type: PerformanceStatType.WalletRequest,
operation: evt.operation,
+ avgDurationMs: evt.durationMs,
maxDurationMs: evt.durationMs,
+ minDurationMs: evt.durationMs,
+ totalDurationMs: evt.durationMs,
count: 1,
};
} else if (evt.type === ObservabilityEventType.ShepherdTaskResult) {
return {
type: PerformanceStatType.WalletTask,
taskId: evt.taskId,
+ avgDurationMs: evt.durationMs,
maxDurationMs: evt.durationMs,
+ minDurationMs: evt.durationMs,
+ totalDurationMs: evt.durationMs,
count: 1,
};
}
@@ -198,7 +229,10 @@ export namespace PerformanceTable {
tab[stat.type]?.push(stat);
} else {
const existing = tab[stat.type]!![index];
+ existing.avgDurationMs = Math.floor((existing.avgDurationMs + stat.totalDurationMs) / 2);
existing.maxDurationMs = Math.max(existing.maxDurationMs, stat.maxDurationMs);
+ existing.minDurationMs = Math.min(existing.minDurationMs, stat.minDurationMs);
+ existing.totalDurationMs = existing.totalDurationMs + stat.totalDurationMs;
existing.count += 1;
tab[stat.type]!![index] = existing;
}
@@ -210,7 +244,7 @@ export namespace PerformanceTable {
function sort(tab: PerformanceTable) {
for (const k of Object.keys(tab)) {
const key = k as keyof typeof tab
- tab[key]!!.sort((a, b) => b.maxDurationMs - a.maxDurationMs);
+ tab[key]!!.sort((a, b) => b.avgDurationMs - a.avgDurationMs);
}
}
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
@@ -4522,7 +4522,7 @@ export interface GetBankingChoicesForPaytoResponse {
export interface GetPerformanceStatsRequest {
/**
- * Limit to N largest performance stats of each table.
+ * Limit to N largest average performance stats of each table.
*
* When undefined, all performance stats will be returned.
*/
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -1531,8 +1531,8 @@ export type GetActiveTasksOp = {
* current running wallet instance are generated from observability events and
* stored in memory.
*
- * Under each table, only the highest duration for each operation
- * (e.g. `getBalances` wallet request) is included.
+ * Under each table, different types of duration for each operation
+ * (e.g. `getBalances` wallet request) are included.
*/
export type GetPerformanceStatsOp = {
op: WalletApiOperation.TestingGetPerformanceStats;