WebWorker.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. const os = require('os');
  2. const fs = require('fs-extra');
  3. const WorkerState = require('./WorkerState');
  4. const { JembaDbThread } = require('jembadb');
  5. const DbCreator = require('./DbCreator');
  6. const ayncExit = new (require('./AsyncExit'))();
  7. const log = new (require('./AppLogger'))().log;//singleton
  8. const utils = require('./utils');
  9. //server states
  10. const ssNormal = 'normal';
  11. const ssDbLoading = 'db_loading';
  12. const ssDbCreating = 'db_creating';
  13. const stateToText = {
  14. [ssNormal]: '',
  15. [ssDbLoading]: 'Загрузка поисковой базы',
  16. [ssDbCreating]: 'Создание поисковой базы',
  17. };
  18. //singleton
  19. let instance = null;
  20. class WebWorker {
  21. constructor(config) {
  22. if (!instance) {
  23. this.config = config;
  24. this.workerState = new WorkerState();
  25. this.wState = this.workerState.getControl('server_state');
  26. this.myState = '';
  27. this.db = null;
  28. ayncExit.add(this.closeDb.bind(this));
  29. this.loadOrCreateDb();//no await
  30. this.logServerStats();//no await
  31. instance = this;
  32. }
  33. return instance;
  34. }
  35. checkMyState() {
  36. if (this.myState != ssNormal)
  37. throw new Error('server_busy');
  38. }
  39. setMyState(newState, workerState = {}) {
  40. this.myState = newState;
  41. this.wState.set(Object.assign({}, workerState, {
  42. state: newState,
  43. serverMessage: stateToText[newState]
  44. }));
  45. }
  46. async closeDb() {
  47. if (this.db) {
  48. await this.db.unlock();
  49. this.db = null;
  50. }
  51. }
  52. async createDb(dbPath) {
  53. this.setMyState(ssDbCreating);
  54. log('Searcher DB create start');
  55. const config = this.config;
  56. if (await fs.pathExists(dbPath))
  57. throw new Error(`createDb.pathExists: ${dbPath}`);
  58. const db = new JembaDbThread();//создаем не в потоке, чтобы лучше работал GC
  59. await db.lock({
  60. dbPath,
  61. create: true,
  62. softLock: true,
  63. tableDefaults: {
  64. cacheSize: 5,
  65. },
  66. });
  67. try {
  68. log(' start INPX import');
  69. const dbCreator = new DbCreator(config);
  70. await dbCreator.run(db, (state) => {
  71. this.setMyState(ssDbCreating, state);
  72. if (state.fileName)
  73. log(` load ${state.fileName}`);
  74. if (state.recsLoaded)
  75. log(` processed ${state.recsLoaded} records`);
  76. if (state.job)
  77. log(` ${state.job}`);
  78. });
  79. log(' finish INPX import');
  80. } finally {
  81. await db.unlock();
  82. log('Searcher DB successfully created');
  83. }
  84. }
  85. async loadOrCreateDb(recreate = false) {
  86. this.setMyState(ssDbLoading);
  87. try {
  88. const config = this.config;
  89. const dbPath = `${config.dataDir}/db`;
  90. //пересоздаем БД из INPX если нужно
  91. if (config.recreateDb || recreate)
  92. await fs.remove(dbPath);
  93. if (!await fs.pathExists(dbPath)) {
  94. await this.createDb(dbPath);
  95. }
  96. //загружаем БД
  97. this.setMyState(ssDbLoading);
  98. log('Searcher DB open');
  99. this.db = new JembaDbThread();
  100. await this.db.lock({
  101. dbPath,
  102. softLock: true,
  103. tableDefaults: {
  104. cacheSize: 5,
  105. },
  106. });
  107. //открываем все таблицы
  108. await this.db.openAll();
  109. await this.db.close({table: 'title'});
  110. log('Searcher DB is ready');
  111. } catch (e) {
  112. log(LM_FATAL, e.message);
  113. ayncExit.exit(1);
  114. } finally {
  115. this.setMyState(ssNormal);
  116. }
  117. }
  118. async logServerStats() {
  119. while (1) {// eslint-disable-line
  120. try {
  121. const memUsage = process.memoryUsage().rss/(1024*1024);//Mb
  122. let loadAvg = os.loadavg();
  123. loadAvg = loadAvg.map(v => v.toFixed(2));
  124. log(`Server info [ memUsage: ${memUsage.toFixed(2)}MB, loadAvg: (${loadAvg.join(', ')}) ]`);
  125. } catch (e) {
  126. log(LM_ERR, e.message);
  127. }
  128. await utils.sleep(5000);
  129. }
  130. }
  131. }
  132. module.exports = WebWorker;