@opengis/fastify-table
Version:
core-plugins
113 lines (112 loc) • 3.88 kB
JavaScript
const keyCacheSubscribe = "emit_cache";
const listenter = {}; // callback send message listener
const promise = {}; // promise await for subscribe
const resolve = {}; // resolve
const publish = {}; // publish
import config from "../../../../../config.js";
import getRedis from "../../../../plugins/redis/funcs/getRedis.js";
// getRedisPublisher
function getRedisPublisher() {
const rst = getRedis({
name: "rst",
...(config.redis || {}),
});
const subscriber = getRedis({
name: "sub",
...(config.redis || {}),
});
subscriber.unsubscribe(keyCacheSubscribe);
subscriber.subscribe(keyCacheSubscribe, () => { });
subscriber.on("message", async (channel, text) => {
const [code, msg] = text.split("|||");
if (msg === "finish" && resolve[code]) {
resolve[code]();
resolve[code] = null;
}
listenter[code].forEach((cb1, i) => {
cb1(`${msg} - ${i}`);
});
});
return rst;
}
// native publisher
function getPublisher() {
const rst = {
publish(key, text) {
const [code, msg] = text.split("|||");
listenter[code]?.forEach((cb1, i) => {
cb1?.(`${msg} - ${i}`);
});
},
};
return rst;
}
// !!! work non cluster mode for cluster subscribe redis
export default async function subscribe(code, cb, reload) {
try {
const rclient = getRedis();
const { isRedis, timeout = 150 } = config?.redis?.pubsub || {}; // test!
const publisher = isRedis ? getRedisPublisher() : getPublisher();
const keyCacheCode = `${keyCacheSubscribe}:${code}`;
// check code is run
const isNotRun = await rclient.setnx(keyCacheCode, 1);
const ttl = await rclient.ttl(keyCacheCode);
// if Run
if (!isNotRun && !reload && ttl > 0) {
// add listener
cb(`==== run as slave ttl: ${ttl}==== `);
const alldata = await rclient.lrange(keyCacheCode + ":list", 0, -1);
alldata.forEach((el) => {
cb(el);
});
// for redis
if (!listenter[code]) {
listenter[code] = [];
promise[code] = new Promise((rsv) => {
resolve[code] = rsv;
});
}
// check master finish
const interval = setInterval(async () => {
const ttl1 = await rclient.ttl(keyCacheCode);
if (ttl1 < 0) {
clearInterval(interval);
cb(`finish master timeout ${timeout}`, 1);
}
}, 5000);
listenter[code].push(cb);
return promise[code];
}
await rclient.expire(keyCacheCode, timeout);
// if not run
// create return promise
promise[code] = new Promise((rsv) => {
resolve[code] = rsv;
});
listenter[code] = [cb];
// listenter[code].push(cb);
// create publish function
publish[code] = (msg) => {
rclient.rpush(keyCacheCode + ":list", msg);
rclient.expire(keyCacheCode, timeout);
// send message to all listener
publisher.publish(keyCacheSubscribe, `${code}|||${msg}`); // redis
// finish and clear
if (msg === "finish") {
// clear code to run again
rclient.del(keyCacheCode);
rclient.del(keyCacheCode + ":list");
// resolve promise
resolve[code]();
// clear
resolve[code] = null;
promise[code] = null;
listenter[code] = [];
}
};
return publish[code];
}
catch (err) {
console.error(err.toString());
}
}