Skip to content

Commit

Permalink
migrate redcron/redlock code from v4 plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
derrickmehaffy committed Jul 22, 2024
1 parent 5857fdd commit c284b1d
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 13 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"dependencies": {
"chalk": "4.1.2",
"debug": "4.3.5",
"ioredis": "5.4.1"
"ioredis": "5.4.1",
"redlock": "5.0.0-beta.2"
},
"peerDependencies": {
"@strapi/strapi": "^5.0.0-rc.4"
Expand All @@ -33,6 +34,9 @@
"email": "derrickmehaffy@gmail.com",
"url": "https://github.com/derrickmehaffy",
"lead": true
},
{
"name": "Excl Networks Inc."
}
],
"bugs": {
Expand Down
9 changes: 9 additions & 0 deletions server/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ module.exports = {
settings: {
debug: false,
debugIORedis: false,
redlockConfig: {
driftFactor: 0.01,
retryCount: 10,
retryDelay: 200,
retryJitter: 200,
},
enableRedlock: false,
lockDelay: null,
lockTTL: 5000,
},
connections: {
default: {
Expand Down
72 changes: 60 additions & 12 deletions server/register.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const debug = require('debug');
const { default: Redlock } = require('redlock');

module.exports = async ({ strapi }) => {
// Load plugin Config
Expand All @@ -25,16 +26,63 @@ module.exports = async ({ strapi }) => {
// Build Redis database connections
await strapi.plugin('redis').service('connection').buildAll(coreConfig);

// Construct Admin Permissions
// Commenting this since it's not needed for now, there is no admin panel for this plugin
// const actions = [
// {
// section: 'settings',
// category: 'redis',
// displayName: 'Access the Redis Overview page',
// uid: 'settings.read',
// pluginName: 'redis',
// },
// ];
// await strapi.admin.services.permission.actionProvider.registerMany(actions);
// Configure Redlock
if (coreConfig.settings.enableRedlock === true) {
const originalAdd = strapi.cron.add;
const redlockConfig = coreConfig.settings.redlockConfig;

strapi.cron.add = (tasks) => {
const generateRedlockFunction = (originalFunction, name) => {
return async (...args) => {
const connections = Object.keys(strapi.redis.connections).map((key) => {
return strapi.redis.connections[key].client;
});
const redlock = new Redlock(connections, redlockConfig);

let lock;
try {
lock = await redlock.acquire([name], coreConfig.settings.lockTTL);
debug(`Job ${name} acquired lock`);
await originalFunction(...args);
} catch (e) {
debug(`Job ${name} failed to acquire lock`);
} finally {
// wait some time so other processes will lose the lock
let lockDelay = coreConfig.settings.lockDelay
? coreConfig.settings.lockDelay
: coreConfig.settings.redlockConfig.retryCount *
(coreConfig.settings.redlockConfig.retryDelay +
coreConfig.settings.redlockConfig.retryJitter);
debug(`Job ${name} waiting ${lockDelay}ms before releasing lock`);
await new Promise((resolve) => setTimeout(resolve, lockDelay));
if (lock) {
debug(`Job ${name} releasing lock`);
try {
await lock.release();
} catch (e) {
debug(`Job ${name} failed to release lock ${e}`);
}
}
}
};
};
Object.keys(tasks).forEach((key) => {
const taskValue = tasks[key];
if (typeof taskValue === 'function') {
strapi.log.info('redlock requires tasks to use the object format');
return;
} else if (
typeof taskValue === 'object' &&
taskValue &&
typeof taskValue.task === 'function' &&
taskValue.bypassRedlock !== true
) {
// fallback to key if no name is provided
const taskName = taskValue.name || key;
taskValue.task = generateRedlockFunction(taskValue.task, 'redlock:' + taskName);
}
});
originalAdd(tasks);
};
}
};
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ ms@2.1.2:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==

node-abort-controller@^3.0.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==

redis-errors@^1.0.0, redis-errors@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
Expand All @@ -105,6 +110,13 @@ redis-parser@^3.0.0:
dependencies:
redis-errors "^1.0.0"

redlock@5.0.0-beta.2:
version "5.0.0-beta.2"
resolved "https://registry.yarnpkg.com/redlock/-/redlock-5.0.0-beta.2.tgz#a629c07e07d001c0fdd9f2efa614144c4416fe44"
integrity sha512-2RDWXg5jgRptDrB1w9O/JgSZC0j7y4SlaXnor93H/UJm/QyDiFgBKNtrh0TI6oCXqYSaSoXxFh6Sd3VtYfhRXw==
dependencies:
node-abort-controller "^3.0.1"

standard-as-callback@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
Expand Down

0 comments on commit c284b1d

Please sign in to comment.