mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
fix: Concurrency controlling multiple processes in Bigcapital CLI commands
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
"@casl/ability": "^5.4.3",
|
"@casl/ability": "^5.4.3",
|
||||||
"@hapi/boom": "^7.4.3",
|
"@hapi/boom": "^7.4.3",
|
||||||
"@lemonsqueezy/lemonsqueezy.js": "^2.2.0",
|
"@lemonsqueezy/lemonsqueezy.js": "^2.2.0",
|
||||||
|
"@supercharge/promise-pool": "^3.2.0",
|
||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/i18n": "^0.8.7",
|
"@types/i18n": "^0.8.7",
|
||||||
"@types/knex": "^0.16.1",
|
"@types/knex": "^0.16.1",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import color from 'colorette';
|
|||||||
import argv from 'getopts';
|
import argv from 'getopts';
|
||||||
import Knex from 'knex';
|
import Knex from 'knex';
|
||||||
import { knexSnakeCaseMappers } from 'objection';
|
import { knexSnakeCaseMappers } from 'objection';
|
||||||
|
import { PromisePool } from '@supercharge/promise-pool';
|
||||||
import '../before';
|
import '../before';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
@@ -28,7 +29,7 @@ function initSystemKnex() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initTenantKnex(organizationId) {
|
function initTenantKnex(organizationId: string = '') {
|
||||||
return Knex({
|
return Knex({
|
||||||
client: config.tenant.db_client,
|
client: config.tenant.db_client,
|
||||||
connection: {
|
connection: {
|
||||||
@@ -71,10 +72,12 @@ function getAllSystemTenants(knex) {
|
|||||||
return knex('tenants');
|
return knex('tenants');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllInitializedSystemTenants(knex) {
|
function getAllInitializedTenants(knex) {
|
||||||
return knex('tenants').whereNotNull('initializedAt');
|
return knex('tenants').whereNotNull('initializedAt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MIGRATION_CONCURRENCY = 10;
|
||||||
|
|
||||||
// module.exports = {
|
// module.exports = {
|
||||||
// log,
|
// log,
|
||||||
// success,
|
// success,
|
||||||
@@ -91,6 +94,7 @@ function getAllInitializedSystemTenants(knex) {
|
|||||||
// - bigcapital tenants:migrate:make
|
// - bigcapital tenants:migrate:make
|
||||||
// - bigcapital system:migrate:make
|
// - bigcapital system:migrate:make
|
||||||
// - bigcapital tenants:list
|
// - bigcapital tenants:list
|
||||||
|
// - bigcapital tenants:list --all
|
||||||
|
|
||||||
commander
|
commander
|
||||||
.command('system:migrate:rollback')
|
.command('system:migrate:rollback')
|
||||||
@@ -149,10 +153,13 @@ commander
|
|||||||
commander
|
commander
|
||||||
.command('tenants:list')
|
.command('tenants:list')
|
||||||
.description('Retrieve a list of all system tenants databases.')
|
.description('Retrieve a list of all system tenants databases.')
|
||||||
|
.option('-a, --all', 'All tenants even are not initialized.')
|
||||||
.action(async (cmd) => {
|
.action(async (cmd) => {
|
||||||
try {
|
try {
|
||||||
const sysKnex = await initSystemKnex();
|
const sysKnex = await initSystemKnex();
|
||||||
const tenants = await getAllSystemTenants(sysKnex);
|
const tenants = cmd?.all
|
||||||
|
? await getAllSystemTenants(sysKnex)
|
||||||
|
: await getAllInitializedTenants(sysKnex);
|
||||||
|
|
||||||
tenants.forEach((tenant) => {
|
tenants.forEach((tenant) => {
|
||||||
const dbName = `${config.tenant.db_name_prefix}${tenant.organizationId}`;
|
const dbName = `${config.tenant.db_name_prefix}${tenant.organizationId}`;
|
||||||
@@ -183,18 +190,20 @@ commander
|
|||||||
commander
|
commander
|
||||||
.command('tenants:migrate:latest')
|
.command('tenants:migrate:latest')
|
||||||
.description('Migrate all tenants or the given tenant id.')
|
.description('Migrate all tenants or the given tenant id.')
|
||||||
.option('-t, --tenant_id [tenant_id]', 'Which tenant id do you migrate.')
|
.option(
|
||||||
|
'-t, --tenant_id [tenant_id]',
|
||||||
|
'Which organization id do you migrate.'
|
||||||
|
)
|
||||||
.action(async (cmd) => {
|
.action(async (cmd) => {
|
||||||
try {
|
try {
|
||||||
const sysKnex = await initSystemKnex();
|
const sysKnex = await initSystemKnex();
|
||||||
const tenants = await getAllInitializedSystemTenants(sysKnex);
|
const tenants = await getAllInitializedTenants(sysKnex);
|
||||||
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
||||||
|
|
||||||
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
||||||
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
||||||
}
|
}
|
||||||
// Validate the tenant id exist first of all.
|
// Validate the tenant id exist first of all.
|
||||||
const migrateOpers = [];
|
|
||||||
const migrateTenant = async (organizationId) => {
|
const migrateTenant = async (organizationId) => {
|
||||||
try {
|
try {
|
||||||
const tenantKnex = await initTenantKnex(organizationId);
|
const tenantKnex = await initTenantKnex(organizationId);
|
||||||
@@ -216,17 +225,17 @@ commander
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!cmd.tenant_id) {
|
if (!cmd.tenant_id) {
|
||||||
tenants.forEach((tenant) => {
|
await PromisePool.withConcurrency(MIGRATION_CONCURRENCY)
|
||||||
const oper = migrateTenant(tenant.organizationId);
|
.for(tenants)
|
||||||
migrateOpers.push(oper);
|
.process((tenant, index, pool) => {
|
||||||
});
|
return migrateTenant(tenant.organizationId);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
success('All tenants are migrated.');
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const oper = migrateTenant(cmd.tenant_id);
|
await migrateTenant(cmd.tenant_id);
|
||||||
migrateOpers.push(oper);
|
|
||||||
}
|
}
|
||||||
Promise.all(migrateOpers).then(() => {
|
|
||||||
success('All tenants are migrated.');
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
exit(error);
|
exit(error);
|
||||||
}
|
}
|
||||||
@@ -235,19 +244,21 @@ commander
|
|||||||
commander
|
commander
|
||||||
.command('tenants:migrate:rollback')
|
.command('tenants:migrate:rollback')
|
||||||
.description('Rollback the last batch of tenants migrations.')
|
.description('Rollback the last batch of tenants migrations.')
|
||||||
.option('-t, --tenant_id [tenant_id]', 'Which tenant id do you migrate.')
|
.option(
|
||||||
|
'-t, --tenant_id [tenant_id]',
|
||||||
|
'Which organization id do you migrate.'
|
||||||
|
)
|
||||||
.action(async (cmd) => {
|
.action(async (cmd) => {
|
||||||
try {
|
try {
|
||||||
const sysKnex = await initSystemKnex();
|
const sysKnex = await initSystemKnex();
|
||||||
const tenants = await getAllSystemTenants(sysKnex);
|
const tenants = await getAllInitializedTenants(sysKnex);
|
||||||
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
||||||
|
|
||||||
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
||||||
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const migrateOpers = [];
|
const migrateTenant = async (organizationId: string) => {
|
||||||
const migrateTenant = async (organizationId) => {
|
|
||||||
try {
|
try {
|
||||||
const tenantKnex = await initTenantKnex(organizationId);
|
const tenantKnex = await initTenantKnex(organizationId);
|
||||||
const [batchNo, _log] = await tenantKnex.migrate.rollback();
|
const [batchNo, _log] = await tenantKnex.migrate.rollback();
|
||||||
@@ -268,17 +279,17 @@ commander
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!cmd.tenant_id) {
|
if (!cmd.tenant_id) {
|
||||||
tenants.forEach((tenant) => {
|
await PromisePool.withConcurrency(MIGRATION_CONCURRENCY)
|
||||||
const oper = migrateTenant(tenant.organizationId);
|
.for(tenants)
|
||||||
migrateOpers.push(oper);
|
.process((tenant, index, pool) => {
|
||||||
});
|
return migrateTenant(tenant.organizationId);
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
success('All tenants are rollbacked.');
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const oper = migrateTenant(cmd.tenant_id);
|
await migrateTenant(cmd.tenant_id);
|
||||||
migrateOpers.push(oper);
|
|
||||||
}
|
}
|
||||||
Promise.all(migrateOpers).then(() => {
|
|
||||||
success('All tenants are rollbacked.');
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
exit(error);
|
exit(error);
|
||||||
}
|
}
|
||||||
|
|||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -50,6 +50,9 @@ importers:
|
|||||||
'@lemonsqueezy/lemonsqueezy.js':
|
'@lemonsqueezy/lemonsqueezy.js':
|
||||||
specifier: ^2.2.0
|
specifier: ^2.2.0
|
||||||
version: 2.2.0
|
version: 2.2.0
|
||||||
|
'@supercharge/promise-pool':
|
||||||
|
specifier: ^3.2.0
|
||||||
|
version: 3.2.0
|
||||||
'@types/express':
|
'@types/express':
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
@@ -5751,6 +5754,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@supercharge/promise-pool@3.2.0:
|
||||||
|
resolution: {integrity: sha512-pj0cAALblTZBPtMltWOlZTQSLT07jIaFNeM8TWoJD1cQMgDB9mcMlVMoetiB35OzNJpqQ2b+QEtwiR9f20mADg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@surma/rollup-plugin-off-main-thread@2.2.3:
|
/@surma/rollup-plugin-off-main-thread@2.2.3:
|
||||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -17382,6 +17390,7 @@ packages:
|
|||||||
|
|
||||||
/memory-pager@1.5.0:
|
/memory-pager@1.5.0:
|
||||||
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==}
|
||||||
|
requiresBuild: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/memorystream@0.3.1:
|
/memorystream@0.3.1:
|
||||||
@@ -23472,6 +23481,7 @@ packages:
|
|||||||
|
|
||||||
/sparse-bitfield@3.0.3:
|
/sparse-bitfield@3.0.3:
|
||||||
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
|
||||||
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
memory-pager: 1.5.0
|
memory-pager: 1.5.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|||||||
Reference in New Issue
Block a user