chore: Still seeing redis connection failures in CI (#9957)

This commit is contained in:
Tom Moor
2025-08-17 18:42:20 -04:00
committed by GitHub
parent dd061790a8
commit cc8a3d8b5e
7 changed files with 65 additions and 85 deletions

View File

@@ -12,7 +12,6 @@
},
"setupFiles": ["<rootDir>/__mocks__/console.js"],
"setupFilesAfterEnv": ["<rootDir>/server/test/setup.ts"],
"globalSetup": "<rootDir>/server/test/globalSetup.js",
"globalTeardown": "<rootDir>/server/test/globalTeardown.js",
"testEnvironment": "node"
},

View File

@@ -295,6 +295,7 @@
"@types/glob": "^8.0.1",
"@types/google.analytics": "^0.0.46",
"@types/invariant": "^2.2.37",
"@types/ioredis-mock": "^8.2.6",
"@types/jest": "^29.5.14",
"@types/jsonwebtoken": "^8.5.9",
"@types/katex": "^0.16.7",
@@ -353,6 +354,7 @@
"discord-api-types": "^0.37.119",
"husky": "^8.0.3",
"i18next-parser": "^8.13.0",
"ioredis-mock": "^8.9.0",
"jest-cli": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.3",

View File

@@ -4,6 +4,7 @@ import snakeCase from "lodash/snakeCase";
import { Second } from "@shared/utils/time";
import env from "@server/env";
import Metrics from "@server/logging/Metrics";
import Redis from "@server/storage/redis";
import ShutdownHelper, { ShutdownOrder } from "@server/utils/ShutdownHelper";
export function createQueue(
@@ -16,9 +17,6 @@ export function createQueue(
// https://github.com/OptimalBits/bull/blob/b6d530f72a774be0fd4936ddb4ad9df3b183f4b6/PATTERNS.md#reusing-redis-connections
const queue = new Queue(name, {
createClient(type) {
// Load dynamically so that this isn't pulled in at startup during tests
const Redis = require("../storage/redis").default;
switch (type) {
case "client":
return Redis.defaultClient;

View File

@@ -1,52 +0,0 @@
import { EventEmitter } from "events";
// Create a mock Redis client with all needed methods mocked
class RedisMock extends EventEmitter {
constructor() {
super();
}
get = jest.fn().mockResolvedValue(null);
set = jest.fn().mockResolvedValue("OK");
del = jest.fn().mockResolvedValue(1);
hget = jest.fn().mockResolvedValue(null);
hset = jest.fn().mockResolvedValue("OK");
hdel = jest.fn().mockResolvedValue(1);
sadd = jest.fn().mockResolvedValue(1);
smembers = jest.fn().mockResolvedValue([]);
keys = jest.fn().mockResolvedValue([]);
ping = jest.fn().mockResolvedValue("PONG");
disconnect = jest.fn();
setMaxListeners = jest.fn();
}
// Mock the RedisAdapter class
class RedisAdapter extends RedisMock {
constructor(_url: string | undefined, _options = {}) {
super();
}
private static client: RedisAdapter;
private static subscriber: RedisAdapter;
public static get defaultClient(): RedisAdapter {
return (
this.client ||
(this.client = new this(undefined, {
connectionNameSuffix: "client",
}))
);
}
public static get defaultSubscriber(): RedisAdapter {
return (
this.subscriber ||
(this.subscriber = new this(undefined, {
maxRetriesPerRequest: null,
connectionNameSuffix: "subscriber",
}))
);
}
}
export default RedisAdapter;

View File

@@ -1,14 +0,0 @@
import { sequelize } from "@server/storage/database";
module.exports = async function () {
const sql = sequelize.getQueryInterface();
const tables = Object.keys(sequelize.models).map((model) => {
const n = sequelize.models[model].getTableName();
return sql.queryGenerator.quoteTable(
typeof n === "string" ? n : n.tableName
);
});
const flushQuery = `TRUNCATE ${tables.join(", ")} CASCADE`;
await sequelize.query(flushQuery);
};

View File

@@ -1,18 +1,18 @@
import "reflect-metadata";
import sharedEnv from "@shared/env";
import env from "@server/env";
require("jest-fetch-mock").enableMocks();
fetchMock.dontMock();
require("@server/storage/database");
import Redis from "ioredis-mock";
// Enable mocks for Redis-related modules
jest.mock("@server/storage/redis");
jest.mock("ioredis", () => require("ioredis-mock"));
jest.mock("@server/utils/MutexLock");
jest.mock("@server/utils/CacheHelper");
// We never want to make real S3 requests in test environment
// Enable fetch mocks for testing
require("jest-fetch-mock").enableMocks();
fetchMock.dontMock();
// Mock AWS SDK S3 client and related commands
jest.mock("@aws-sdk/client-s3", () => ({
S3Client: jest.fn(() => ({
send: jest.fn(),
@@ -36,6 +36,13 @@ jest.mock("@aws-sdk/s3-request-presigner", () => ({
getSignedUrl: jest.fn(),
}));
// Initialize the database models
require("@server/storage/database");
beforeEach(() => {
env.URL = sharedEnv.URL = "https://app.outline.dev";
});
afterEach((done) => {
new Redis().flushall().then(() => done());
});

View File

@@ -2286,10 +2286,15 @@
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
integrity "sha1-6QyfcXaLNzbnbX3WeD/Gwq+oi8g= sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
"@ioredis/commands@^1.0.2", "@ioredis/commands@^1.1.1":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11"
integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==
"@ioredis/as-callback@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@ioredis/as-callback/-/as-callback-3.0.0.tgz#b96c9b05e6701e85ec6a5e62fa254071b0aec97f"
integrity sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg==
"@ioredis/commands@^1.0.2", "@ioredis/commands@^1.1.1", "@ioredis/commands@^1.2.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.3.0.tgz#4dc3ae9bfa7146b63baf27672a61db0ea86e35e5"
integrity sha512-M/T6Zewn7sDaBQEqIZ8Rb+i9y8qfGmq+5SDFSf9sA2lUZTmdDLVdOiQaeDp+Q4wElZ9HG1GAX5KhDaidp6LQsQ==
"@isaacs/cliui@^8.0.2":
version "8.0.2"
@@ -4943,6 +4948,11 @@
resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.37.tgz#1709741e534364d653c87dff22fc76fa94aa7bc0"
integrity sha512-IwpIMieE55oGWiXkQPSBY1nw1nFs6bsKXTFskNY8sdS17K24vyEBRQZEwlRS7ZmXCWnJcQtbxWzly+cODWGs2A==
"@types/ioredis-mock@^8.2.6":
version "8.2.6"
resolved "https://registry.yarnpkg.com/@types/ioredis-mock/-/ioredis-mock-8.2.6.tgz#efc80b2fe702d3c3b9ee70f3fe05a36c18b2a528"
integrity sha512-5heqtZMvQ4nXARY0o8rc8cjkJjct2ScM12yCJ/h731S9He93a2cv+kAhwPCNwTKDfNH9gjRfLG4VpAEYJU0/gQ==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
@@ -8247,6 +8257,20 @@ fecha@^4.2.0:
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce"
integrity "sha1-CoOtj4bvYqCR4iu1oDnNA9I+7M4= sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
fengari-interop@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.3.tgz#3ad37a90e7430b69b365441e9fc0ba168942a146"
integrity sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw==
fengari@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/fengari/-/fengari-0.1.4.tgz#72416693cd9e43bd7d809d7829ddc0578b78b0bb"
integrity sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==
dependencies:
readline-sync "^1.4.9"
sprintf-js "^1.1.1"
tmp "^0.0.33"
fetch-retry@^5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/fetch-retry/-/fetch-retry-5.0.6.tgz#17d0bc90423405b7a88b74355bf364acd2a7fa56"
@@ -9170,6 +9194,17 @@ invariant@^2.2.2, invariant@^2.2.4:
dependencies:
loose-envify "^1.0.0"
ioredis-mock@^8.9.0:
version "8.9.0"
resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-8.9.0.tgz#5d694c4b81d3835e4291e0b527f947e260981779"
integrity sha512-yIglcCkI1lvhwJVoMsR51fotZVsPsSk07ecTCgRTRlicG0Vq3lke6aAaHklyjmRNRsdYAgswqC2A0bPtQK4LSw==
dependencies:
"@ioredis/as-callback" "^3.0.0"
"@ioredis/commands" "^1.2.0"
fengari "^0.1.4"
fengari-interop "^0.1.3"
semver "^7.5.4"
ioredis@^4.28.2:
version "4.30.0"
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.30.0.tgz#023277fcbeddd2dba3c101ef45f26c3f1de98a92"
@@ -12738,6 +12773,11 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
readline-sync@^1.4.9:
version "1.4.10"
resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b"
integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==
reakit-system@^0.15.2:
version "0.15.2"
resolved "https://registry.yarnpkg.com/reakit-system/-/reakit-system-0.15.2.tgz#a485fab84b3942acbed6212c3b56a6ef8611c457"
@@ -13659,10 +13699,10 @@ split2@^3.1.0, split2@^3.1.1:
dependencies:
readable-stream "^3.0.0"
sprintf-js@^1.0.3:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673"
integrity "sha1-2hdlJiv4wPVxdJ8q1sJjACB65nM= sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
sprintf-js@^1.0.3, sprintf-js@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
sprintf-js@~1.0.2:
version "1.0.3"