Skip to content

Commit 6e75a22

Browse files
soccermaxMax Gruenfelder
andauthored
fix retry open after (#438)
Co-authored-by: Max Gruenfelder <maximilian.gruenfelder@scheer-group.com>
1 parent 39b932e commit 6e75a22

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## v2.1.0 - 2025-02-XX
9+
10+
### Added
11+
12+
- [CAP Queue] Add support for defining successor and failed events of event handlers. See documentation for how to use it.
13+
- [CAP Queue] Allow to propagate cds.context properties (e.g. features). This can be configured per event (`cds.env.requires[<SERVICE>].queued.propagatedContextProperties = ["features"]`)
14+
15+
### Fixed
16+
17+
- The event property `retryOpenAfter` now works as expected.
18+
819
## v2.0.4 - 2025-01-22
920

1021
### Fixed

src/EventQueueProcessorBase.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,10 +504,16 @@ class EventQueueProcessorBase {
504504
if (!data.startAfter && [EventProcessingStatus.Error, EventProcessingStatus.Open].includes(data.status)) {
505505
data.startAfter = new Date(
506506
Date.now() +
507-
(EventProcessingStatus.Error ? this.#eventConfig.retryFailedAfter : this.#eventConfig.retryOpenAfter)
507+
(data.status === EventProcessingStatus.Error
508+
? this.#eventConfig.retryFailedAfter
509+
: this.#eventConfig.retryOpenAfter)
508510
);
509511
}
510512

513+
if (data.status === EventProcessingStatus.Open && !("attempts" in data)) {
514+
data.attempts = { "-=": 1 };
515+
}
516+
511517
if (data.startAfter) {
512518
this.#eventSchedulerInstance.scheduleEvent(
513519
this.__context.tenant,

test/asset/outboxProject/srv/service/standard-service.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ class StandardService extends cds.Service {
119119
}),
120120
}));
121121
});
122+
123+
this.on("retryOpenAfter", () => {
124+
return { status: 0 };
125+
});
126+
127+
this.on("retryFailedAfter", () => {
128+
return { status: 3 };
129+
});
122130
}
123131
}
124132

test/eventQueueOutbox.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ cds.env.requires.StandardService = {
126126
propagateHeaders: ["authId", "customHeader"],
127127
events: {
128128
timeBucketAction: { timeBucket: "*/60 * * * * *" },
129+
retryFailedAfter: { retryFailedAfter: 120 * 1000 },
130+
retryOpenAfter: { retryOpenAfter: 140 * 1000 },
129131
},
130132
},
131133
};
@@ -2712,6 +2714,42 @@ describe("event-queue outbox", () => {
27122714
});
27132715
});
27142716
});
2717+
2718+
describe("retry open and failed after", () => {
2719+
it("retry failed after", async () => {
2720+
const service = await cds.connect.to("StandardService");
2721+
await service.send("retryFailedAfter", {});
2722+
await commitAndOpenNew();
2723+
await processEventQueue(tx.context, "CAP_OUTBOX", `${service.name}.retryFailedAfter`);
2724+
const [event] = await testHelper.selectEventQueueAndReturn(tx, {
2725+
expectedLength: 1,
2726+
additionalColumns: ["lastAttemptTimestamp"],
2727+
});
2728+
expect(event).toMatchObject({
2729+
status: EventProcessingStatus.Error,
2730+
attempts: 1,
2731+
startAfter: new Date(new Date(event.lastAttemptTimestamp).getTime() + 120 * 1000).toISOString(),
2732+
});
2733+
expect(loggerMock.callsLengths().error).toEqual(0);
2734+
});
2735+
2736+
it("retry open after", async () => {
2737+
const service = await cds.connect.to("StandardService");
2738+
await service.send("retryOpenAfter", {});
2739+
await commitAndOpenNew();
2740+
await processEventQueue(tx.context, "CAP_OUTBOX", `${service.name}.retryOpenAfter`);
2741+
const [event] = await testHelper.selectEventQueueAndReturn(tx, {
2742+
expectedLength: 1,
2743+
additionalColumns: ["lastAttemptTimestamp"],
2744+
});
2745+
expect(event).toMatchObject({
2746+
status: EventProcessingStatus.Open,
2747+
attempts: 0,
2748+
startAfter: new Date(new Date(event.lastAttemptTimestamp).getTime() + 140 * 1000).toISOString(),
2749+
});
2750+
expect(loggerMock.callsLengths().error).toEqual(0);
2751+
});
2752+
});
27152753
});
27162754

27172755
const commitAndOpenNew = async () => {

0 commit comments

Comments
 (0)