actionhero
Version:
The reusable, scalable, and quick node.js API server for stateless and stateful applications
146 lines (145 loc) • 6.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisInitializer = void 0;
const dotProp = require("dot-prop");
const index_1 = require("../index");
/**
* Redis helpers and connections.
*/
class RedisInitializer extends index_1.Initializer {
constructor() {
super();
this.name = "redis";
this.loadPriority = 200;
this.startPriority = 101;
this.stopPriority = 99999;
}
async initialize() {
var _a;
index_1.api.redis = {
clients: {},
subscriptionHandlers: {},
rpcCallbacks: {},
status: {
subscribed: false,
},
};
index_1.api.redis.subscriptionHandlers.do = async (message) => {
if (!message.connectionId ||
(index_1.api.connections && index_1.api.connections.connections[message.connectionId])) {
const cmdParts = message.method.split(".");
const cmd = cmdParts.shift();
if (cmd !== "api") {
throw new Error("cannot operate on a method outside of the api object");
}
const callableApi = Object.assign(index_1.api, { log: index_1.log });
const method = dotProp.get(callableApi, cmdParts.join("."));
let args = message.args;
if (args === null) {
args = [];
}
if (!Array.isArray(args)) {
args = [args];
}
if (method) {
const response = await method.apply(null, args);
await index_1.redis.respondCluster(message.messageId, response);
}
else {
(0, index_1.log)("RPC method `" + cmdParts.join(".") + "` not found", "crit");
}
}
};
index_1.api.redis.subscriptionHandlers.doResponse = function (message) {
if (index_1.api.redis.rpcCallbacks[message.messageId]) {
const { resolve, timer } = index_1.api.redis.rpcCallbacks[message.messageId];
clearTimeout(timer);
resolve(message.response);
delete index_1.api.redis.rpcCallbacks[message.messageId];
}
};
const connectionNames = ["client", "subscriber", "tasks"];
for (const r of connectionNames) {
if (index_1.config.redis[r].buildNew === true) {
index_1.api.redis.clients[r] = new index_1.config.redis[r].konstructor(...((_a = index_1.config.redis[r].args) !== null && _a !== void 0 ? _a : []));
index_1.api.redis.clients[r].on("error", (error) => {
(0, index_1.log)(`Redis connection \`${r}\` error`, "alert", error);
});
index_1.api.redis.clients[r].on("connect", () => {
(0, index_1.log)(`Redis connection \`${r}\` connected`, "debug");
});
index_1.api.redis.clients[r].on("ready", () => {
(0, index_1.log)(`Redis connection \`${r}\` ready`, "debug");
});
index_1.api.redis.clients[r].on("close", () => {
(0, index_1.log)(`Redis connection \`${r}\` closed`, "debug");
});
index_1.api.redis.clients[r].on("end", () => {
(0, index_1.log)(`Redis connection \`${r}\` ended`, "debug");
});
index_1.api.redis.clients[r].on("reconnecting", () => {
(0, index_1.log)(`Redis connection \`${r}\` reconnecting`, "info");
});
}
else {
index_1.api.redis.clients[r] = index_1.config.redis[r].konstructor(index_1.config.redis[r].args);
index_1.api.redis.clients[r].on("error", (error) => {
(0, index_1.log)(`Redis connection \`${r}\` error`, "alert", error);
});
(0, index_1.log)(`Redis connection \`${r}\` connected`, "debug");
}
if (r !== "subscriber")
await index_1.api.redis.clients[r].get("_test");
}
if (!index_1.api.redis.status.subscribed) {
await index_1.api.redis.clients.subscriber.subscribe(index_1.config.general.channel);
index_1.api.redis.status.subscribed = true;
const messageHandler = async (messageChannel, stringifiedMessage) => {
let message;
try {
message = JSON.parse(stringifiedMessage);
}
catch (e) {
message = {};
}
if (messageChannel === index_1.config.general.channel &&
message.serverToken === index_1.config.general.serverToken) {
if (index_1.api.redis.subscriptionHandlers[message.messageType]) {
await index_1.api.redis.subscriptionHandlers[message.messageType](message);
}
}
};
index_1.api.redis.clients.subscriber.on("message", messageHandler);
}
}
async start() {
await index_1.redis.doCluster("api.log", [
`actionhero member ${index_1.id} has joined the cluster`,
]);
}
async stop() {
await index_1.api.redis.clients.subscriber.unsubscribe();
index_1.api.redis.status.subscribed = false;
await index_1.redis.doCluster("api.log", [
`actionhero member ${index_1.id} has left the cluster`,
]);
await index_1.utils.sleep(index_1.config.redis.stopTimeout); // allow some time for the goodbye message to propagate
const keys = Object.keys(index_1.api.redis.clients);
for (const i in keys) {
const client = index_1.api.redis.clients[keys[i]];
//@ts-ignore
if (typeof client.end === "function") {
//@ts-ignore
await client.end();
}
else if (typeof client.quit === "function") {
await client.quit();
}
else if (typeof client.disconnect === "function") {
await client.disconnect();
}
}
await index_1.utils.sleep(index_1.config.redis.stopTimeout); // allow some time for the connection to close
}
}
exports.RedisInitializer = RedisInitializer;