mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
refactor(core): Make instances more resilient to license sync issues (#16627)
This commit is contained in:
@@ -214,6 +214,64 @@ describe('License', () => {
|
||||
const mainPlan = license.getMainPlan();
|
||||
expect(mainPlan).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('onExpirySoon', () => {
|
||||
it.each([
|
||||
{
|
||||
instanceType: 'main' as const,
|
||||
isLeader: true,
|
||||
shouldReload: false,
|
||||
description: 'Leader main should not reload',
|
||||
},
|
||||
{
|
||||
instanceType: 'main' as const,
|
||||
isLeader: false,
|
||||
shouldReload: true,
|
||||
description: 'Follower main should reload',
|
||||
},
|
||||
{
|
||||
instanceType: 'worker' as const,
|
||||
isLeader: false,
|
||||
shouldReload: true,
|
||||
description: 'Worker should reload',
|
||||
},
|
||||
{
|
||||
instanceType: 'webhook' as const,
|
||||
isLeader: false,
|
||||
shouldReload: true,
|
||||
description: 'Webhook should reload',
|
||||
},
|
||||
])('$description', async ({ instanceType, isLeader, shouldReload }) => {
|
||||
const logger = mockLogger();
|
||||
const reloadSpy = jest.spyOn(License.prototype, 'reload').mockResolvedValueOnce();
|
||||
const instanceSettings = mock<InstanceSettings>({ instanceType });
|
||||
Object.defineProperty(instanceSettings, 'isLeader', { get: () => isLeader });
|
||||
|
||||
license = new License(
|
||||
logger,
|
||||
instanceSettings,
|
||||
mock(),
|
||||
mock(),
|
||||
mock<GlobalConfig>({ license: licenseConfig }),
|
||||
);
|
||||
|
||||
await license.init();
|
||||
|
||||
const licenseManager = LicenseManager as jest.MockedClass<typeof LicenseManager>;
|
||||
const calls = licenseManager.mock.calls;
|
||||
const licenseManagerCall = calls[calls.length - 1][0];
|
||||
const onExpirySoon = licenseManagerCall.onExpirySoon;
|
||||
|
||||
if (shouldReload) {
|
||||
expect(onExpirySoon).toBeDefined();
|
||||
onExpirySoon!();
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
} else {
|
||||
expect(onExpirySoon).toBeUndefined();
|
||||
expect(reloadSpy).not.toHaveBeenCalled();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('License', () => {
|
||||
|
||||
@@ -78,6 +78,8 @@ export class License implements LicenseProvider {
|
||||
const collectPassthroughData = isMainInstance
|
||||
? async () => await this.licenseMetricsService.collectPassthroughData()
|
||||
: async () => ({});
|
||||
const onExpirySoon = !this.instanceSettings.isLeader ? () => this.onExpirySoon() : undefined;
|
||||
const expirySoonOffsetMins = !this.instanceSettings.isLeader ? 120 : undefined;
|
||||
|
||||
const { isLeader } = this.instanceSettings;
|
||||
const { autoRenewalEnabled } = this.globalConfig.license;
|
||||
@@ -107,6 +109,8 @@ export class License implements LicenseProvider {
|
||||
collectPassthroughData,
|
||||
onFeatureChange,
|
||||
onLicenseRenewed,
|
||||
onExpirySoon,
|
||||
expirySoonOffsetMins,
|
||||
});
|
||||
|
||||
await this.manager.initialize();
|
||||
@@ -433,4 +437,20 @@ export class License implements LicenseProvider {
|
||||
disableAutoRenewals() {
|
||||
this.manager?.disableAutoRenewals();
|
||||
}
|
||||
|
||||
private onExpirySoon() {
|
||||
this.logger.info('License is about to expire soon, reloading license...');
|
||||
|
||||
// reload in background to avoid blocking SDK
|
||||
|
||||
void this.reload()
|
||||
.then(() => {
|
||||
this.logger.info('Reloaded license on expiry soon');
|
||||
})
|
||||
.catch((error) => {
|
||||
this.logger.error('Failed to reload license on expiry soon', {
|
||||
error: error instanceof Error ? error.message : error,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user