From 61b645bb776b4397f5e22e20e7ff0c9bdbb911eb Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 12:54:10 +0100 Subject: [PATCH 01/22] redis statistics --- .gitignore | 1 + src/dbHandler.js | 127 +++++++++--- src/shared/eventQueueStats.js | 146 ++++++++++++++ test/dbHandlerStats.test.js | 365 ++++++++++++++++++++++++++++++++++ test/eventQueueStats.test.js | 134 +++++++++++++ test/mocks/redisMock.js | 63 +++++- test/redisPubSub.test.js | 2 + 7 files changed, 812 insertions(+), 26 deletions(-) create mode 100644 src/shared/eventQueueStats.js create mode 100644 test/dbHandlerStats.test.js create mode 100644 test/eventQueueStats.test.js diff --git a/.gitignore b/.gitignore index 7ca70254..9c6cb6df 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ **/.project **/.settings *.code-workspace +CLAUDE.md # package managers bower_components/ diff --git a/src/dbHandler.js b/src/dbHandler.js index 030db39d..74e1169c 100644 --- a/src/dbHandler.js +++ b/src/dbHandler.js @@ -4,11 +4,14 @@ const cds = require("@sap/cds"); const redisPub = require("./redis/redisPub"); const config = require("./config"); +const eventQueueStats = require("./shared/eventQueueStats"); +const { EventProcessingStatus } = require("./constants"); const COMPONENT_NAME = "/eventQueue/dbHandler"; const registeredHandlers = { eventQueueDbHandler: false, beforeDbHandler: false, + updateDbHandler: false, }; const registerEventQueueDbHandler = (dbService) => { @@ -26,36 +29,112 @@ const registerEventQueueDbHandler = (dbService) => { req.tx._.eventQueuePublishEvents = req.tx._.eventQueuePublishEvents ?? {}; const eventQueuePublishEvents = req.tx._.eventQueuePublishEvents; const data = Array.isArray(req.query.INSERT.entries) ? req.query.INSERT.entries : [req.query.INSERT.entries]; - const eventCombinations = Object.keys( - data.reduce((result, event) => { - const key = [event.type, event.subType, event.namespace].join("##"); - if ( - !config.hasEventAfterCommitFlag(event.type, event.subType, event.namespace) || - eventQueuePublishEvents[key] - ) { - return result; - } + + req.tx._.eventQueueStatsOpenCount = (req.tx._.eventQueueStatsOpenCount ?? 0) + data.length; + const newCombinations = data.reduce((result, event) => { + const key = [event.type, event.subType, event.namespace].join("##"); + if (config.hasEventAfterCommitFlag(event.type, event.subType, event.namespace) && !eventQueuePublishEvents[key]) { eventQueuePublishEvents[key] = true; - result[key] = true; - return result; - }, {}) - ); + result.push(key); + } + return result; + }, []); - eventCombinations.length && + req.tx._.eventQueueBroadcastCombinations ??= []; + req.tx._.eventQueueBroadcastCombinations.push(...newCombinations); + if (!req.tx._.eventQueueSucceededHandlerRegistered) { + req.tx._.eventQueueSucceededHandlerRegistered = true; req.on("succeeded", () => { - const events = eventCombinations.map((eventCombination) => { - const [type, subType, namespace] = eventCombination.split("##"); - return { type, subType, namespace }; - }); - - redisPub.broadcastEvent(req.tenant, events).catch((err) => { - cds.log(COMPONENT_NAME).error("db handler failure during broadcasting event", err, { - tenant: req.tenant, - events, + if (config.redisEnabled && req.tx._.eventQueueStatsOpenCount) { + eventQueueStats + .incrementCounters(req.tenant, eventQueueStats.StatusField.Pending, req.tx._.eventQueueStatsOpenCount) + .catch((err) => { + cds.log(COMPONENT_NAME).error("db handler failure during updating event stats", err, { + tenant: req.tenant, + }); + }); + } + const combinations = req.tx._.eventQueueBroadcastCombinations; + if (combinations.length) { + const events = combinations.map((combination) => { + const [type, subType, namespace] = combination.split("##"); + return { type, subType, namespace }; }); - }); + redisPub.broadcastEvent(req.tenant, events).catch((err) => { + cds.log(COMPONENT_NAME).error("db handler failure during broadcasting event", err, { + tenant: req.tenant, + events, + }); + }); + } }); + } }); + + if (!registeredHandlers.updateDbHandler) { + registeredHandlers.updateDbHandler = true; + dbService.after("UPDATE", def, (affectedRows, req) => { + const newStatus = req.query.UPDATE?.data?.status; + if (newStatus == null) { + return; + } + + const count = typeof affectedRows === "number" && affectedRows > 0 ? affectedRows : 1; + + req.tx._ = req.tx._ ?? {}; + req.tx._.eventQueueStatsPendingDelta = req.tx._.eventQueueStatsPendingDelta ?? 0; + req.tx._.eventQueueStatsInProgressDelta = req.tx._.eventQueueStatsInProgressDelta ?? 0; + + if (newStatus === EventProcessingStatus.InProgress) { + req.tx._.eventQueueStatsPendingDelta -= count; + req.tx._.eventQueueStatsInProgressDelta += count; + } else if (newStatus === EventProcessingStatus.Error) { + req.tx._.eventQueueStatsInProgressDelta -= count; + req.tx._.eventQueueStatsPendingDelta += count; + } else if ( + newStatus === EventProcessingStatus.Done || + newStatus === EventProcessingStatus.Exceeded || + newStatus === EventProcessingStatus.Suspended + ) { + req.tx._.eventQueueStatsInProgressDelta -= count; + } + + if (!req.tx._.eventQueueUpdateSucceededHandlerRegistered) { + req.tx._.eventQueueUpdateSucceededHandlerRegistered = true; + req.on("succeeded", () => { + if (!config.redisEnabled) { + return; + } + + const pendingDelta = req.tx._.eventQueueStatsPendingDelta; + const inProgressDelta = req.tx._.eventQueueStatsInProgressDelta; + const ops = []; + + if (pendingDelta !== 0) { + ops.push( + eventQueueStats.adjustTenantCounter(req.tenant, eventQueueStats.StatusField.Pending, pendingDelta), + eventQueueStats.adjustGlobalCounter(eventQueueStats.StatusField.Pending, pendingDelta) + ); + } + if (inProgressDelta !== 0) { + ops.push( + eventQueueStats.adjustTenantCounter(req.tenant, eventQueueStats.StatusField.InProgress, inProgressDelta), + eventQueueStats.adjustGlobalCounter(eventQueueStats.StatusField.InProgress, inProgressDelta) + ); + } + Promise.allSettled(ops).then((results) => { + for (const result of results) { + if (result.status === "rejected") { + cds + .log(COMPONENT_NAME) + .error("db handler failure during updating event stats on update", result.reason, { tenant: req.tenant }); + } + } + }); + }); + } + }); + } }; module.exports = { diff --git a/src/shared/eventQueueStats.js b/src/shared/eventQueueStats.js new file mode 100644 index 00000000..6e7da197 --- /dev/null +++ b/src/shared/eventQueueStats.js @@ -0,0 +1,146 @@ +"use strict"; + +const cds = require("@sap/cds"); + +const redis = require("./redis"); +const config = require("../config"); + +const COMPONENT_NAME = "/eventQueue/eventQueueStats"; + +const StatusField = { + Pending: "pending", + InProgress: "inProgress", +}; + +const _tenantKey = (tenantId) => `${config.redisNamespace(true)}##stats##tenant##${tenantId}`; +const _globalKey = () => `${config.redisNamespace(true)}##stats##global`; + +/** + * Atomically adjusts a tenant's event counter for the given status field. + * + * @param {string} tenantId + * @param {string} field - one of StatusField.* + * @param {number} increment - positive to increment, negative to decrement + */ +const adjustTenantCounter = async (tenantId, field, increment) => { + const logger = cds.log(COMPONENT_NAME); + try { + const client = await redis.createMainClientAndConnect(); + await client.hIncrBy(_tenantKey(tenantId), field, increment); + } catch (err) { + logger.error("failed to adjust tenant stats counter", err, { tenantId, field, increment }); + } +}; + +/** + * Atomically adjusts the global event counter for the given status field. + * Also updates the `updatedAt` timestamp on the global hash. + * + * @param {string} field - one of StatusField.* + * @param {number} increment - positive to increment, negative to decrement + */ +const adjustGlobalCounter = async (field, increment) => { + const logger = cds.log(COMPONENT_NAME); + try { + const client = await redis.createMainClientAndConnect(); + await client.hIncrBy(_globalKey(), field, increment); + } catch (err) { + logger.error("failed to adjust global stats counter", err, { field, increment }); + } +}; + +/** + * Increments a tenant counter and the matching global counter in a single call. + * + * @param {string} tenantId + * @param {string} field - one of StatusField.* + * @param {number} [increment=1] + */ +const incrementCounters = async (tenantId, field, increment = 1) => { + await Promise.all([adjustTenantCounter(tenantId, field, increment), adjustGlobalCounter(field, increment)]); +}; + +/** + * Decrements a tenant counter and the matching global counter in a single call. + * + * @param {string} tenantId + * @param {string} field - one of StatusField.* + * @param {number} [decrement=1] + */ +const decrementCounters = async (tenantId, field, decrement = 1) => { + await Promise.all([adjustTenantCounter(tenantId, field, -decrement), adjustGlobalCounter(field, -decrement)]); +}; + +/** + * Returns the current stats hash for a single tenant. + * All counter values are returned as integers; missing fields default to 0. + * + * @param {string} tenantId + * @returns {Promise<{open: number, inProgress: number, error: number}>} + */ +const getTenantStats = async (tenantId) => { + const logger = cds.log(COMPONENT_NAME); + try { + const client = await redis.createMainClientAndConnect(); + const raw = await client.hGetAll(_tenantKey(tenantId)); + return _parseCounterHash(raw); + } catch (err) { + logger.error("failed to read tenant stats", err, { tenantId }); + return _emptyCounters(); + } +}; + +/** + * Returns the current global stats hash. + * All counter values are returned as integers; missing fields default to 0. + * + * @returns {Promise<{open: number, inProgress: number, error: number}>} + */ +const getGlobalStats = async () => { + const logger = cds.log(COMPONENT_NAME); + try { + const client = await redis.createMainClientAndConnect(); + const raw = await client.hGetAll(_globalKey()); + return _parseCounterHash(raw); + } catch (err) { + logger.error("failed to read global stats", err); + return _emptyCounters(); + } +}; + +/** + * Deletes the stats hash for a specific tenant. + * Intended for use during tenant offboarding. It does not adjust the global stats still will be fixed with the next global run + * + * @param {string} tenantId + */ +const deleteTenantStats = async (tenantId) => { + const logger = cds.log(COMPONENT_NAME); + try { + const client = await redis.createMainClientAndConnect(); + await client.del(_tenantKey(tenantId)); + } catch (err) { + logger.error("failed to delete tenant stats", err, { tenantId }); + } +}; + +const _parseCounterHash = (raw) => ({ + [StatusField.Pending]: raw[StatusField.Pending] != null ? parseInt(raw[StatusField.Pending]) : 0, + [StatusField.InProgress]: raw[StatusField.InProgress] != null ? parseInt(raw[StatusField.InProgress]) : 0, +}); + +const _emptyCounters = () => ({ + [StatusField.Pending]: 0, + [StatusField.InProgress]: 0, +}); + +module.exports = { + StatusField, + incrementCounters, + decrementCounters, + adjustTenantCounter, + adjustGlobalCounter, + getTenantStats, + getGlobalStats, + deleteTenantStats, +}; diff --git a/test/dbHandlerStats.test.js b/test/dbHandlerStats.test.js new file mode 100644 index 00000000..e50cb869 --- /dev/null +++ b/test/dbHandlerStats.test.js @@ -0,0 +1,365 @@ +"use strict"; + +const path = require("path"); + +const mockRedis = require("./mocks/redisMock"); +jest.mock("../src/shared/redis", () => mockRedis); + +const cds = require("@sap/cds/lib"); + +const eventQueue = require("../src"); +const config = require("../src/config"); +const { getTenantStats, getGlobalStats, StatusField } = require("../src/shared/eventQueueStats"); +const { EventProcessingStatus } = require("../src/constants"); +const { processEventQueue } = require("../src/processEventQueue"); +const testHelper = require("./helper"); +const { Logger: mockLogger } = require("./mocks/logger"); + +const outboxProject = path.join(__dirname, "asset", "outboxProject"); + +cds.env.requires.StandardService = { + impl: path.join(outboxProject, "srv/service/standard-service.js"), + outbox: { kind: "persistent-outbox" }, +}; + +cds.env.requires.NotificationService = { + impl: path.join(outboxProject, "srv/service/service.js"), + outbox: { kind: "persistent-outbox" }, +}; + +cds.test(outboxProject); + +describe("dbHandler - stats tracking via CAP outbox", () => { + let context, tx, loggerMock; + + beforeAll(async () => { + eventQueue.config.initialized = false; + await eventQueue.initialize({ + processEventsAfterPublish: false, + registerAsEventProcessor: false, + insertEventsBeforeCommit: true, + useAsCAPOutbox: true, + userId: "dummyTestUser", + }); + cds.emit("connect", await cds.connect.to("db")); + config.redisEnabled = true; + eventQueue.registerEventQueueDbHandler(cds.db); + loggerMock = mockLogger(); + }); + + beforeEach(async () => { + context = new cds.EventContext({ user: "testUser", tenant: 123 }); + tx = cds.tx(context); + await tx.run(DELETE.from("sap.eventqueue.Lock")); + await tx.run(DELETE.from("sap.eventqueue.Event")); + await commitAndOpenNew(); + mockRedis.clearState(); + jest.clearAllMocks(); + }); + + afterEach(async () => { + await tx.rollback(); + }); + + afterAll(async () => { + config.redisEnabled = false; + await cds.shutdown; + }); + + // ── CREATE handler tests ──────────────────────────────────────────────────── + + it("increments pending counter by 1 after single send and commit", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(1); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(1); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("accumulates pending counter for multiple sends in same transaction", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(3); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(3); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("does not increment counter when transaction is rolled back", async () => { + const innerTx = cds.tx(context); + const service = (await cds.connect.to("StandardService")).tx(innerTx.context); + await service.send("main", {}); + await innerTx.rollback(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + }); + + it("does not increment counter when redisEnabled is false", async () => { + config.redisEnabled = false; + try { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + } finally { + config.redisEnabled = true; + } + }); + + it("tracks stats per tenant while global counter aggregates", async () => { + // tenant 123: send 2 events + const service123 = (await cds.connect.to("StandardService")).tx(context); + await service123.send("main", {}); + await service123.send("main", {}); + await commitAndOpenNew(); + + // tenant 456: send 1 event in its own tx + const ctx456 = new cds.EventContext({ user: "testUser", tenant: 456 }); + const tx456 = cds.tx(ctx456); + const service456 = (await cds.connect.to("StandardService")).tx(ctx456); + await service456.send("main", {}); + await tx456.commit(); + + const stats123 = await getTenantStats(123); + expect(stats123[StatusField.Pending]).toBe(2); + + const stats456 = await getTenantStats(456); + expect(stats456[StatusField.Pending]).toBe(1); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(3); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + // ── UPDATE handler tests — direct status transitions ──────────────────────── + + describe("UPDATE handler — direct status transitions", () => { + it("Open → InProgress: decrements pending, increments inProgress", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(2); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + expect(globalStats[StatusField.InProgress]).toBe(2); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Done: decrements inProgress, no pending change", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=2 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Done }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Error: decrements inProgress, increments pending (will be retried)", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=2 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Error }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(2); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(2); + expect(globalStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Exceeded: decrements inProgress, no pending change", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=2 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Exceeded }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("two UPDATEs in one transaction accumulate into a single succeeded handler call", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + // Open→InProgress then InProgress→Done without an intermediate commit + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Done }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + // Net delta: pending -2, inProgress +2 then -2 → both counters at 0 + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("does not adjust counters when redisEnabled is false", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + config.redisEnabled = false; + try { + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(2); + expect(tenantStats[StatusField.InProgress]).toBe(0); + } finally { + config.redisEnabled = true; + } + }); + + it("does not adjust counters when transaction is rolled back", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + const innerTx = cds.tx(context); + await innerTx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await innerTx.rollback(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(2); + expect(tenantStats[StatusField.InProgress]).toBe(0); + }); + }); + + // ── processEventQueue integration tests ───────────────────────────────────── + + describe("processEventQueue integration — stats via real processing", () => { + it("successful processing transitions pending → inProgress → Done (counters reach zero)", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + expect((await getTenantStats(123))[StatusField.Pending]).toBe(1); + expect((await getTenantStats(123))[StatusField.InProgress]).toBe(0); + + await processEventQueue(tx.context, "CAP_OUTBOX", "StandardService"); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + expect(globalStats[StatusField.InProgress]).toBe(0); + + await testHelper.selectEventQueueAndExpectDone(tx, { expectedLength: 1 }); + }); + + it("failed processing transitions pending → inProgress → Error → back to pending", async () => { + const service = cds.outboxed(await cds.connect.to("NotificationService")).tx(context); + await service.send("errorEvent", { to: "to", subject: "subject", body: "body" }); + await commitAndOpenNew(); + + expect((await getTenantStats(123))[StatusField.Pending]).toBe(1); + expect((await getTenantStats(123))[StatusField.InProgress]).toBe(0); + + await processEventQueue(tx.context, "CAP_OUTBOX", "NotificationService"); + await commitAndOpenNew(); + + // Error state means the event will be retried → counts as pending + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(1); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(1); + expect(globalStats[StatusField.InProgress]).toBe(0); + + await testHelper.selectEventQueueAndExpectError(tx, { expectedLength: 1 }); + }); + }); + + const commitAndOpenNew = async () => { + await tx.commit(); + context = new cds.EventContext({ user: "testUser", tenant: 123 }); + tx = cds.tx(context); + }; +}); diff --git a/test/eventQueueStats.test.js b/test/eventQueueStats.test.js new file mode 100644 index 00000000..6c3815ba --- /dev/null +++ b/test/eventQueueStats.test.js @@ -0,0 +1,134 @@ +"use strict"; + +const path = require("path"); + +const cds = require("@sap/cds/lib"); + +const mockRedis = require("./mocks/redisMock"); +jest.mock("../src/shared/redis", () => mockRedis); + +const eventQueue = require("../src"); +const { + StatusField, + incrementCounters, + decrementCounters, + adjustTenantCounter, + adjustGlobalCounter, + getTenantStats, + getGlobalStats, + deleteTenantStats, +} = require("../src/shared/eventQueueStats"); + +const project = __dirname + "/.."; +cds.test(project); + +describe("eventQueueStats", () => { + beforeAll(async () => { + const configFilePath = path.join(__dirname, "asset", "config.yml"); + await eventQueue.initialize({ + configFilePath, + processEventsAfterPublish: false, + registerAsEventProcessor: false, + }); + }); + + beforeEach(() => { + mockRedis.clearState(); + }); + + afterAll(() => cds.shutdown); + + describe("incrementCounters / decrementCounters", () => { + it("increments tenant and global counters", async () => { + await incrementCounters("t1", StatusField.Pending, 3); + + const tenant = await getTenantStats("t1"); + expect(tenant.pending).toBe(3); + expect(tenant.inProgress).toBe(0); + + const global = await getGlobalStats(); + expect(global.pending).toBe(3); + }); + + it("decrements tenant and global counters", async () => { + await incrementCounters("t1", StatusField.Pending, 5); + await decrementCounters("t1", StatusField.Pending, 2); + + const tenant = await getTenantStats("t1"); + expect(tenant.pending).toBe(3); + + const global = await getGlobalStats(); + expect(global.pending).toBe(3); + }); + + it("multiple tenants are tracked independently", async () => { + await incrementCounters("t1", StatusField.Pending, 2); + await incrementCounters("t2", StatusField.Pending, 5); + + expect((await getTenantStats("t1")).pending).toBe(2); + expect((await getTenantStats("t2")).pending).toBe(5); + }); + + it("global counter aggregates across all tenants", async () => { + await incrementCounters("t1", StatusField.InProgress, 1); + await incrementCounters("t2", StatusField.InProgress, 4); + + const global = await getGlobalStats(); + expect(global.inProgress).toBe(5); + }); + }); + + describe("adjustTenantCounter", () => { + it("creates hash with zero base when first incremented", async () => { + await adjustTenantCounter("t1", StatusField.InProgress, 1); + + const stats = await getTenantStats("t1"); + expect(stats.inProgress).toBe(1); + expect(stats.pending).toBe(0); + }); + + it("supports negative increments", async () => { + await adjustTenantCounter("t1", StatusField.Pending, 10); + await adjustTenantCounter("t1", StatusField.Pending, -3); + + expect((await getTenantStats("t1")).pending).toBe(7); + }); + }); + + describe("adjustGlobalCounter", () => { + it("increments the global counter for the given field", async () => { + await adjustGlobalCounter(StatusField.Pending, 7); + + const global = await getGlobalStats(); + expect(global.pending).toBe(7); + }); + }); + + describe("getTenantStats", () => { + it("returns all-zero object for unknown tenant", async () => { + const stats = await getTenantStats("unknown-tenant"); + expect(stats).toEqual({ pending: 0, inProgress: 0 }); + }); + }); + + describe("getGlobalStats", () => { + it("returns all-zero object when no data exists", async () => { + const stats = await getGlobalStats(); + expect(stats).toEqual({ pending: 0, inProgress: 0 }); + }); + }); + + describe("deleteTenantStats", () => { + it("removes the tenant hash", async () => { + await incrementCounters("t1", StatusField.Pending, 5); + await deleteTenantStats("t1"); + + const stats = await getTenantStats("t1"); + expect(stats).toEqual({ pending: 0, inProgress: 0 }); + }); + + it("does not throw when tenant does not exist", async () => { + await expect(deleteTenantStats("nonexistent")).resolves.toBeUndefined(); + }); + }); +}); diff --git a/test/mocks/redisMock.js b/test/mocks/redisMock.js index a0f03202..5cb66f8c 100644 --- a/test/mocks/redisMock.js +++ b/test/mocks/redisMock.js @@ -2,7 +2,8 @@ let state = {}; let testState = {}; -const _createMainClientAndConnect = async () => ({ + +const _buildClient = () => ({ get: async (key) => state[key]?.value ?? null, exists: async (key) => Object.prototype.hasOwnProperty.call(state, key), set: async (key, value, options) => { @@ -13,12 +14,70 @@ const _createMainClientAndConnect = async () => ({ testState[key] = { value, options }; return "OK"; }, - del: async (key) => delete state[key], + del: async (key) => { + const existed = Object.prototype.hasOwnProperty.call(state, key); + delete state[key]; + return existed ? 1 : 0; + }, + hIncrBy: async (key, field, increment) => { + if (!state[key]) { + state[key] = { hash: {} }; + } + const current = parseInt(state[key].hash[field] ?? "0", 10); + state[key].hash[field] = String(current + increment); + return current + increment; + }, + hSet: async (key, field, value) => { + if (!state[key]) { + state[key] = { hash: {} }; + } + const isNew = !Object.prototype.hasOwnProperty.call(state[key].hash, field); + state[key].hash[field] = String(value); + return isNew ? 1 : 0; + }, + hGetAll: async (key) => { + return state[key]?.hash ?? {}; + }, + multi: () => { + const ops = []; + const pipeline = { + hIncrBy: (key, field, increment) => { + ops.push(async () => { + if (!state[key]) { + state[key] = { hash: {} }; + } + const current = parseInt(state[key].hash[field] ?? "0", 10); + state[key].hash[field] = String(current + increment); + return current + increment; + }); + return pipeline; + }, + hSet: (key, field, value) => { + ops.push(async () => { + if (!state[key]) { + state[key] = { hash: {} }; + } + state[key].hash[field] = String(value); + }); + return pipeline; + }, + exec: async () => { + const results = []; + for (const op of ops) { + results.push(await op()); + } + return results; + }, + }; + return pipeline; + }, _: { state, }, }); +const _createMainClientAndConnect = async () => _buildClient(); + module.exports = { attachRedisUnsubscribeHandler: () => {}, subscribeRedisChannel: () => {}, diff --git a/test/redisPubSub.test.js b/test/redisPubSub.test.js index 37fcd9ed..24df9362 100644 --- a/test/redisPubSub.test.js +++ b/test/redisPubSub.test.js @@ -10,6 +10,7 @@ const setTimeoutSpy = jest.spyOn(global, "setTimeout").mockImplementation((first }); const distributedLock = require("../src/shared/distributedLock"); +const eventQueueStats = require("../src/shared/eventQueueStats"); const checkLockExistsSpy = jest.spyOn(distributedLock, "checkLockExists"); const config = require("../src/config"); const redisPub = require("../src/redis/redisPub"); @@ -67,6 +68,7 @@ describe("eventQueue Redis Events and DB Handlers", () => { eventQueue.registerEventQueueDbHandler(cds.db); loggerMock = mockLogger(); jest.spyOn(cds.utils, "uuid").mockReturnValue("6e31047a-d2b5-4e3c-83d8-deab20165956"); + jest.spyOn(eventQueueStats, "incrementCounters").mockResolvedValue(); }); beforeEach(async () => { From b4ab94d7b0af0b0cb897dc779b99cfe5cb88ec64 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 12:56:16 +0100 Subject: [PATCH 02/22] remove comments --- test/dbHandlerStats.test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/dbHandlerStats.test.js b/test/dbHandlerStats.test.js index e50cb869..36a34028 100644 --- a/test/dbHandlerStats.test.js +++ b/test/dbHandlerStats.test.js @@ -66,8 +66,6 @@ describe("dbHandler - stats tracking via CAP outbox", () => { await cds.shutdown; }); - // ── CREATE handler tests ──────────────────────────────────────────────────── - it("increments pending counter by 1 after single send and commit", async () => { const service = (await cds.connect.to("StandardService")).tx(context); await service.send("main", {}); @@ -154,8 +152,6 @@ describe("dbHandler - stats tracking via CAP outbox", () => { expect(loggerMock.callsLengths().error).toBe(0); }); - // ── UPDATE handler tests — direct status transitions ──────────────────────── - describe("UPDATE handler — direct status transitions", () => { it("Open → InProgress: decrements pending, increments inProgress", async () => { const service = (await cds.connect.to("StandardService")).tx(context); From 6cc055efde72c2c41b1cf6a15c35e45e7ee89046 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 12:57:30 +0100 Subject: [PATCH 03/22] remove comments --- test/dbHandlerStats.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/dbHandlerStats.test.js b/test/dbHandlerStats.test.js index 36a34028..2bcd8565 100644 --- a/test/dbHandlerStats.test.js +++ b/test/dbHandlerStats.test.js @@ -304,8 +304,6 @@ describe("dbHandler - stats tracking via CAP outbox", () => { }); }); - // ── processEventQueue integration tests ───────────────────────────────────── - describe("processEventQueue integration — stats via real processing", () => { it("successful processing transitions pending → inProgress → Done (counters reach zero)", async () => { const service = (await cds.connect.to("StandardService")).tx(context); From 8295092143dfa185897daa7eda6e8ce931d8c064 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 21:05:52 +0100 Subject: [PATCH 04/22] fix --- test-integration/keep-alive-tx-handling-e2e.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-integration/keep-alive-tx-handling-e2e.test.js b/test-integration/keep-alive-tx-handling-e2e.test.js index 748e34fa..c4e54397 100644 --- a/test-integration/keep-alive-tx-handling-e2e.test.js +++ b/test-integration/keep-alive-tx-handling-e2e.test.js @@ -20,6 +20,7 @@ const distributedLock = require("../src/shared/distributedLock"); const periodicEvents = require("../src/periodicEvents"); const { publishEvent } = require("../src/publishEvent"); const redisPub = require("../src/redis/redisPub"); +const eventQueueStats = require("../src/shared/eventQueueStats"); const configFilePath = path.join(__dirname, "..", "./test", "asset", "config.yml"); @@ -48,6 +49,7 @@ describe("keep-alive-tx-handling-e2e", () => { registerAsEventProcessor: false, isEventQueueActive: false, }); + jest.spyOn(eventQueueStats, "incrementCounters").mockResolvedValue(); loggerMock = mockLogger(); const db = await cds.connect.to("db"); From 6889a63189a8f72824414be37f901f3bd5f9029a Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 23:00:41 +0100 Subject: [PATCH 05/22] wip --- src/dbHandler.js | 4 +++- .../keep-alive-tx-handling-e2e.test.js | 18 +++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/dbHandler.js b/src/dbHandler.js index 74e1169c..db00cdf7 100644 --- a/src/dbHandler.js +++ b/src/dbHandler.js @@ -127,7 +127,9 @@ const registerEventQueueDbHandler = (dbService) => { if (result.status === "rejected") { cds .log(COMPONENT_NAME) - .error("db handler failure during updating event stats on update", result.reason, { tenant: req.tenant }); + .error("db handler failure during updating event stats on update", result.reason, { + tenant: req.tenant, + }); } } }); diff --git a/test-integration/keep-alive-tx-handling-e2e.test.js b/test-integration/keep-alive-tx-handling-e2e.test.js index c4e54397..485df2c4 100644 --- a/test-integration/keep-alive-tx-handling-e2e.test.js +++ b/test-integration/keep-alive-tx-handling-e2e.test.js @@ -105,13 +105,17 @@ describe("keep-alive-tx-handling-e2e", () => { describe("commitOnEventLevel", () => { it("straight forward", async () => { - await cds.tx({}, (tx2) => - testHelper.insertEventEntry(tx2, { - numberOfEntries: 2, - type: isolatedNoParallel.type, - subType: isolatedNoParallel.subType, - }) - ); + try { + await cds.tx({}, (tx2) => + testHelper.insertEventEntry(tx2, { + numberOfEntries: 2, + type: isolatedNoParallel.type, + subType: isolatedNoParallel.subType, + }) + ); + } catch (err) { + debugger; + } const { db } = cds.services; const { Event } = cds.entities("sap.eventqueue"); let forUpdateCounter = 0; From e869f2f947ee343c641833c1599d9680de4c8045 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sat, 7 Mar 2026 23:33:12 +0100 Subject: [PATCH 06/22] wip --- .../__snapshots__/e2e-redis.test.js.snap | 11 ++++++++++- .../keep-alive-tx-handling-e2e.test.js | 19 ++++++++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/test-integration/__snapshots__/e2e-redis.test.js.snap b/test-integration/__snapshots__/e2e-redis.test.js.snap index 2f662a8e..d7f8e85d 100644 --- a/test-integration/__snapshots__/e2e-redis.test.js.snap +++ b/test-integration/__snapshots__/e2e-redis.test.js.snap @@ -12,6 +12,8 @@ exports[`end-to-end redis broadcast checkAndInsertPeriodicEvents should insert n [ "EVENT_QUEUE##default##RUN_REDIS_CHECK", "EVENT_QUEUE##default####TEST_STATIC", + "EVENT_QUEUE##default##stats##tenant##undefined", + "EVENT_QUEUE##default##stats##global", ] `; @@ -24,6 +26,8 @@ exports[`end-to-end redis broadcast insert entry: redis broadcast + process 1`] exports[`end-to-end redis broadcast insert entry: redis broadcast + process 2`] = ` [ + "EVENT_QUEUE##default##stats##tenant##undefined", + "EVENT_QUEUE##default##stats##global", "EVENT_QUEUE##default####TEST_STATIC", ] `; @@ -34,4 +38,9 @@ exports[`end-to-end runner should select open events and process + validate skip ] `; -exports[`end-to-end runner should select open events and process + validate skip broadcast 2`] = `[]`; +exports[`end-to-end runner should select open events and process + validate skip broadcast 2`] = ` +[ + "EVENT_QUEUE##default##stats##tenant##undefined", + "EVENT_QUEUE##default##stats##global", +] +`; diff --git a/test-integration/keep-alive-tx-handling-e2e.test.js b/test-integration/keep-alive-tx-handling-e2e.test.js index 485df2c4..f7783815 100644 --- a/test-integration/keep-alive-tx-handling-e2e.test.js +++ b/test-integration/keep-alive-tx-handling-e2e.test.js @@ -105,17 +105,14 @@ describe("keep-alive-tx-handling-e2e", () => { describe("commitOnEventLevel", () => { it("straight forward", async () => { - try { - await cds.tx({}, (tx2) => - testHelper.insertEventEntry(tx2, { - numberOfEntries: 2, - type: isolatedNoParallel.type, - subType: isolatedNoParallel.subType, - }) - ); - } catch (err) { - debugger; - } + await cds.tx({}, (tx2) => + testHelper.insertEventEntry(tx2, { + numberOfEntries: 2, + type: isolatedNoParallel.type, + subType: isolatedNoParallel.subType, + }) + ); + const { db } = cds.services; const { Event } = cds.entities("sap.eventqueue"); let forUpdateCounter = 0; From 96f8b70369bbfbd9d7da7d4c822e8c22baf68b4a Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 09:45:10 +0100 Subject: [PATCH 07/22] update statistic via runner --- src/runner/openEvents.js | 12 ++--- src/runner/runner.js | 24 +++++++++- src/shared/eventQueueStats.js | 44 +++++++++++++------ .../__snapshots__/runner.test.js.snap | 31 ++++++++++++- test-integration/e2e-redis.test.js | 1 - test-integration/runner.test.js | 44 +++++++++++++++++++ 6 files changed, 133 insertions(+), 23 deletions(-) diff --git a/src/runner/openEvents.js b/src/runner/openEvents.js index fc95f75a..71058dfa 100644 --- a/src/runner/openEvents.js +++ b/src/runner/openEvents.js @@ -29,12 +29,12 @@ const getOpenQueueEntries = async (tx, filterAppSpecificEvents = true) => { new Date(startTime.getTime() - 30 * MS_IN_DAYS).toISOString(), ")" ) - .columns("type", "subType", "namespace") + .columns("count(ID) as count", "type", "subType", "namespace") .groupBy("type", "subType", "namespace") ); const result = []; - for (const { type, subType, namespace } of entries) { + for (const { type, subType, namespace, count } of entries) { if (config.isCapOutboxEvent(type)) { const { srvName, actionName } = config.normalizeSubType(type, subType); try { @@ -48,14 +48,14 @@ const getOpenQueueEntries = async (tx, filterAppSpecificEvents = true) => { config.addCAPServiceWithoutEnvConfig(subType, service); } if (config.shouldBeProcessedInThisApplication(type, subType, namespace)) { - result.push({ namespace, type, subType }); + result.push({ namespace, type, subType, count }); } } } catch { /* ignore catch */ } finally { if (!filterAppSpecificEvents) { - result.push({ namespace, type, subType }); + result.push({ namespace, type, subType, count }); } } } else { @@ -64,10 +64,10 @@ const getOpenQueueEntries = async (tx, filterAppSpecificEvents = true) => { config.getEventConfig(type, subType, namespace) && config.shouldBeProcessedInThisApplication(type, subType, namespace) ) { - result.push({ namespace, type, subType }); + result.push({ namespace, type, subType, count }); } } else { - result.push({ namespace, type, subType }); + result.push({ namespace, type, subType, count }); } } } diff --git a/src/runner/runner.js b/src/runner/runner.js index 9295041c..d4095265 100644 --- a/src/runner/runner.js +++ b/src/runner/runner.js @@ -14,6 +14,7 @@ const common = require("../shared/common"); const config = require("../config"); const redisPub = require("../redis/redisPub"); const openEvents = require("./openEvents"); +const eventQueueStats = require("../shared/eventQueueStats"); const { runEventCombinationForTenant } = require("./runnerHelper"); const { trace } = require("../shared/openTelemetry"); @@ -141,7 +142,7 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { } catch (err) { logger.error("executing event queue run for multi instance and tenant failed", err); } - + const tenantCounts = {}; for (const tenantId of tenantIds) { try { await cds.tx({ tenant: tenantId }, async (tx) => { @@ -160,6 +161,16 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { tenantId, entries: entries.length, }); + tenantCounts[tenantId] = entries; + const pendingByNamespace = {}; + for (const entry of entries) { + pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; + } + for (const [namespace, count] of Object.entries(pendingByNamespace)) { + eventQueueStats + .setTenantCounter(tenantId, namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating tenant stats failed", err, { tenantId, namespace })); + } if (!entries.length) { return; } @@ -178,6 +189,17 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { logger.error("broadcasting events for tenant failed", { tenantId }, err); } } + const globalPendingByNamespace = {}; + for (const tenantEntries of Object.values(tenantCounts)) { + for (const entry of tenantEntries) { + globalPendingByNamespace[entry.namespace] = (globalPendingByNamespace[entry.namespace] ?? 0) + entry.count; + } + } + for (const [namespace, count] of Object.entries(globalPendingByNamespace)) { + eventQueueStats + .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating global stats failed", err, { namespace })); + } }; const _executeEventsAllTenants = async (tenantIds) => { diff --git a/src/shared/eventQueueStats.js b/src/shared/eventQueueStats.js index 6e7da197..5edbafef 100644 --- a/src/shared/eventQueueStats.js +++ b/src/shared/eventQueueStats.js @@ -14,6 +14,7 @@ const StatusField = { const _tenantKey = (tenantId) => `${config.redisNamespace(true)}##stats##tenant##${tenantId}`; const _globalKey = () => `${config.redisNamespace(true)}##stats##global`; +const _keyPrefix = (namespace) => `${config.redisNamespace(false)}##${namespace}`; /** * Atomically adjusts a tenant's event counter for the given status field. @@ -23,12 +24,11 @@ const _globalKey = () => `${config.redisNamespace(true)}##stats##global`; * @param {number} increment - positive to increment, negative to decrement */ const adjustTenantCounter = async (tenantId, field, increment) => { - const logger = cds.log(COMPONENT_NAME); try { const client = await redis.createMainClientAndConnect(); await client.hIncrBy(_tenantKey(tenantId), field, increment); } catch (err) { - logger.error("failed to adjust tenant stats counter", err, { tenantId, field, increment }); + cds.log(COMPONENT_NAME).error("failed to adjust tenant stats counter", err, { tenantId, field, increment }); } }; @@ -40,12 +40,11 @@ const adjustTenantCounter = async (tenantId, field, increment) => { * @param {number} increment - positive to increment, negative to decrement */ const adjustGlobalCounter = async (field, increment) => { - const logger = cds.log(COMPONENT_NAME); try { const client = await redis.createMainClientAndConnect(); await client.hIncrBy(_globalKey(), field, increment); } catch (err) { - logger.error("failed to adjust global stats counter", err, { field, increment }); + cds.log(COMPONENT_NAME).error("failed to adjust global stats counter", err, { field, increment }); } }; @@ -57,7 +56,7 @@ const adjustGlobalCounter = async (field, increment) => { * @param {number} [increment=1] */ const incrementCounters = async (tenantId, field, increment = 1) => { - await Promise.all([adjustTenantCounter(tenantId, field, increment), adjustGlobalCounter(field, increment)]); + await Promise.allSettled([adjustTenantCounter(tenantId, field, increment), adjustGlobalCounter(field, increment)]); }; /** @@ -68,7 +67,7 @@ const incrementCounters = async (tenantId, field, increment = 1) => { * @param {number} [decrement=1] */ const decrementCounters = async (tenantId, field, decrement = 1) => { - await Promise.all([adjustTenantCounter(tenantId, field, -decrement), adjustGlobalCounter(field, -decrement)]); + await Promise.allSettled([adjustTenantCounter(tenantId, field, -decrement), adjustGlobalCounter(field, -decrement)]); }; /** @@ -76,16 +75,15 @@ const decrementCounters = async (tenantId, field, decrement = 1) => { * All counter values are returned as integers; missing fields default to 0. * * @param {string} tenantId - * @returns {Promise<{open: number, inProgress: number, error: number}>} + * @returns {Promise<{pending: number, inProgress: number}>} */ const getTenantStats = async (tenantId) => { - const logger = cds.log(COMPONENT_NAME); try { const client = await redis.createMainClientAndConnect(); const raw = await client.hGetAll(_tenantKey(tenantId)); return _parseCounterHash(raw); } catch (err) { - logger.error("failed to read tenant stats", err, { tenantId }); + cds.log(COMPONENT_NAME).error("failed to read tenant stats", err, { tenantId }); return _emptyCounters(); } }; @@ -94,16 +92,15 @@ const getTenantStats = async (tenantId) => { * Returns the current global stats hash. * All counter values are returned as integers; missing fields default to 0. * - * @returns {Promise<{open: number, inProgress: number, error: number}>} + * @returns {Promise<{pending: number, inProgress: number}>} */ const getGlobalStats = async () => { - const logger = cds.log(COMPONENT_NAME); try { const client = await redis.createMainClientAndConnect(); const raw = await client.hGetAll(_globalKey()); return _parseCounterHash(raw); } catch (err) { - logger.error("failed to read global stats", err); + cds.log(COMPONENT_NAME).error("failed to read global stats", err); return _emptyCounters(); } }; @@ -114,13 +111,30 @@ const getGlobalStats = async () => { * * @param {string} tenantId */ +const setTenantCounter = async (tenantId, namespace, field, value) => { + try { + const client = await redis.createMainClientAndConnect(); + await client.hSet(`${_keyPrefix(namespace)}##stats##tenant##${tenantId}`, field, value); + } catch (err) { + cds.log(COMPONENT_NAME).error("failed to set tenant stats counter", err, { tenantId, namespace, field, value }); + } +}; + +const setGlobalCounter = async (namespace, field, value) => { + try { + const client = await redis.createMainClientAndConnect(); + await client.hSet(`${_keyPrefix(namespace)}##stats##global`, field, value); + } catch (err) { + cds.log(COMPONENT_NAME).error("failed to set global stats counter", err, { namespace, field, value }); + } +}; + const deleteTenantStats = async (tenantId) => { - const logger = cds.log(COMPONENT_NAME); try { const client = await redis.createMainClientAndConnect(); await client.del(_tenantKey(tenantId)); } catch (err) { - logger.error("failed to delete tenant stats", err, { tenantId }); + cds.log(COMPONENT_NAME).error("failed to delete tenant stats", err, { tenantId }); } }; @@ -140,6 +154,8 @@ module.exports = { decrementCounters, adjustTenantCounter, adjustGlobalCounter, + setTenantCounter, + setGlobalCounter, getTenantStats, getGlobalStats, deleteTenantStats, diff --git a/test-integration/__snapshots__/runner.test.js.snap b/test-integration/__snapshots__/runner.test.js.snap index 54c00387..d1617495 100644 --- a/test-integration/__snapshots__/runner.test.js.snap +++ b/test-integration/__snapshots__/runner.test.js.snap @@ -95,6 +95,7 @@ exports[`runner redis multi tenant tenant id filter should not acquire lock - on "e9bb8ec0-c85e-4035-b7cf-1b11ba8e5792", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -105,6 +106,7 @@ exports[`runner redis multi tenant tenant id filter should not acquire lock - on "cd805323-879c-4bf7-b19c-8ffbbee22e1f", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -115,6 +117,7 @@ exports[`runner redis multi tenant tenant id filter should not acquire lock - on "9f3ed8f0-8aaf-439e-a96a-04cd5b680c59", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -126,7 +129,20 @@ exports[`runner redis multi tenant tenant id filter should not acquire lock - on exports[`runner redis multi tenant tenant id filter should not acquire lock - only process tenants based on tenant filter with open events - split into two instances 2`] = `[]`; -exports[`runner redis multi tenant tenant id filter should not acquire lock - only process tenants based on tenant filter with open events - split into two instances 3`] = `{}`; +exports[`runner redis multi tenant tenant id filter should not acquire lock - only process tenants based on tenant filter with open events - split into two instances 3`] = ` +{ + "EVENT_QUEUE##default##stats##global": { + "hash": { + "pending": "2", + }, + }, + "EVENT_QUEUE##default##stats##tenant##TEST_STATIC": { + "hash": { + "pending": "1", + }, + }, +} +`; exports[`runner redis multi tenant with open events - broadcast should be called 1`] = ` [ @@ -134,6 +150,7 @@ exports[`runner redis multi tenant with open events - broadcast should be called "cd805323-879c-4bf7-b19c-8ffbbee22e1f", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -144,6 +161,7 @@ exports[`runner redis multi tenant with open events - broadcast should be called "9f3ed8f0-8aaf-439e-a96a-04cd5b680c59", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -154,6 +172,7 @@ exports[`runner redis multi tenant with open events - broadcast should be called "e9bb8ec0-c85e-4035-b7cf-1b11ba8e5792", [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", @@ -203,6 +222,16 @@ exports[`runner redis multi tenant with open events - broadcast should be called "PX": 60000, }, }, + "EVENT_QUEUE##default##stats##global": { + "hash": { + "pending": "3", + }, + }, + "EVENT_QUEUE##default##stats##tenant##TEST_STATIC": { + "hash": { + "pending": "1", + }, + }, } `; diff --git a/test-integration/e2e-redis.test.js b/test-integration/e2e-redis.test.js index e310968c..4ee0b4c2 100644 --- a/test-integration/e2e-redis.test.js +++ b/test-integration/e2e-redis.test.js @@ -82,7 +82,6 @@ describe("end-to-end", () => { beforeEach(async () => { await DELETE.from("sap.eventqueue.Lock"); await DELETE.from("sap.eventqueue.Event"); - await DELETE.from("cds.outbox.Messages"); jest.clearAllMocks(); redisMock.clearState(); redisMock.clearTestState(); diff --git a/test-integration/runner.test.js b/test-integration/runner.test.js index 79e8a153..366fa217 100644 --- a/test-integration/runner.test.js +++ b/test-integration/runner.test.js @@ -7,6 +7,7 @@ cds.test(__dirname + "/_env"); const mockRedis = require("../test/mocks/redisMock"); jest.mock("../src/shared/redis", () => mockRedis); +const { getTenantStats, getGlobalStats, StatusField } = require("../src/shared/eventQueueStats"); const WorkerQueue = require("../src/shared/WorkerQueue"); const processEventQueue = require("../src/processEventQueue"); const openEvents = require("../src/runner/openEvents"); @@ -176,6 +177,49 @@ describe("runner", () => { expect(loggerMock.callsLengths().error).toEqual(0); }); + describe("stats tracking", () => { + it("sets pending counter per tenant and globally after runner with open events", async () => { + await cds.tx({}, async (tx2) => { + await periodicEvents.checkAndInsertPeriodicEvents(tx2.context); + }); + mockTenantIds(tenantIds); + jest.spyOn(redisPub, "broadcastEvent").mockResolvedValue(); + jest.spyOn(periodicEvents, "checkAndInsertPeriodicEvents").mockResolvedValue(); + + await Promise.allSettled([runner.__._multiTenancyRedis(), runner.__._multiTenancyRedis()]); + await Promise.allSettled(WorkerQueue.instance.runningPromises); + await new Promise(setImmediate); + + for (const tenantId of tenantIds) { + const stats = await getTenantStats(tenantId); + expect(stats[StatusField.Pending]).toBe(1); + } + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(tenantIds.length); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("does not update stats when there are no open events", async () => { + mockTenantIds(tenantIds); + jest.spyOn(redisPub, "broadcastEvent").mockResolvedValue(); + jest.spyOn(periodicEvents, "checkAndInsertPeriodicEvents").mockResolvedValue(); + + await Promise.allSettled([runner.__._multiTenancyRedis()]); + await Promise.allSettled(WorkerQueue.instance.runningPromises); + await new Promise(setImmediate); + + for (const tenantId of tenantIds) { + const stats = await getTenantStats(tenantId); + expect(stats[StatusField.Pending]).toBe(0); + } + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + }); + describe("tenant id filter should not acquire lock - only process tenants based on tenant filter", () => { it("always false", async () => { await cds.tx({}, async (tx2) => { From 6aa10f6bc3e3c5991d0cea591d883c9fcbd542ab Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 10:41:05 +0100 Subject: [PATCH 08/22] report metrics to open telemtry --- src/initialize.js | 2 ++ src/shared/eventQueueStats.js | 21 ++++++++++++ src/shared/openTelemetry.js | 60 ++++++++++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/initialize.js b/src/initialize.js index 392c55e8..7ba7f0ef 100644 --- a/src/initialize.js +++ b/src/initialize.js @@ -17,6 +17,7 @@ const { getAllTenantIds } = require("./shared/cdsHelper"); const { EventProcessingStatus } = require("./constants"); const distributedLock = require("./shared/distributedLock"); const EventQueueError = require("./EventQueueError"); +const { initMetrics } = require("./shared/openTelemetry"); const readFileAsync = promisify(fs.readFile); @@ -125,6 +126,7 @@ const initialize = async (options = {}) => { runInterval: config.runInterval, useAsCAPQueue: config.useAsCAPQueue, }); + initMetrics(); resolveFn(); }; diff --git a/src/shared/eventQueueStats.js b/src/shared/eventQueueStats.js index 5edbafef..2010a36c 100644 --- a/src/shared/eventQueueStats.js +++ b/src/shared/eventQueueStats.js @@ -129,6 +129,26 @@ const setGlobalCounter = async (namespace, field, value) => { } }; +const getAllNamespaceStats = async () => { + const namespaces = config.processingNamespaces; + const client = await redis.createMainClientAndConnect(); + const results = await Promise.allSettled( + namespaces.map(async (namespace) => { + const raw = await client.hGetAll(`${_keyPrefix(namespace)}##stats##global`); + return { namespace, stats: _parseCounterHash(raw) }; + }) + ); + const out = {}; + for (const result of results) { + if (result.status === "fulfilled") { + out[result.value.namespace] = result.value.stats; + } else { + cds.log(COMPONENT_NAME).error("failed to read namespace stats", result.reason); + } + } + return out; +}; + const deleteTenantStats = async (tenantId) => { try { const client = await redis.createMainClientAndConnect(); @@ -156,6 +176,7 @@ module.exports = { adjustGlobalCounter, setTenantCounter, setGlobalCounter, + getAllNamespaceStats, getTenantStats, getGlobalStats, deleteTenantStats, diff --git a/src/shared/openTelemetry.js b/src/shared/openTelemetry.js index f9d5896a..323edecf 100644 --- a/src/shared/openTelemetry.js +++ b/src/shared/openTelemetry.js @@ -12,9 +12,13 @@ const cds = require("@sap/cds"); const otel = _resilientRequire("@opentelemetry/api"); const config = require("../config"); +const eventQueueStats = require("./eventQueueStats"); const COMPONENT_NAME = "/shared/openTelemetry"; +let _statsSnapshot = null; +let _metricsInitialized = false; + const trace = async (context, label, fn, { attributes = {}, newRootSpan = false, traceContext } = {}) => { if (!config.enableTelemetry || !otel) { return fn(); @@ -110,4 +114,58 @@ const getCurrentTraceContext = () => { return carrier; }; -module.exports = { trace, getCurrentTraceContext }; +const _refreshStats = async () => { + try { + const namespaces = await eventQueueStats.getAllNamespaceStats(); + _statsSnapshot = { namespaces, lastRefreshedAt: Date.now() }; + } catch (err) { + cds.log(COMPONENT_NAME).error("failed to refresh queue stats for metrics", err); + } +}; + +const initMetrics = () => { + if (_metricsInitialized || !config.enableTelemetry || !config.redisEnabled || !otel?.metrics) { + return; + } + const meterProvider = otel.metrics.getMeterProvider?.(); + if (!meterProvider) { + return; + } + + _metricsInitialized = true; + + const meter = otel.metrics.getMeter("@cap-js-community/event-queue"); + + const pendingGauge = meter.createObservableGauge("cap.event_queue.jobs.pending", { + description: "Current number of jobs waiting to be processed.", + unit: "1", + }); + const inProgressGauge = meter.createObservableGauge("cap.event_queue.jobs.in_progress", { + description: "Current number of jobs actively being processed by workers.", + unit: "1", + }); + const refreshAgeGauge = meter.createObservableGauge("cap.event_queue.stats.refresh_age", { + description: "Age of the most recent queue statistics snapshot.", + unit: "s", + }); + + meter.addBatchObservableCallback( + (observableResult) => { + if (!_statsSnapshot) { + return; + } + observableResult.observe(refreshAgeGauge, (Date.now() - _statsSnapshot.lastRefreshedAt) / 1000); + for (const [namespace, stats] of Object.entries(_statsSnapshot.namespaces)) { + const attrs = { "queue.namespace": namespace }; + observableResult.observe(pendingGauge, stats.pending, attrs); + observableResult.observe(inProgressGauge, stats.inProgress, attrs); + } + }, + [pendingGauge, inProgressGauge, refreshAgeGauge] + ); + + _refreshStats(); + setInterval(_refreshStats, 30_000).unref(); +}; + +module.exports = { trace, getCurrentTraceContext, initMetrics }; From 900ae7db9ecb573edb5f4191224cf8469af7739a Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 11:43:57 +0100 Subject: [PATCH 09/22] snapshots --- .../baseFunctionality.test.js.snap | 36 +++++++++++++++++++ .../eventQueueOutbox.test.js.snap | 5 +++ 2 files changed, 41 insertions(+) diff --git a/test/__snapshots__/baseFunctionality.test.js.snap b/test/__snapshots__/baseFunctionality.test.js.snap index 3c7688e1..d1c4249a 100644 --- a/test/__snapshots__/baseFunctionality.test.js.snap +++ b/test/__snapshots__/baseFunctionality.test.js.snap @@ -111,31 +111,37 @@ exports[`baseFunctionality ad-hoc events error handling missing event implementa exports[`baseFunctionality getOpenQueueEntries event types in error should be considered 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DBKeepAlive", "type": "HealthCheckKeepAlive_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DB", "type": "HealthCheck_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", }, { + "count": 1, "namespace": "default", "subType": "everyFiveMin", "type": "TimeSpecificEveryFiveMin_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "cron", "type": "TimeSpecificEveryMin_PERIODIC", @@ -146,26 +152,31 @@ exports[`baseFunctionality getOpenQueueEntries event types in error should be co exports[`baseFunctionality getOpenQueueEntries event types in progress should be ignored 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DBKeepAlive", "type": "HealthCheckKeepAlive_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DB", "type": "HealthCheck_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "everyFiveMin", "type": "TimeSpecificEveryFiveMin_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "cron", "type": "TimeSpecificEveryMin_PERIODIC", @@ -176,46 +187,55 @@ exports[`baseFunctionality getOpenQueueEntries event types in progress should be exports[`baseFunctionality getOpenQueueEntries filterAppSpecificEvents return open event types 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "AppInstance", "type": "AppSpecific_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "AppName", "type": "AppSpecific_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "both", "type": "AppSpecific_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DBKeepAlive", "type": "HealthCheckKeepAlive_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DB", "type": "HealthCheck_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", }, { + "count": 1, "namespace": "default", "subType": "everyFiveMin", "type": "TimeSpecificEveryFiveMin_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "cron", "type": "TimeSpecificEveryMin_PERIODIC", @@ -226,31 +246,37 @@ exports[`baseFunctionality getOpenQueueEntries filterAppSpecificEvents return op exports[`baseFunctionality getOpenQueueEntries return open event types 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "DELETE_EVENTS", "type": "EVENT_QUEUE_BASE_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DBKeepAlive", "type": "HealthCheckKeepAlive_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "DB", "type": "HealthCheck_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", }, { + "count": 1, "namespace": "default", "subType": "everyFiveMin", "type": "TimeSpecificEveryFiveMin_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "cron", "type": "TimeSpecificEveryMin_PERIODIC", @@ -261,11 +287,13 @@ exports[`baseFunctionality getOpenQueueEntries return open event types 2`] = ` exports[`baseFunctionality getOpenQueueEntries should respect app instance configuration both open event relevant for app 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "AppInstance", "type": "AppSpecific", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", @@ -276,6 +304,7 @@ exports[`baseFunctionality getOpenQueueEntries should respect app instance confi exports[`baseFunctionality getOpenQueueEntries should respect app instance configuration one open event for app and one not for this app 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", @@ -286,11 +315,13 @@ exports[`baseFunctionality getOpenQueueEntries should respect app instance confi exports[`baseFunctionality getOpenQueueEntries should respect app instance configuration one open event for app and one not for this app but redis should ignore filter 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "AppInstance", "type": "AppSpecific", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", @@ -301,11 +332,13 @@ exports[`baseFunctionality getOpenQueueEntries should respect app instance confi exports[`baseFunctionality getOpenQueueEntries should respect app name configuration both open event relevant for app 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "AppName", "type": "AppSpecific", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", @@ -316,6 +349,7 @@ exports[`baseFunctionality getOpenQueueEntries should respect app name configura exports[`baseFunctionality getOpenQueueEntries should respect app name configuration one open event for app and one not for this app 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", @@ -326,11 +360,13 @@ exports[`baseFunctionality getOpenQueueEntries should respect app name configura exports[`baseFunctionality getOpenQueueEntries should respect app name configuration one open event for app and one not for this app but redis should ignore filter 2`] = ` [ { + "count": 1, "namespace": "default", "subType": "AppName", "type": "AppSpecific", }, { + "count": 1, "namespace": "default", "subType": "Task", "type": "Notifications", diff --git a/test/__snapshots__/eventQueueOutbox.test.js.snap b/test/__snapshots__/eventQueueOutbox.test.js.snap index 33f65d63..9ce8cc2c 100644 --- a/test/__snapshots__/eventQueueOutbox.test.js.snap +++ b/test/__snapshots__/eventQueueOutbox.test.js.snap @@ -419,26 +419,31 @@ exports[`event-queue outbox monkeyPatchCAPOutbox=true req.data should be stored exports[`event-queue outbox monkeyPatchCAPOutbox=true return open event types 1`] = ` [ { + "count": 1, "namespace": "default", "subType": "NotificationService", "type": "CAP_OUTBOX", }, { + "count": 1, "namespace": "default", "subType": "NotificationServicePeriodic.main", "type": "CAP_OUTBOX_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "NotificationServicePeriodic.randomOffset", "type": "CAP_OUTBOX_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "QueueService.main", "type": "CAP_OUTBOX_PERIODIC", }, { + "count": 1, "namespace": "default", "subType": "sapafcsdk.scheduling.ProviderService.timeBucketAction", "type": "CAP_OUTBOX_PERIODIC", From 7f36d6a69dec05b8eef4f8b7927ce8fb51e1e719 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 13:36:01 +0100 Subject: [PATCH 10/22] wip --- .claude/worktrees/funny-borg | 1 + src/runner/runner.js | 9 +++++++++ test-integration/__snapshots__/runner.test.js.snap | 5 +++++ 3 files changed, 15 insertions(+) create mode 160000 .claude/worktrees/funny-borg diff --git a/.claude/worktrees/funny-borg b/.claude/worktrees/funny-borg new file mode 160000 index 00000000..900ae7db --- /dev/null +++ b/.claude/worktrees/funny-borg @@ -0,0 +1 @@ +Subproject commit 900ae7db9ecb573edb5f4191224cf8469af7739a diff --git a/src/runner/runner.js b/src/runner/runner.js index d4095265..2c68bf4a 100644 --- a/src/runner/runner.js +++ b/src/runner/runner.js @@ -389,6 +389,15 @@ const _singleTenantRedis = async () => { logger.info("broadcasting events for run", { entries: entries.length, }); + const pendingByNamespace = {}; + for (const entry of entries) { + pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; + } + for (const [namespace, count] of Object.entries(pendingByNamespace)) { + eventQueueStats + .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating global stats failed", err, { namespace })); + } if (!entries.length) { return; } diff --git a/test-integration/__snapshots__/runner.test.js.snap b/test-integration/__snapshots__/runner.test.js.snap index d1617495..495d3dfa 100644 --- a/test-integration/__snapshots__/runner.test.js.snap +++ b/test-integration/__snapshots__/runner.test.js.snap @@ -292,5 +292,10 @@ exports[`runner redis single tenant with open events - broadcast should be calle "PX": 1425000, }, }, + "EVENT_QUEUE##default##stats##global": { + "hash": { + "pending": "1", + }, + }, } `; From 17e8d68d1646218eb96bcfdf233c6a1f645703ba Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 13:48:03 +0100 Subject: [PATCH 11/22] add tests --- test-integration/dbHandlerStats.test.js | 384 ++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 test-integration/dbHandlerStats.test.js diff --git a/test-integration/dbHandlerStats.test.js b/test-integration/dbHandlerStats.test.js new file mode 100644 index 00000000..5f836ec5 --- /dev/null +++ b/test-integration/dbHandlerStats.test.js @@ -0,0 +1,384 @@ +"use strict"; + +const path = require("path"); + +const mockRedis = require("../test/mocks/redisMock"); +jest.mock("../src/shared/redis", () => mockRedis); + +const cds = require("@sap/cds"); +cds.test(__dirname + "/_env"); + +const basePath = path.join(__dirname, "..", "test", "asset", "outboxProject"); +cds.env.requires.StandardService = { + impl: path.join(basePath, "srv/service/standard-service.js"), + outbox: { kind: "persistent-outbox" }, +}; + +cds.env.requires.NotificationService = { + impl: path.join(basePath, "srv/service/service.js"), + outbox: { kind: "persistent-outbox" }, +}; + +const eventQueue = require("../src"); +const config = require("../src/config"); +const { getTenantStats, getGlobalStats, StatusField } = require("../src/shared/eventQueueStats"); +const { EventProcessingStatus } = require("../src/constants"); +const { processEventQueue } = require("../src/processEventQueue"); +const testHelper = require("../test/helper"); +const { Logger: mockLogger } = require("../test/mocks/logger"); + +describe("dbHandler - stats tracking on HANA", () => { + let context, tx, loggerMock; + + beforeAll(async () => { + eventQueue.config.initialized = false; + await eventQueue.initialize({ + processEventsAfterPublish: false, + registerAsEventProcessor: false, + insertEventsBeforeCommit: true, + useAsCAPOutbox: true, + userId: "dummyTestUser", + }); + const db = await cds.connect.to("db"); + cds.emit("connect", db); + config.redisEnabled = true; + eventQueue.registerEventQueueDbHandler(db); + loggerMock = mockLogger(); + }); + + beforeEach(async () => { + context = new cds.EventContext({ user: "testUser", tenant: 123 }); + tx = cds.tx(context); + await cds.tx({}, async (tx2) => { + await tx2.run(DELETE.from("sap.eventqueue.Lock")); + await tx2.run(DELETE.from("sap.eventqueue.Event")); + }); + await commitAndOpenNew(); + mockRedis.clearState(); + jest.clearAllMocks(); + }); + + afterEach(async () => { + await tx.rollback(); + }); + + afterAll(async () => { + config.redisEnabled = false; + await cds.disconnect(); + await cds.shutdown(); + }); + + it("increments pending counter by 1 after single send and commit", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(1); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(1); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("accumulates pending counter for multiple sends in same transaction", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(3); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(3); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("does not increment counter when transaction is rolled back", async () => { + const innerTx = cds.tx(context); + const service = (await cds.connect.to("StandardService")).tx(innerTx.context); + await service.send("main", {}); + await innerTx.rollback(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + }); + + it("does not increment counter when redisEnabled is false", async () => { + config.redisEnabled = false; + try { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + } finally { + config.redisEnabled = true; + } + }); + + it("tracks stats per tenant while global counter aggregates", async () => { + const service123 = (await cds.connect.to("StandardService")).tx(context); + await service123.send("main", {}); + await service123.send("main", {}); + await commitAndOpenNew(); + + const ctx456 = new cds.EventContext({ user: "testUser", tenant: 456 }); + const tx456 = cds.tx(ctx456); + const service456 = (await cds.connect.to("StandardService")).tx(ctx456); + await service456.send("main", {}); + await tx456.commit(); + + const stats123 = await getTenantStats(123); + expect(stats123[StatusField.Pending]).toBe(2); + + const stats456 = await getTenantStats(456); + expect(stats456[StatusField.Pending]).toBe(1); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(3); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + describe("UPDATE handler — HANA affectedRows behavior", () => { + it("Open → InProgress: HANA affectedRows returns correct count for bulk update of 3 rows", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=3 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); + + // On HANA, affectedRows must be 3 — not the fallback of 1 + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(3); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + expect(globalStats[StatusField.InProgress]).toBe(3); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Done: HANA affectedRows correctly decrements all inProgress", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=3 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=3 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Done }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Error: HANA affectedRows correctly restores all rows as pending", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=3 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=3 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Error }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(3); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(3); + expect(globalStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("InProgress → Exceeded: HANA affectedRows correctly decrements all inProgress", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=3 + + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); // pending=0, inProgress=3 + + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Exceeded }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("UPDATE matching 0 rows does not affect counters", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); // pending=1 + + // WHERE clause matches nothing — affectedRows=0, must not change counters + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Done }) + .where({ status: EventProcessingStatus.InProgress }) // nothing is InProgress yet + ); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(1); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("two UPDATEs in one transaction accumulate into a single succeeded handler call", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + // Open→InProgress then InProgress→Done without an intermediate commit + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await tx.run( + UPDATE.entity("sap.eventqueue.Event") + .set({ status: EventProcessingStatus.Done }) + .where({ status: EventProcessingStatus.InProgress }) + ); + await commitAndOpenNew(); + + // Net delta: pending -2, inProgress +2 then -2 → both counters at 0 + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + expect(loggerMock.callsLengths().error).toBe(0); + }); + + it("does not adjust counters when redisEnabled is false", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + config.redisEnabled = false; + try { + await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(2); + expect(tenantStats[StatusField.InProgress]).toBe(0); + } finally { + config.redisEnabled = true; + } + }); + + it("does not adjust counters when transaction is rolled back", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await service.send("main", {}); + await commitAndOpenNew(); // pending=2 + + const innerTx = cds.tx(context); + await innerTx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); + await innerTx.rollback(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(2); + expect(tenantStats[StatusField.InProgress]).toBe(0); + }); + }); + + describe("processEventQueue integration — stats via real processing", () => { + it("successful processing transitions pending → inProgress → Done (counters reach zero)", async () => { + const service = (await cds.connect.to("StandardService")).tx(context); + await service.send("main", {}); + await commitAndOpenNew(); + + expect((await getTenantStats(123))[StatusField.Pending]).toBe(1); + expect((await getTenantStats(123))[StatusField.InProgress]).toBe(0); + + await processEventQueue(tx.context, "CAP_OUTBOX", "StandardService"); + await commitAndOpenNew(); + + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(0); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(0); + expect(globalStats[StatusField.InProgress]).toBe(0); + + await testHelper.selectEventQueueAndExpectDone(tx, { expectedLength: 1 }); + }); + + it("failed processing transitions pending → inProgress → Error → back to pending", async () => { + const service = cds.outboxed(await cds.connect.to("NotificationService")).tx(context); + await service.send("errorEvent", { to: "to", subject: "subject", body: "body" }); + await commitAndOpenNew(); + + expect((await getTenantStats(123))[StatusField.Pending]).toBe(1); + expect((await getTenantStats(123))[StatusField.InProgress]).toBe(0); + + await processEventQueue(tx.context, "CAP_OUTBOX", "NotificationService"); + await commitAndOpenNew(); + + // Error state means the event will be retried → counts as pending + const tenantStats = await getTenantStats(123); + expect(tenantStats[StatusField.Pending]).toBe(1); + expect(tenantStats[StatusField.InProgress]).toBe(0); + + const globalStats = await getGlobalStats(); + expect(globalStats[StatusField.Pending]).toBe(1); + expect(globalStats[StatusField.InProgress]).toBe(0); + + await testHelper.selectEventQueueAndExpectError(tx, { expectedLength: 1 }); + }); + }); + + const commitAndOpenNew = async () => { + await tx.commit(); + context = new cds.EventContext({ user: "testUser", tenant: 123 }); + tx = cds.tx(context); + }; +}); From f583b591c8f7b01713076470d5e85a2bfc3a2ee5 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 13:57:18 +0100 Subject: [PATCH 12/22] wip --- .claude/worktrees/funny-borg | 2 +- src/dbHandler.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.claude/worktrees/funny-borg b/.claude/worktrees/funny-borg index 900ae7db..17e8d68d 160000 --- a/.claude/worktrees/funny-borg +++ b/.claude/worktrees/funny-borg @@ -1 +1 @@ -Subproject commit 900ae7db9ecb573edb5f4191224cf8469af7739a +Subproject commit 17e8d68d1646218eb96bcfdf233c6a1f645703ba diff --git a/src/dbHandler.js b/src/dbHandler.js index db00cdf7..9381fa04 100644 --- a/src/dbHandler.js +++ b/src/dbHandler.js @@ -73,14 +73,12 @@ const registerEventQueueDbHandler = (dbService) => { if (!registeredHandlers.updateDbHandler) { registeredHandlers.updateDbHandler = true; - dbService.after("UPDATE", def, (affectedRows, req) => { + dbService.after("UPDATE", def, (count, req) => { const newStatus = req.query.UPDATE?.data?.status; if (newStatus == null) { return; } - const count = typeof affectedRows === "number" && affectedRows > 0 ? affectedRows : 1; - req.tx._ = req.tx._ ?? {}; req.tx._.eventQueueStatsPendingDelta = req.tx._.eventQueueStatsPendingDelta ?? 0; req.tx._.eventQueueStatsInProgressDelta = req.tx._.eventQueueStatsInProgressDelta ?? 0; From c59ae6544a8de6ffeb731f6639ab287705e2d3db Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 13:58:35 +0100 Subject: [PATCH 13/22] gitingore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 47915012..1c953d34 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ data/afc.sqlite-wal data/test.sqlite coverage Claude.md +.claude/ # temp temp/ From 866f1422a5f9ac827a7afc0af86195110e12197e Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 14:51:05 +0100 Subject: [PATCH 14/22] wip --- src/runner/runner.js | 8 +++++--- test-integration/__snapshots__/e2e-redis.test.js.snap | 2 +- test-integration/__snapshots__/runner.test.js.snap | 5 +++++ test/mocks/redisMock.js | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/runner/runner.js b/src/runner/runner.js index 2c68bf4a..5591ec76 100644 --- a/src/runner/runner.js +++ b/src/runner/runner.js @@ -162,7 +162,7 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { entries: entries.length, }); tenantCounts[tenantId] = entries; - const pendingByNamespace = {}; + const pendingByNamespace = Object.fromEntries(config.processingNamespaces.map((name) => [name, 0])); for (const entry of entries) { pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; } @@ -189,7 +189,9 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { logger.error("broadcasting events for tenant failed", { tenantId }, err); } } - const globalPendingByNamespace = {}; + const globalPendingByNamespace = Object.fromEntries( + tenantIds.map((tenant) => [tenant, config.processingNamespaces.map((namespace) => ({ namespace, count: 0 }))]) + ); for (const tenantEntries of Object.values(tenantCounts)) { for (const entry of tenantEntries) { globalPendingByNamespace[entry.namespace] = (globalPendingByNamespace[entry.namespace] ?? 0) + entry.count; @@ -389,7 +391,7 @@ const _singleTenantRedis = async () => { logger.info("broadcasting events for run", { entries: entries.length, }); - const pendingByNamespace = {}; + const pendingByNamespace = Object.fromEntries(config.processingNamespaces.map((name) => [name, 0])); for (const entry of entries) { pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; } diff --git a/test-integration/__snapshots__/e2e-redis.test.js.snap b/test-integration/__snapshots__/e2e-redis.test.js.snap index d7f8e85d..161f47ef 100644 --- a/test-integration/__snapshots__/e2e-redis.test.js.snap +++ b/test-integration/__snapshots__/e2e-redis.test.js.snap @@ -11,9 +11,9 @@ exports[`end-to-end redis broadcast checkAndInsertPeriodicEvents should insert n exports[`end-to-end redis broadcast checkAndInsertPeriodicEvents should insert new events and runner should broadcast + process events 2`] = ` [ "EVENT_QUEUE##default##RUN_REDIS_CHECK", + "EVENT_QUEUE##default##stats##global", "EVENT_QUEUE##default####TEST_STATIC", "EVENT_QUEUE##default##stats##tenant##undefined", - "EVENT_QUEUE##default##stats##global", ] `; diff --git a/test-integration/__snapshots__/runner.test.js.snap b/test-integration/__snapshots__/runner.test.js.snap index 495d3dfa..34494250 100644 --- a/test-integration/__snapshots__/runner.test.js.snap +++ b/test-integration/__snapshots__/runner.test.js.snap @@ -262,6 +262,11 @@ exports[`runner redis single tenant no open events 2`] = ` "PX": 1425000, }, }, + "EVENT_QUEUE##default##stats##global": { + "hash": { + "pending": "0", + }, + }, } `; diff --git a/test/mocks/redisMock.js b/test/mocks/redisMock.js index 5cb66f8c..2ff69bd2 100644 --- a/test/mocks/redisMock.js +++ b/test/mocks/redisMock.js @@ -81,6 +81,7 @@ const _createMainClientAndConnect = async () => _buildClient(); module.exports = { attachRedisUnsubscribeHandler: () => {}, subscribeRedisChannel: () => {}, + publishMessage: async () => {}, createClientAndConnect: _createMainClientAndConnect, createMainClientAndConnect: _createMainClientAndConnect, closeSubscribeClient: () => {}, From ba52c32bc92a30a680934f300ba0820d82ff35e7 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 15:07:17 +0100 Subject: [PATCH 15/22] wip --- src/shared/eventQueueStats.js | 28 +++++++++++++++++++ src/shared/openTelemetry.js | 13 ++++++++- test/eventQueueStats.test.js | 51 +++++++++++++++++++++++++++++++++++ test/mocks/redisMock.js | 14 ++++++++++ 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/shared/eventQueueStats.js b/src/shared/eventQueueStats.js index 2010a36c..597ea5a2 100644 --- a/src/shared/eventQueueStats.js +++ b/src/shared/eventQueueStats.js @@ -158,6 +158,33 @@ const deleteTenantStats = async (tenantId) => { } }; +/** + * Resets the inProgress counter to 0 for all processing namespaces (global + all tenants). + * Called on instance startup to clean up stale counts left by a previous crash. + */ +const resetInProgressCounters = async () => { + try { + const clientOrCluster = await redis.createMainClientAndConnect(); + const clients = redis.isClusterMode() + ? clientOrCluster.masters.map((master) => master.client) + : [clientOrCluster]; + + const globalOps = config.processingNamespaces.map((namespace) => + clientOrCluster.hSet(`${_keyPrefix(namespace)}##stats##global`, StatusField.InProgress, 0) + ); + await Promise.allSettled(globalOps); + + // NOTE: use SCAN because KEYS is not supported for cluster clients + for (const client of clients) { + for await (const key of client.scanIterator({ MATCH: "*##stats##tenant##*", COUNT: 1000 })) { + await client.hSet(key, StatusField.InProgress, 0); + } + } + } catch (err) { + cds.log(COMPONENT_NAME).error("failed to reset inProgress counters on startup", err); + } +}; + const _parseCounterHash = (raw) => ({ [StatusField.Pending]: raw[StatusField.Pending] != null ? parseInt(raw[StatusField.Pending]) : 0, [StatusField.InProgress]: raw[StatusField.InProgress] != null ? parseInt(raw[StatusField.InProgress]) : 0, @@ -180,4 +207,5 @@ module.exports = { getTenantStats, getGlobalStats, deleteTenantStats, + resetInProgressCounters, }; diff --git a/src/shared/openTelemetry.js b/src/shared/openTelemetry.js index 323edecf..96af84e0 100644 --- a/src/shared/openTelemetry.js +++ b/src/shared/openTelemetry.js @@ -134,6 +134,10 @@ const initMetrics = () => { _metricsInitialized = true; + eventQueueStats + .resetInProgressCounters() + .catch((err) => cds.log(COMPONENT_NAME).error("failed to reset inProgress counters", err)); + const meter = otel.metrics.getMeter("@cap-js-community/event-queue"); const pendingGauge = meter.createObservableGauge("cap.event_queue.jobs.pending", { @@ -149,6 +153,14 @@ const initMetrics = () => { unit: "s", }); + _statsSnapshot = { + lastRefreshedAt: Date.now(), + namespaces: Object.fromEntries( + config.processingNamespaces.map((namespace) => [namespace, { pending: 0, inProgress: 0 }]) + ), + }; + _refreshStats(); + meter.addBatchObservableCallback( (observableResult) => { if (!_statsSnapshot) { @@ -164,7 +176,6 @@ const initMetrics = () => { [pendingGauge, inProgressGauge, refreshAgeGauge] ); - _refreshStats(); setInterval(_refreshStats, 30_000).unref(); }; diff --git a/test/eventQueueStats.test.js b/test/eventQueueStats.test.js index 6c3815ba..0e908046 100644 --- a/test/eventQueueStats.test.js +++ b/test/eventQueueStats.test.js @@ -17,6 +17,7 @@ const { getTenantStats, getGlobalStats, deleteTenantStats, + resetInProgressCounters, } = require("../src/shared/eventQueueStats"); const project = __dirname + "/.."; @@ -131,4 +132,54 @@ describe("eventQueueStats", () => { await expect(deleteTenantStats("nonexistent")).resolves.toBeUndefined(); }); }); + + describe("resetInProgressCounters", () => { + it("resets global inProgress to 0 for all configured namespaces", async () => { + await incrementCounters("t1", StatusField.InProgress, 5); + + await resetInProgressCounters(); + + const global = await getGlobalStats(); + expect(global.inProgress).toBe(0); + }); + + it("does not touch the pending counter", async () => { + await incrementCounters("t1", StatusField.Pending, 3); + await incrementCounters("t1", StatusField.InProgress, 2); + + await resetInProgressCounters(); + + const global = await getGlobalStats(); + expect(global.pending).toBe(3); + expect(global.inProgress).toBe(0); + }); + + it("resets inProgress in tenant hash keys found via scan", async () => { + await incrementCounters("t1", StatusField.InProgress, 4); + await incrementCounters("t2", StatusField.InProgress, 2); + + await resetInProgressCounters(); + + const t1 = await getTenantStats("t1"); + expect(t1.inProgress).toBe(0); + + const t2 = await getTenantStats("t2"); + expect(t2.inProgress).toBe(0); + }); + + it("preserves tenant pending counter after reset", async () => { + await incrementCounters("t1", StatusField.Pending, 7); + await incrementCounters("t1", StatusField.InProgress, 3); + + await resetInProgressCounters(); + + const t1 = await getTenantStats("t1"); + expect(t1.pending).toBe(7); + expect(t1.inProgress).toBe(0); + }); + + it("resolves without error when no keys exist", async () => { + await expect(resetInProgressCounters()).resolves.toBeUndefined(); + }); + }); }); diff --git a/test/mocks/redisMock.js b/test/mocks/redisMock.js index 2ff69bd2..987f957c 100644 --- a/test/mocks/redisMock.js +++ b/test/mocks/redisMock.js @@ -38,6 +38,19 @@ const _buildClient = () => ({ hGetAll: async (key) => { return state[key]?.hash ?? {}; }, + scanIterator: ({ MATCH } = {}) => { + const regex = MATCH + ? new RegExp( + "^" + MATCH.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$" + ) + : null; + const matchingKeys = Object.keys(state).filter((k) => !regex || regex.test(k)); + return (async function* () { + for (const key of matchingKeys) { + yield key; + } + })(); + }, multi: () => { const ops = []; const pipeline = { @@ -82,6 +95,7 @@ module.exports = { attachRedisUnsubscribeHandler: () => {}, subscribeRedisChannel: () => {}, publishMessage: async () => {}, + isClusterMode: () => false, createClientAndConnect: _createMainClientAndConnect, createMainClientAndConnect: _createMainClientAndConnect, closeSubscribeClient: () => {}, From a5894c4821f7b5a725eb819fc563f899b9d5a67f Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 15:08:40 +0100 Subject: [PATCH 16/22] fix --- src/runner/runner.js | 4 +--- test-integration/__snapshots__/runner.test.js.snap | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/runner/runner.js b/src/runner/runner.js index 5591ec76..e2d290d3 100644 --- a/src/runner/runner.js +++ b/src/runner/runner.js @@ -189,9 +189,7 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { logger.error("broadcasting events for tenant failed", { tenantId }, err); } } - const globalPendingByNamespace = Object.fromEntries( - tenantIds.map((tenant) => [tenant, config.processingNamespaces.map((namespace) => ({ namespace, count: 0 }))]) - ); + const globalPendingByNamespace = Object.fromEntries(config.processingNamespaces.map((namespace) => [namespace, 0])); for (const tenantEntries of Object.values(tenantCounts)) { for (const entry of tenantEntries) { globalPendingByNamespace[entry.namespace] = (globalPendingByNamespace[entry.namespace] ?? 0) + entry.count; diff --git a/test-integration/__snapshots__/runner.test.js.snap b/test-integration/__snapshots__/runner.test.js.snap index 34494250..9009169c 100644 --- a/test-integration/__snapshots__/runner.test.js.snap +++ b/test-integration/__snapshots__/runner.test.js.snap @@ -86,6 +86,16 @@ exports[`runner redis multi tenant no open events 2`] = ` "PX": 60000, }, }, + "EVENT_QUEUE##default##stats##global": { + "hash": { + "pending": "0", + }, + }, + "EVENT_QUEUE##default##stats##tenant##TEST_STATIC": { + "hash": { + "pending": "0", + }, + }, } `; From d8503948c9dabcd546ac41ff8e4b1e6f7849fc20 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 15:21:33 +0100 Subject: [PATCH 17/22] fix lint --- src/shared/eventQueueStats.js | 4 +--- test/mocks/redisMock.js | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/shared/eventQueueStats.js b/src/shared/eventQueueStats.js index 597ea5a2..4bba3ecf 100644 --- a/src/shared/eventQueueStats.js +++ b/src/shared/eventQueueStats.js @@ -165,9 +165,7 @@ const deleteTenantStats = async (tenantId) => { const resetInProgressCounters = async () => { try { const clientOrCluster = await redis.createMainClientAndConnect(); - const clients = redis.isClusterMode() - ? clientOrCluster.masters.map((master) => master.client) - : [clientOrCluster]; + const clients = redis.isClusterMode() ? clientOrCluster.masters.map((master) => master.client) : [clientOrCluster]; const globalOps = config.processingNamespaces.map((namespace) => clientOrCluster.hSet(`${_keyPrefix(namespace)}##stats##global`, StatusField.InProgress, 0) diff --git a/test/mocks/redisMock.js b/test/mocks/redisMock.js index 987f957c..1465ebcb 100644 --- a/test/mocks/redisMock.js +++ b/test/mocks/redisMock.js @@ -41,7 +41,11 @@ const _buildClient = () => ({ scanIterator: ({ MATCH } = {}) => { const regex = MATCH ? new RegExp( - "^" + MATCH.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$" + "^" + + MATCH.replace(/[.+^${}()|[\]\\]/g, "\\$&") + .replace(/\*/g, ".*") + .replace(/\?/g, ".") + + "$" ) : null; const matchingKeys = Object.keys(state).filter((k) => !regex || regex.test(k)); From 14e44e603c65e18606e5ef0331cd4638541708c5 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Sun, 8 Mar 2026 15:22:50 +0100 Subject: [PATCH 18/22] wip --- .claude/worktrees/funny-borg | 1 - 1 file changed, 1 deletion(-) delete mode 160000 .claude/worktrees/funny-borg diff --git a/.claude/worktrees/funny-borg b/.claude/worktrees/funny-borg deleted file mode 160000 index 17e8d68d..00000000 --- a/.claude/worktrees/funny-borg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 17e8d68d1646218eb96bcfdf233c6a1f645703ba From 22267fc90e71a73d514de27e1db79fcbdb8c8332 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Thu, 2 Apr 2026 21:32:49 +0200 Subject: [PATCH 19/22] add flag to disable the redis statistic --- src/config.js | 9 +++++++++ src/dbHandler.js | 9 ++++----- src/initialize.js | 2 ++ src/runner/runner.js | 30 ++++++++++++++++++------------ src/shared/openTelemetry.js | 2 +- test/dbHandlerStats.test.js | 21 ++------------------- tmp/newTask.txt | 2 ++ 7 files changed, 38 insertions(+), 37 deletions(-) create mode 100644 tmp/newTask.txt diff --git a/src/config.js b/src/config.js index 83327bd3..4fa68814 100644 --- a/src/config.js +++ b/src/config.js @@ -107,6 +107,7 @@ class Config { #redisOptions; #insertEventsBeforeCommit; #enableTelemetry; + #collectEventQueueMetrics; #unsubscribeHandlers = []; #unsubscribedTenants = {}; #cronTimezone; @@ -901,6 +902,14 @@ class Config { return this.#enableTelemetry; } + set collectEventQueueMetrics(value) { + this.#collectEventQueueMetrics = value; + } + + get collectEventQueueMetrics() { + return this.#collectEventQueueMetrics; + } + get isMultiTenancy() { return !!cds.requires.multitenancy; } diff --git a/src/dbHandler.js b/src/dbHandler.js index 9381fa04..bdac0131 100644 --- a/src/dbHandler.js +++ b/src/dbHandler.js @@ -45,7 +45,7 @@ const registerEventQueueDbHandler = (dbService) => { if (!req.tx._.eventQueueSucceededHandlerRegistered) { req.tx._.eventQueueSucceededHandlerRegistered = true; req.on("succeeded", () => { - if (config.redisEnabled && req.tx._.eventQueueStatsOpenCount) { + if (config.collectEventQueueMetrics && config.redisEnabled && req.tx._.eventQueueStatsOpenCount) { eventQueueStats .incrementCounters(req.tenant, eventQueueStats.StatusField.Pending, req.tx._.eventQueueStatsOpenCount) .catch((err) => { @@ -72,6 +72,9 @@ const registerEventQueueDbHandler = (dbService) => { }); if (!registeredHandlers.updateDbHandler) { + if (!config.collectEventQueueMetrics || !config.redisEnabled) { + return; + } registeredHandlers.updateDbHandler = true; dbService.after("UPDATE", def, (count, req) => { const newStatus = req.query.UPDATE?.data?.status; @@ -100,10 +103,6 @@ const registerEventQueueDbHandler = (dbService) => { if (!req.tx._.eventQueueUpdateSucceededHandlerRegistered) { req.tx._.eventQueueUpdateSucceededHandlerRegistered = true; req.on("succeeded", () => { - if (!config.redisEnabled) { - return; - } - const pendingDelta = req.tx._.eventQueueStatsPendingDelta; const inProgressDelta = req.tx._.eventQueueStatsInProgressDelta; const ops = []; diff --git a/src/initialize.js b/src/initialize.js index 7ba7f0ef..6f860c08 100644 --- a/src/initialize.js +++ b/src/initialize.js @@ -50,6 +50,7 @@ const CONFIG_VARS = [ ["disableProcessingOfSuspendedTenants", true], ["namespace", "default"], ["processingNamespaces", ["default"]], + ["collectEventQueueMetrics", false], ]; /** @@ -79,6 +80,7 @@ const CONFIG_VARS = [ * @param {string} [options.crashOnRedisUnavailable=true] - If enabled an error is thrown if the redis connection check is not successful * @param {string} [options.namespace=default] - Default namespace in which events are published * @param {string} [options.processingNamespaces=[default]] - Namespaces which the application processes + * @param {boolean} [options.collectEventQueueMetrics=false] - Enable collection of event queue metrics (pending/inProgress counters) stored in Redis and exposed via OpenTelemetry gauges. */ const initialize = async (options = {}) => { if (config.initialized) { diff --git a/src/runner/runner.js b/src/runner/runner.js index e2d290d3..9a2fcfcf 100644 --- a/src/runner/runner.js +++ b/src/runner/runner.js @@ -166,10 +166,12 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { for (const entry of entries) { pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; } - for (const [namespace, count] of Object.entries(pendingByNamespace)) { - eventQueueStats - .setTenantCounter(tenantId, namespace, eventQueueStats.StatusField.Pending, count) - .catch((err) => logger.error("updating tenant stats failed", err, { tenantId, namespace })); + if (config.collectEventQueueMetrics) { + for (const [namespace, count] of Object.entries(pendingByNamespace)) { + eventQueueStats + .setTenantCounter(tenantId, namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating tenant stats failed", err, { tenantId, namespace })); + } } if (!entries.length) { return; @@ -195,10 +197,12 @@ const _executeEventsAllTenantsRedis = async (tenantIds) => { globalPendingByNamespace[entry.namespace] = (globalPendingByNamespace[entry.namespace] ?? 0) + entry.count; } } - for (const [namespace, count] of Object.entries(globalPendingByNamespace)) { - eventQueueStats - .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) - .catch((err) => logger.error("updating global stats failed", err, { namespace })); + if (config.collectEventQueueMetrics) { + for (const [namespace, count] of Object.entries(globalPendingByNamespace)) { + eventQueueStats + .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating global stats failed", err, { namespace })); + } } }; @@ -393,10 +397,12 @@ const _singleTenantRedis = async () => { for (const entry of entries) { pendingByNamespace[entry.namespace] = (pendingByNamespace[entry.namespace] ?? 0) + entry.count; } - for (const [namespace, count] of Object.entries(pendingByNamespace)) { - eventQueueStats - .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) - .catch((err) => logger.error("updating global stats failed", err, { namespace })); + if (config.collectEventQueueMetrics) { + for (const [namespace, count] of Object.entries(pendingByNamespace)) { + eventQueueStats + .setGlobalCounter(namespace, eventQueueStats.StatusField.Pending, count) + .catch((err) => logger.error("updating global stats failed", err, { namespace })); + } } if (!entries.length) { return; diff --git a/src/shared/openTelemetry.js b/src/shared/openTelemetry.js index 96af84e0..418d96ea 100644 --- a/src/shared/openTelemetry.js +++ b/src/shared/openTelemetry.js @@ -124,7 +124,7 @@ const _refreshStats = async () => { }; const initMetrics = () => { - if (_metricsInitialized || !config.enableTelemetry || !config.redisEnabled || !otel?.metrics) { + if (_metricsInitialized || !config.collectEventQueueMetrics || !config.enableTelemetry || !config.redisEnabled || !otel?.metrics) { return; } const meterProvider = otel.metrics.getMeterProvider?.(); diff --git a/test/dbHandlerStats.test.js b/test/dbHandlerStats.test.js index 2bcd8565..412dd1c7 100644 --- a/test/dbHandlerStats.test.js +++ b/test/dbHandlerStats.test.js @@ -43,6 +43,7 @@ describe("dbHandler - stats tracking via CAP outbox", () => { }); cds.emit("connect", await cds.connect.to("db")); config.redisEnabled = true; + config.collectEventQueueMetrics = true; eventQueue.registerEventQueueDbHandler(cds.db); loggerMock = mockLogger(); }); @@ -63,6 +64,7 @@ describe("dbHandler - stats tracking via CAP outbox", () => { afterAll(async () => { config.redisEnabled = false; + config.collectEventQueueMetrics = false; await cds.shutdown; }); @@ -269,25 +271,6 @@ describe("dbHandler - stats tracking via CAP outbox", () => { expect(loggerMock.callsLengths().error).toBe(0); }); - it("does not adjust counters when redisEnabled is false", async () => { - const service = (await cds.connect.to("StandardService")).tx(context); - await service.send("main", {}); - await service.send("main", {}); - await commitAndOpenNew(); // pending=2 - - config.redisEnabled = false; - try { - await tx.run(UPDATE.entity("sap.eventqueue.Event").set({ status: EventProcessingStatus.InProgress })); - await commitAndOpenNew(); - - const tenantStats = await getTenantStats(123); - expect(tenantStats[StatusField.Pending]).toBe(2); - expect(tenantStats[StatusField.InProgress]).toBe(0); - } finally { - config.redisEnabled = true; - } - }); - it("does not adjust counters when transaction is rolled back", async () => { const service = (await cds.connect.to("StandardService")).tx(context); await service.send("main", {}); diff --git a/tmp/newTask.txt b/tmp/newTask.txt new file mode 100644 index 00000000..36e16d3b --- /dev/null +++ b/tmp/newTask.txt @@ -0,0 +1,2 @@ +initialize only if instance number is zero. +initzialize only if is eventprocessor make sure app only reports for its processing namespace \ No newline at end of file From 82efd21e83a55cb807b1bff201b1a1a7b15dc470 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Thu, 2 Apr 2026 21:57:45 +0200 Subject: [PATCH 20/22] wip --- CHANGELOG.md | 1 + docs/Gemfile | 15 ++- docs/Gemfile.lock | 283 ++++++++------------------------------- docs/_config.yml | 2 +- docs/index.md | 23 ++-- docs/telemetry/img_2.png | Bin 0 -> 286599 bytes docs/telemetry/index.md | 65 +++++++++ 7 files changed, 141 insertions(+), 248 deletions(-) create mode 100644 docs/telemetry/img_2.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 91e7b9b3..20f3839c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [CAP Queue] Add support for defining successor and failed events of event handlers. See documentation for how to use it. - [CAP Queue] Allow to propagate cds.context properties (e.g. features). This can be configured per event (`cds.env.requires[].queued.propagateContextProperties = ["features"]`) +- [Telemetry] Add opt-in event queue metrics (`collectEventQueueMetrics`). When enabled together with Redis and an OpenTelemetry MeterProvider, the module publishes `cap.event_queue.jobs.pending`, `cap.event_queue.jobs.in_progress`, and `cap.event_queue.stats.refresh_age` as Observable Gauges, broken down by namespace. See [documentation](https://cap-js-community.github.io/event-queue/telemetry/). ### Fixed diff --git a/docs/Gemfile b/docs/Gemfile index d2dd01aa..80a79ba6 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -1,13 +1,14 @@ source "https://rubygems.org" -# https://pages.github.com/versions/ - # https://github.com/ruby/ruby -ruby "~> 3.4.7" +ruby ">= 3.4.7" + +# https://jekyllrb.com/docs/installation/ +gem "jekyll", "~> 4.3" -# NOTE: this fixes the relevant jekyll version -# https://github.com/github/pages-gem/releases -gem "github-pages", "~> 232", group: :jekyll_plugins +# Ruby 4.0 removed these from default gems +gem "logger" +gem "csv" # https://github.com/just-the-docs/just-the-docs/releases -gem "just-the-docs", "~> 0.10.1" \ No newline at end of file +gem "just-the-docs", "~> 0.10.1" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index f2a6542e..a5554ce6 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,50 +1,18 @@ GEM remote: https://rubygems.org/ specs: - activesupport (8.1.1) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - json - logger (>= 1.4.2) - minitest (>= 5.1) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) - uri (>= 0.13.1) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) base64 (0.3.0) bigdecimal (3.3.1) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) colorator (1.1.0) - commonmarker (0.23.12) concurrent-ruby (1.3.5) - connection_pool (2.5.4) csv (3.3.5) - dnsruby (1.73.1) - base64 (>= 0.2) - logger (~> 1.6) - simpleidn (~> 0.2.1) - drb (2.2.3) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) - ethon (0.15.0) - ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.10.0) - faraday (2.14.0) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.2) - net-http (~> 0.5) + ffi (1.17.2) ffi (1.17.2-aarch64-linux-gnu) ffi (1.17.2-aarch64-linux-musl) ffi (1.17.2-arm-linux-gnu) @@ -54,175 +22,57 @@ GEM ffi (1.17.2-x86_64-linux-gnu) ffi (1.17.2-x86_64-linux-musl) forwardable-extended (2.6.0) - gemoji (4.1.0) - github-pages (232) - github-pages-health-check (= 1.18.2) - jekyll (= 3.10.0) - jekyll-avatar (= 0.8.0) - jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.5.1) - jekyll-default-layout (= 0.1.5) - jekyll-feed (= 0.17.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.16.1) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.13.0) - kramdown (= 2.4.0) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.16.2, < 2.0) - rouge (= 3.30.0) - terminal-table (~> 1.4) - webrick (~> 1.8) - github-pages-health-check (1.18.2) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (>= 4, < 8) - public_suffix (>= 3.0, < 6.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) + google-protobuf (4.34.1) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-aarch64-linux-gnu) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-aarch64-linux-musl) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-arm64-darwin) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-x86_64-darwin) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-x86_64-linux-gnu) + bigdecimal + rake (~> 13.3) + google-protobuf (4.34.1-x86_64-linux-musl) + bigdecimal + rake (~> 13.3) http_parser.rb (0.8.0) i18n (1.14.7) concurrent-ruby (~> 1.0) - jekyll (3.10.0) + jekyll (4.4.1) addressable (~> 2.4) + base64 (~> 0.2) colorator (~> 1.0) csv (~> 3.0) em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) + i18n (~> 1.0) + jekyll-sass-converter (>= 2.0, < 4.0) jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) + json (~> 2.6) + kramdown (~> 2.3, >= 2.3.1) + kramdown-parser-gfm (~> 1.0) liquid (~> 4.0) - mercenary (~> 0.3.3) + mercenary (~> 0.3, >= 0.3.6) pathutil (~> 0.9) - rouge (>= 1.7, < 4) + rouge (>= 3.0, < 5.0) safe_yaml (~> 1.0) - webrick (>= 1.0) - jekyll-avatar (0.8.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.2.2) - coffee-script (~> 2.2) - coffee-script-source (~> 1.12) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.5.1) - commonmarker (>= 0.23.7, < 1.1.0) - jekyll (>= 3.9, < 4.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.5) - jekyll (>= 3.0, < 5.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.16.1) - jekyll (>= 3.4, < 5.0) - octokit (>= 4, < 7, != 4.4.0) + terminal-table (>= 1.8, < 4.0) + webrick (~> 1.7) jekyll-include-cache (0.2.1) jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) + jekyll-sass-converter (3.1.0) + sass-embedded (~> 1.75) jekyll-seo-tag (2.8.0) jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) jekyll-watch (2.2.1) listen (~> 3.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) json (2.16.0) just-the-docs (0.10.1) jekyll (>= 3.8.5) @@ -239,62 +89,35 @@ GEM rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) mercenary (0.3.6) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.26.1) - net-http (0.7.0) - uri - nokogiri (1.18.10-aarch64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-aarch64-linux-musl) - racc (~> 1.4) - nokogiri (1.18.10-arm-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-arm-linux-musl) - racc (~> 1.4) - nokogiri (1.18.10-arm64-darwin) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-darwin) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-gnu) - racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-musl) - racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (5.1.1) - racc (1.8.1) rake (13.3.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) rexml (3.4.4) rouge (3.30.0) - rubyzip (2.4.1) safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.3) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - simpleidn (0.2.3) + sass-embedded (1.98.0-aarch64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-aarch64-linux-musl) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-arm-linux-gnueabihf) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-arm-linux-musleabihf) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-x86_64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-x86_64-linux-gnu) + google-protobuf (~> 4.31) + sass-embedded (1.98.0-x86_64-linux-musl) + google-protobuf (~> 4.31) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.5.0) - ethon (>= 0.9.0, < 0.16.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) unicode-display_width (1.8.0) - uri (1.1.1) webrick (1.9.1) PLATFORMS @@ -308,8 +131,10 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - github-pages (~> 232) + csv + jekyll (~> 4.3) just-the-docs (~> 0.10.1) + logger RUBY VERSION ruby 3.4.7p58 diff --git a/docs/_config.yml b/docs/_config.yml index 4c70bba3..ec396446 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -26,7 +26,7 @@ description: >- # Build settings baseurl: /event-queue markdown: kramdown -remote_theme: just-the-docs/just-the-docs@v0.4.0 +theme: just-the-docs # Exclude from processing. # The following items will not be processed, by default. diff --git a/docs/index.md b/docs/index.md index 7e30bf8e..274fc9ad 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,8 +32,9 @@ processing. job execution. - [Managed transactions](/event-queue/transaction-handling) for reliable event processing. - [Plug and play](setup) integration via `cds-plugin`. -- [Telemetry support and trace propagation](/event-queue/telemetry), including event-queue-specific telemetry data and - tracing information. +- [Telemetry support and trace propagation](/event-queue/telemetry), including distributed tracing, trace context + propagation, and opt-in OpenTelemetry metrics for real-time queue depth monitoring (`cap.event_queue.jobs.pending`, + `cap.event_queue.jobs.in_progress`). - Full support for local testing with SQLite, enabling feature development and testing in a local environment to boost productivity. - Asynchronous processing of resource-intensive tasks to improve UI responsiveness. @@ -70,13 +71,13 @@ processing. manages the load, distributing it across all available app instances.+ - OpenTelemetry and Trace Propagation - The event-queue integrates with OpenTelemetry, providing detailed telemetry data for monitoring and - troubleshooting. - OpenTelemetry captures traces, spans, and metrics that help diagnose performance bottlenecks, detect failures, and - understand the lifecycle of events. + troubleshooting. OpenTelemetry captures traces, spans, and metrics that help diagnose performance bottlenecks, + detect failures, and understand the lifecycle of events. - **Trace Propagation** ensures that tracing context is maintained across distributed services, allowing end-to-end - visibility - into event processing. This is especially beneficial in microservice architectures, where events traverse multiple - services and instances. With trace propagation, developers can track event execution paths, measure processing - times, - and correlate related events across different services, leading to improved observability and debugging - efficiency. + visibility into event processing. This is especially beneficial in microservice architectures, where events + traverse multiple services and instances. With trace propagation, developers can track event execution paths, + measure processing times, and correlate related events across different services, leading to improved observability + and debugging efficiency. + - **Queue Depth Metrics** – When enabled via `collectEventQueueMetrics`, the event-queue exposes real-time + Observable Gauges (`cap.event_queue.jobs.pending`, `cap.event_queue.jobs.in_progress`) per namespace, backed by + Redis and surfaced to any OpenTelemetry-compatible monitoring tool. diff --git a/docs/telemetry/img_2.png b/docs/telemetry/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..02ad9171daa8346404c7a8fadfd0ed900305068c GIT binary patch literal 286599 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 z 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 z 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 z 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 Date: Thu, 2 Apr 2026 22:19:32 +0200 Subject: [PATCH 21/22] fix tests --- src/dbHandler.js | 3 +++ test-integration/dbHandlerStats.test.js | 2 ++ test-integration/e2e-redis.test.js | 1 + test-integration/runner.test.js | 1 + 4 files changed, 7 insertions(+) diff --git a/src/dbHandler.js b/src/dbHandler.js index bdac0131..2afe44ef 100644 --- a/src/dbHandler.js +++ b/src/dbHandler.js @@ -103,6 +103,9 @@ const registerEventQueueDbHandler = (dbService) => { if (!req.tx._.eventQueueUpdateSucceededHandlerRegistered) { req.tx._.eventQueueUpdateSucceededHandlerRegistered = true; req.on("succeeded", () => { + if (!config.redisEnabled) { + return; + } const pendingDelta = req.tx._.eventQueueStatsPendingDelta; const inProgressDelta = req.tx._.eventQueueStatsInProgressDelta; const ops = []; diff --git a/test-integration/dbHandlerStats.test.js b/test-integration/dbHandlerStats.test.js index 5f836ec5..6a7cdbf4 100644 --- a/test-integration/dbHandlerStats.test.js +++ b/test-integration/dbHandlerStats.test.js @@ -42,6 +42,7 @@ describe("dbHandler - stats tracking on HANA", () => { const db = await cds.connect.to("db"); cds.emit("connect", db); config.redisEnabled = true; + config.collectEventQueueMetrics = true; eventQueue.registerEventQueueDbHandler(db); loggerMock = mockLogger(); }); @@ -64,6 +65,7 @@ describe("dbHandler - stats tracking on HANA", () => { afterAll(async () => { config.redisEnabled = false; + config.collectEventQueueMetrics = false; await cds.disconnect(); await cds.shutdown(); }); diff --git a/test-integration/e2e-redis.test.js b/test-integration/e2e-redis.test.js index 4ee0b4c2..49b9c093 100644 --- a/test-integration/e2e-redis.test.js +++ b/test-integration/e2e-redis.test.js @@ -75,6 +75,7 @@ describe("end-to-end", () => { isEventQueueActive: true, }); eventQueue.config.redisEnabled = true; + eventQueue.config.collectEventQueueMetrics = true; cds.emit("connect", await cds.connect.to("db")); }); diff --git a/test-integration/runner.test.js b/test-integration/runner.test.js index 366fa217..0c63671d 100644 --- a/test-integration/runner.test.js +++ b/test-integration/runner.test.js @@ -59,6 +59,7 @@ describe("runner", () => { }); configInstance = eventQueue.config; configInstance.redisEnabled = true; + configInstance.collectEventQueueMetrics = true; loggerMock = mockLogger(); jest.clearAllMocks(); }); From 205c2c806788c9215df95cde107142d664d93029 Mon Sep 17 00:00:00 2001 From: Max Gruenfelder Date: Thu, 2 Apr 2026 22:24:04 +0200 Subject: [PATCH 22/22] prettier --- docs/telemetry/index.md | 20 ++++++++++---------- src/shared/openTelemetry.js | 8 +++++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/telemetry/index.md b/docs/telemetry/index.md index 7845bd8d..0ed8b116 100644 --- a/docs/telemetry/index.md +++ b/docs/telemetry/index.md @@ -104,10 +104,10 @@ processed) per namespace, stored in Redis and exposed as OpenTelemetry Observabl ### Metrics Published -| Metric name | Unit | Description | -| ------------------------------------ | ---- | --------------------------------------------------------- | -| `cap.event_queue.jobs.pending` | 1 | Current number of events waiting to be processed | -| `cap.event_queue.jobs.in_progress` | 1 | Current number of events actively being processed | +| Metric name | Unit | Description | +| ----------------------------------- | ---- | --------------------------------------------------------- | +| `cap.event_queue.jobs.pending` | 1 | Current number of events waiting to be processed | +| `cap.event_queue.jobs.in_progress` | 1 | Current number of events actively being processed | | `cap.event_queue.stats.refresh_age` | s | Age of the most recent stats snapshot (staleness monitor) | All metrics carry a `queue.namespace` attribute so you can filter by namespace in your monitoring tool. @@ -148,12 +148,12 @@ Or via `cds.env` (e.g. in `package.json`): The full set of conditions required for metrics to be active: -| Condition | Required value | Notes | -| ------------------------------- | -------------- | ---------------------------------------------------- | -| `collectEventQueueMetrics` | `true` | Master switch; default `false` | -| `enableTelemetry` | `true` | Default `true`; global telemetry kill-switch | -| Redis enabled | yes | Stats are stored in Redis hashes | -| OpenTelemetry metrics SDK | present | `@opentelemetry/api` with a configured MeterProvider | +| Condition | Required value | Notes | +| -------------------------- | -------------- | ---------------------------------------------------- | +| `collectEventQueueMetrics` | `true` | Master switch; default `false` | +| `enableTelemetry` | `true` | Default `true`; global telemetry kill-switch | +| Redis enabled | yes | Stats are stored in Redis hashes | +| OpenTelemetry metrics SDK | present | `@opentelemetry/api` with a configured MeterProvider | If any condition is not met, `initMetrics()` returns immediately and no gauges are registered. diff --git a/src/shared/openTelemetry.js b/src/shared/openTelemetry.js index 418d96ea..4192d6f2 100644 --- a/src/shared/openTelemetry.js +++ b/src/shared/openTelemetry.js @@ -124,7 +124,13 @@ const _refreshStats = async () => { }; const initMetrics = () => { - if (_metricsInitialized || !config.collectEventQueueMetrics || !config.enableTelemetry || !config.redisEnabled || !otel?.metrics) { + if ( + _metricsInitialized || + !config.collectEventQueueMetrics || + !config.enableTelemetry || + !config.redisEnabled || + !otel?.metrics + ) { return; } const meterProvider = otel.metrics.getMeterProvider?.();