clear the locks by hostname at server startup
MODIFY
src/locking/LockingManager.ts
src/locking/LockingManager.ts
@@ -82,6 +82,11 @@ export default class LockingManager {
return true;
}
+ public static async cleanUpLocks(): Promise<void> {
+ const hostname = Utils.getHostname();
+ await LockingStorage.deleteLockByHostname(hostname);
+ }
+
private static createLock(tenantID: string, entity: LockEntity, key: string, type: LockType = LockType.EXCLUSIVE): Lock {
if (!tenantID) {
throw new BackendError({

MODIFY
src/start.ts
src/start.ts
@@ -6,6 +6,7 @@ import Configuration from './utils/Configuration';
import Constants from './utils/Constants';
import I18nManager from './utils/I18nManager';
import JsonCentralSystemServer from './server/ocpp/json/JsonCentralSystemServer';
+import LockingManager from './locking/LockingManager';
import Logging from './utils/Logging';
import MigrationConfiguration from './types/configuration/MigrationConfiguration';
import MigrationHandler from './migration/MigrationHandler';
@@ -124,6 +125,10 @@ export default class Bootstrap {
// Init the Scheduler
// -------------------------------------------------------------------------
SchedulerManager.init();
+
+ // Locks remain in storage if server crashes
+ // Delete acquired database locks with same hostname
+ await LockingManager.cleanUpLocks();
}
} catch (error) {
// Log

MODIFY
src/storage/mongodb/LockingStorage.ts
src/storage/mongodb/LockingStorage.ts
@@ -55,4 +55,15 @@ export default class LockingStorage {
Logging.traceEnd(Constants.DEFAULT_TENANT, MODULE_NAME, 'deleteLock', uniqueTimerID, result);
return result.value !== null;
}
+
+ public static async deleteLockByHostname(hostname:string): Promise<void> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(Constants.DEFAULT_TENANT, MODULE_NAME, 'deleteLock');
+ // Delete
+ const result = await global.database.getCollection<any>(Constants.DEFAULT_TENANT, 'locks')
+ .deleteMany({ 'hostname': hostname });
+ // Debug
+ Logging.traceEnd(Constants.DEFAULT_TENANT, MODULE_NAME, 'deleteLock', uniqueTimerID, result.deletedCount);
+ }
+
}

MODIFY
src/utils/Logging.ts
src/utils/Logging.ts
@@ -17,9 +17,7 @@ import { ServerAction } from '../types/Server';
import User from '../types/User';
import UserToken from '../types/UserToken';
import Utils from './Utils';
-import cfenv from 'cfenv';
import cluster from 'cluster';
-import os from 'os';
import sizeof from 'object-sizeof';
const MODULE_NAME = 'Logging';
@@ -677,7 +675,7 @@ export default class Logging {
log.source = `${Constants.CENTRAL_SERVER}`;
}
// Host
- log.host = Configuration.isCloudFoundry() ? cfenv.getAppEnv().name : os.hostname();
+ log.host = Utils.getHostname();
// Process
log.process = log.process ? log.process : (cluster.isWorker ? 'worker ' + cluster.worker.id.toString() : 'master');
// Anonymize message

MODIFY
src/utils/Utils.ts
src/utils/Utils.ts
@@ -23,10 +23,12 @@ import UserToken from '../types/UserToken';
import { WebSocketCloseEventStatusString } from '../types/WebSocket';
import _ from 'lodash';
import bcrypt from 'bcryptjs';
+import cfenv from 'cfenv';
import crypto from 'crypto';
import fs from 'fs';
import http from 'http';
import moment from 'moment';
+import os from 'os';
import passwordGenerator from 'password-generator';
import path from 'path';
import tzlookup from 'tz-lookup';
@@ -1345,4 +1347,8 @@ export default class Utils {
public static isPlateIDValid(plateID): boolean {
return /^[A-Z0-9- ]*$/.test(plateID);
}
+
+ public static getHostname(): string {
+ return Configuration.isCloudFoundry() ? cfenv.getAppEnv().name : os.hostname();
+ }
}

clear the locks by hostname at server startup