perf: cache-only strategy for list views, cache-then-cw for single fetch
- Add data-source hierarchy to opportunity manager (cache-only, cache-then-cw, cw-first) - fetchPages/search/fetchByCompany use cache-only: Redis → DB (no CW calls) - fetchItem uses cache-then-cw by default, cw-first when fresh=true - Add idleTimeout: 255 to Bun.serve to prevent request timeouts - Map CW status 57 (04. Confirmed Quote) to Active equivalency - Add computeCacheTTL algorithm and opportunityCache module
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import {
|
||||
computeCacheTTL,
|
||||
TTL_HIGH_ACTIVITY,
|
||||
TTL_MODERATE_ACTIVITY,
|
||||
TTL_LOW_ACTIVITY,
|
||||
} from "../../src/modules/algorithms/computeCacheTTL";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Fixed reference point so tests are deterministic. */
|
||||
const NOW = new Date("2026-03-02T12:00:00Z");
|
||||
|
||||
/** Return a Date offset from NOW by `days` (negative = past, positive = future). */
|
||||
const daysFromNow = (days: number): Date =>
|
||||
new Date(NOW.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rule 1a — Closed records older than 30 days should not be cached
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — Rule 1a: Closed records (>30 days)", () => {
|
||||
test("returns null when closedFlag is true and closedDate is null", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("returns null when closedFlag is true and closedDate is 60 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-60),
|
||||
expectedCloseDate: daysFromNow(-1),
|
||||
lastUpdated: daysFromNow(-1),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("returns null when closedFlag is true and closedDate is 31 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: new Date(NOW.getTime() - 31 * 24 * 60 * 60 * 1000),
|
||||
expectedCloseDate: daysFromNow(2),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rule 1b — Recently closed (within 30 days) → 15 minutes
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — Rule 1b: Recently closed (≤30 days)", () => {
|
||||
test("returns 15min when closed 1 day ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-1),
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when closed 15 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-15),
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when closed exactly 30 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-30),
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when closed today even with recent activity dates", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: NOW,
|
||||
expectedCloseDate: daysFromNow(-1),
|
||||
lastUpdated: NOW,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("just past 30-day boundary returns null", () => {
|
||||
const justPast30Days = new Date(
|
||||
NOW.getTime() - 30 * 24 * 60 * 60 * 1000 - 1,
|
||||
);
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: justPast30Days,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rule 2 — High activity (within 5 days) → 30 seconds
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — Rule 2: High activity (≤5 days)", () => {
|
||||
test("returns 30s when lastUpdated is today", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: NOW,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when lastUpdated is 3 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-3),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when lastUpdated is exactly 5 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-5),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when expectedCloseDate is 2 days in the future", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(2),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when expectedCloseDate is 5 days in the future", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(5),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when expectedCloseDate is 4 days ago (recently passed)", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(-4),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when either date is within 5 days (lastUpdated wins)", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(-30),
|
||||
lastUpdated: daysFromNow(-2),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 30s when either date is within 5 days (expectedCloseDate wins)", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(3),
|
||||
lastUpdated: daysFromNow(-30),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rule 3 — Moderate activity (within 14 days but > 5 days) → 60 seconds
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — Rule 3: Moderate activity (6–14 days)", () => {
|
||||
test("returns 60s when lastUpdated is 6 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-6),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 60s when lastUpdated is 10 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-10),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 60s when lastUpdated is exactly 14 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-14),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 60s when expectedCloseDate is 8 days in the future", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(8),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 60s when expectedCloseDate is 14 days in the future", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(14),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 60s when expectedCloseDate is 12 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(-12),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rule 4 — Low activity (older than 14 days) → 15 minutes
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — Rule 4: Low activity (>14 days)", () => {
|
||||
test("returns 15min when lastUpdated is 15 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-15),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when lastUpdated is 60 days ago", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-60),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when expectedCloseDate is 20 days in the future", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(20),
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when both dates are null", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("returns 15min when both dates are far in the past", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(-100),
|
||||
lastUpdated: daysFromNow(-90),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Edge cases
|
||||
// ---------------------------------------------------------------------------
|
||||
describe("computeCacheTTL — edge cases", () => {
|
||||
test("defaults `now` to current time when omitted", () => {
|
||||
// Open, no dates → should return LOW_ACTIVITY (15min)
|
||||
const result = computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: null,
|
||||
});
|
||||
expect(result).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("5-day boundary is inclusive", () => {
|
||||
// Exactly 5 days should match high activity
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-5),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("just past 5-day boundary falls to moderate", () => {
|
||||
// 5 days + 1 millisecond past → moderate
|
||||
const justPast5Days = new Date(NOW.getTime() - 5 * 24 * 60 * 60 * 1000 - 1);
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: justPast5Days,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("14-day boundary is inclusive", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: daysFromNow(-14),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_MODERATE_ACTIVITY);
|
||||
});
|
||||
|
||||
test("just past 14-day boundary falls to low activity", () => {
|
||||
const justPast14Days = new Date(
|
||||
NOW.getTime() - 14 * 24 * 60 * 60 * 1000 - 1,
|
||||
);
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: null,
|
||||
lastUpdated: justPast14Days,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
|
||||
test("higher-priority rule wins when both dates span different tiers", () => {
|
||||
// expectedCloseDate in 5-day window, lastUpdated in 14-day window → 30s
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: false,
|
||||
closedDate: null,
|
||||
expectedCloseDate: daysFromNow(3),
|
||||
lastUpdated: daysFromNow(-10),
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_HIGH_ACTIVITY);
|
||||
});
|
||||
|
||||
test("closed >30 days always returns null regardless of other dates", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-60),
|
||||
expectedCloseDate: NOW,
|
||||
lastUpdated: NOW,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("recently closed always returns 15min regardless of activity dates", () => {
|
||||
expect(
|
||||
computeCacheTTL({
|
||||
closedFlag: true,
|
||||
closedDate: daysFromNow(-5),
|
||||
expectedCloseDate: NOW,
|
||||
lastUpdated: NOW,
|
||||
now: NOW,
|
||||
}),
|
||||
).toBe(TTL_LOW_ACTIVITY);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user